From e6b4d2a07a9bf8124341c6d4c3fc0fd055b09aa3 Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 28 Jun 2013 22:37:28 -0700 Subject: [PATCH 001/382] snapshot --- dist/r.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/r.js b/dist/r.js index dbcb28c8..56c0844e 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+[reflect] Sat, 29 Jun 2013 02:57:59 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.6+ Sat, 29 Jun 2013 05:37:15 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+[reflect] Sat, 29 Jun 2013 02:57:59 GMT', + version = '2.1.6+ Sat, 29 Jun 2013 05:37:15 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, From 82ae0e4868c1bd446df6055ea266b648d0ecaf0d Mon Sep 17 00:00:00 2001 From: Benjamin Woodruff Date: Sat, 6 Jul 2013 13:58:33 -0400 Subject: [PATCH 002/382] Handle booleans in transform.js' objectToString This was causing some issues with grunt-bower-requirejs, as it uses modifyConfig. The resulting config had its boolean values replaced with empty objects, `{}`. I haven't run the unit tests over this, but it's such a trivial change that it *shouldn't* cause any issues. --- build/jslib/transform.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jslib/transform.js b/build/jslib/transform.js index 34c0bb95..71f6a044 100644 --- a/build/jslib/transform.js +++ b/build/jslib/transform.js @@ -364,7 +364,7 @@ function (esprima, parse, logger, lang) { value = 'null'; } else if (obj === undefined) { value = 'undefined'; - } else if (typeof obj === 'number') { + } else if (typeof obj === 'number' || typeof obj === 'boolean') { value = obj; } else if (typeof obj === 'string') { //Use double quotes in case the config may also work as JSON. @@ -415,4 +415,4 @@ function (esprima, parse, logger, lang) { }; return transform; -}); \ No newline at end of file +}); From f9232a76ab6a094b0d47b706ea92dc1eefa743e3 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Jul 2013 20:17:03 -0700 Subject: [PATCH 003/382] Refs #475, add test for boolean serialization --- build/tests/transform/addPath.js | 2 ++ build/tests/transform/expected/addPath.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/build/tests/transform/addPath.js b/build/tests/transform/addPath.js index ec0d718b..8ffdba02 100644 --- a/build/tests/transform/addPath.js +++ b/build/tests/transform/addPath.js @@ -2,5 +2,7 @@ requirejs.config({ 'something/else': 'ok', _another_thing: 'ok', + good: true, + bad: false, baseUrl: 'some/thing' }); diff --git a/build/tests/transform/expected/addPath.js b/build/tests/transform/expected/addPath.js index 0f391b6a..20761673 100644 --- a/build/tests/transform/expected/addPath.js +++ b/build/tests/transform/expected/addPath.js @@ -2,6 +2,8 @@ requirejs.config({ 'something/else': 'ok', _another_thing: 'ok', + good: true, + bad: false, baseUrl: 'some/thing', paths: { newlyAdded: 'some/added/path' From 18165516a46b18a1fbbf2c9b9267d25c7733ce53 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Jul 2013 20:17:42 -0700 Subject: [PATCH 004/382] snapshot --- dist/r.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index 56c0844e..4b1571f1 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Sat, 29 Jun 2013 05:37:15 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.6+ Sun, 07 Jul 2013 03:17:29 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+ Sat, 29 Jun 2013 05:37:15 GMT', + version = '2.1.6+ Sun, 07 Jul 2013 03:17:29 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22075,7 +22075,7 @@ function (esprima, parse, logger, lang) { value = 'null'; } else if (obj === undefined) { value = 'undefined'; - } else if (typeof obj === 'number') { + } else if (typeof obj === 'number' || typeof obj === 'boolean') { value = obj; } else if (typeof obj === 'string') { //Use double quotes in case the config may also work as JSON. @@ -22126,7 +22126,8 @@ function (esprima, parse, logger, lang) { }; return transform; -});/** +}); +/** * @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 From 55507ab55bcd51dbfb3d6ea24eb9732fa4f0229c Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Jul 2013 21:40:20 -0700 Subject: [PATCH 005/382] Fixes #703, just warn if shim config used in node, allow a suppress config to hide it --- build/jslib/node.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/jslib/node.js b/build/jslib/node.js index 95a5dcf8..b1c5fb32 100644 --- a/build/jslib/node.js +++ b/build/jslib/node.js @@ -102,10 +102,11 @@ }; req.load = function (context, moduleName, url) { - var contents, err; + var contents, err, + config = context.config; - if (context.config.shim[moduleName]) { - throw new Error('Shim config not supported in Node: detected ' + + if (config.shim[moduleName] && (!config.suppress || !config.suppress.nodeShim)) { + console.warn('Shim config not supported in Node, may or may not work. Detected ' + 'for module: ' + moduleName); } From 2b12e40f08cb21491f05c62cf66e5ec2a5cd3fc0 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Jul 2013 21:41:07 -0700 Subject: [PATCH 006/382] snapshot --- dist/r.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dist/r.js b/dist/r.js index 4b1571f1..1ef54a42 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Sun, 07 Jul 2013 03:17:29 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.6+ Sun, 07 Jul 2013 04:41:00 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+ Sun, 07 Jul 2013 03:17:29 GMT', + version = '2.1.6+ Sun, 07 Jul 2013 04:41:00 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -2443,10 +2443,11 @@ var requirejs, require, define, xpcUtil; }; req.load = function (context, moduleName, url) { - var contents, err; + var contents, err, + config = context.config; - if (context.config.shim[moduleName]) { - throw new Error('Shim config not supported in Node: detected ' + + if (config.shim[moduleName] && (!config.suppress || !config.suppress.nodeShim)) { + console.warn('Shim config not supported in Node, may or may not work. Detected ' + 'for module: ' + moduleName); } From 64f3909721ee32e22b2b19ac1bf7480ff5128f32 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Jul 2013 22:44:02 -0700 Subject: [PATCH 007/382] Fixes #452, allow commonjs convert to see MyModule = module.exports --- build/jslib/parse.js | 2 +- build/tests/convert.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build/jslib/parse.js b/build/jslib/parse.js index 4bf89ae3..8588126b 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -625,7 +625,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { traverse(esprima.parse(fileContents), function (node) { var type, - exp = node.expression; + exp = node.expression || node.init; if (node.type === 'Identifier' && (node.name === '__dirname' || node.name === '__filename')) { diff --git a/build/tests/convert.js b/build/tests/convert.js index 7f17fe1c..989a0f34 100644 --- a/build/tests/convert.js +++ b/build/tests/convert.js @@ -27,7 +27,10 @@ define(['commonJs'], function (commonJs) { source7 = 'exports.name = __filename;', expected7 = 'define(function (require, exports, module) {' + 'var __filename = module.uri || "", __dirname = __filename.substring(0, __filename.lastIndexOf("/") + 1); ' + - 'exports.name = __filename;\n});\n'; + 'exports.name = __filename;\n});\n', + + source8 = 'var MyModule = module.exports = "foo";', + expected8 = 'define(function (require, exports, module) {var MyModule = module.exports = "foo";\n});\n'; t.is(source1, commonJs.convert('fake.js', source1)); t.is(source2, commonJs.convert('fake.js', source2)); @@ -36,6 +39,7 @@ define(['commonJs'], function (commonJs) { t.is(expected5, commonJs.convert('source5', source5)); t.is(expected6, commonJs.convert('source6', source6)); t.is(expected7, commonJs.convert('source7', source7)); + t.is(expected8, commonJs.convert('source8', source8)); } ] ); From f2959d9524016ca2c6161cccce5dbeab265b6203 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Jul 2013 22:44:17 -0700 Subject: [PATCH 008/382] snapshot --- dist/r.js | 30 +++++++++++++++++++----------- require.js | 24 ++++++++++++++++-------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/dist/r.js b/dist/r.js index 1ef54a42..19ba703d 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Sun, 07 Jul 2013 04:41:00 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.6+ Sun, 07 Jul 2013 05:44:10 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+ Sun, 07 Jul 2013 04:41:00 GMT', + version = '2.1.6+ Sun, 07 Jul 2013 05:44:10 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -232,7 +232,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.6+ 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 */ @@ -245,7 +245,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.6', + version = '2.1.6+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -2027,6 +2027,19 @@ var requirejs, require, define, xpcUtil; */ req.onError = defaultOnError; + /** + * Creates the node for the load command. Only used in browser envs. + */ + req.createNode = function (config, moduleName, url) { + var node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + return node; + }; + /** * Does the request to load a module for the browser case. * Make this a separate function to allow other environments @@ -2041,12 +2054,7 @@ var requirejs, require, define, xpcUtil; node; if (isBrowser) { //In the browser so use a script tag - node = config.xhtml ? - document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : - document.createElement('script'); - node.type = config.scriptType || 'text/javascript'; - node.charset = 'utf-8'; - node.async = true; + node = req.createNode(config, moduleName, url); node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName); @@ -21460,7 +21468,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { traverse(esprima.parse(fileContents), function (node) { var type, - exp = node.expression; + exp = node.expression || node.init; if (node.type === 'Identifier' && (node.name === '__dirname' || node.name === '__filename')) { diff --git a/require.js b/require.js index 2109a251..6e24bc39 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.6 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.6+ 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 */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.6', + version = '2.1.6+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -1794,6 +1794,19 @@ var requirejs, require, define; */ req.onError = defaultOnError; + /** + * Creates the node for the load command. Only used in browser envs. + */ + req.createNode = function (config, moduleName, url) { + var node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + return node; + }; + /** * Does the request to load a module for the browser case. * Make this a separate function to allow other environments @@ -1808,12 +1821,7 @@ var requirejs, require, define; node; if (isBrowser) { //In the browser so use a script tag - node = config.xhtml ? - document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : - document.createElement('script'); - node.type = config.scriptType || 'text/javascript'; - node.charset = 'utf-8'; - node.async = true; + node = req.createNode(config, moduleName, url); node.setAttribute('data-requirecontext', context.contextName); node.setAttribute('data-requiremodule', moduleName); From bebecf80f65fc66f3abc42bbc43bf11ee8dd3c91 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 16:06:36 -0700 Subject: [PATCH 009/382] Fixes #471, give source error for mainConfigFile parse failure --- build/jslib/build.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 37c79b92..92e0a6a8 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1001,7 +1001,8 @@ define(function (require) { ' correctly while running in the optimizer. Try only' + ' using a config that is also valid JSON, or do not use' + ' mainConfigFile and instead copy the config values needed' + - ' into a build file or command line arguments given to the optimizer.'); + ' into a build file or command line arguments given to the optimizer.\n' + + 'Source error from parsing: ' + mainConfigFile + ': ' + configError); } if (mainConfig) { mainConfigPath = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/')); From f3e18fcd827fc61b9075c3f04a29a80ebafaea33 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 16:43:59 -0700 Subject: [PATCH 010/382] Fixes #444 do not proceed with build if dir is a parent of appDir or baseUrl --- build/jslib/build.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 92e0a6a8..08b20164 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1097,10 +1097,21 @@ define(function (require) { ' for optimization, and "dir" if you want the appDir' + ' or baseUrl directories optimized.'); } - if (config.dir && config.appDir && config.dir === config.appDir) { - throw new Error('"dir" and "appDir" set to the same directory.' + - ' This could result in the deletion of appDir.' + - ' Stopping.'); + + if (config.dir) { + // Make sure the output dir is not set to a parent of the + // source dir or the same dir, as it will result in source + // code deletion. + if (config.dir === config.baseUrl || + config.dir === config.appDir || + (config.baseUrl && build.makeRelativeFilePath(config.dir, + config.baseUrl).indexOf('..') !== 0) || + (config.appDir && + build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0)) { + throw new Error('"dir" is set to a parent or same directory as' + + ' "appDir" or "baseUrl". This can result in' + + ' the deletion of source code. Stopping.'); + } } if (config.insertRequire && !lang.isArray(config.insertRequire)) { From 908d3ac227476275fbc825cf5c61124b2fa1fdb7 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 16:44:13 -0700 Subject: [PATCH 011/382] snapshot --- dist/r.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/dist/r.js b/dist/r.js index 19ba703d..edcd5c1f 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Sun, 07 Jul 2013 05:44:10 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.6+ Sun, 07 Jul 2013 23:44:07 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+ Sun, 07 Jul 2013 05:44:10 GMT', + version = '2.1.6+ Sun, 07 Jul 2013 23:44:07 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24627,7 +24627,8 @@ define('build', function (require) { ' correctly while running in the optimizer. Try only' + ' using a config that is also valid JSON, or do not use' + ' mainConfigFile and instead copy the config values needed' + - ' into a build file or command line arguments given to the optimizer.'); + ' into a build file or command line arguments given to the optimizer.\n' + + 'Source error from parsing: ' + mainConfigFile + ': ' + configError); } if (mainConfig) { mainConfigPath = mainConfigFile.substring(0, mainConfigFile.lastIndexOf('/')); @@ -24722,10 +24723,21 @@ define('build', function (require) { ' for optimization, and "dir" if you want the appDir' + ' or baseUrl directories optimized.'); } - if (config.dir && config.appDir && config.dir === config.appDir) { - throw new Error('"dir" and "appDir" set to the same directory.' + - ' This could result in the deletion of appDir.' + - ' Stopping.'); + + if (config.dir) { + // Make sure the output dir is not set to a parent of the + // source dir or the same dir, as it will result in source + // code deletion. + if (config.dir === config.baseUrl || + config.dir === config.appDir || + (config.baseUrl && build.makeRelativeFilePath(config.dir, + config.baseUrl).indexOf('..') !== 0) || + (config.appDir && + build.makeRelativeFilePath(config.dir, config.appDir).indexOf('..') !== 0)) { + throw new Error('"dir" is set to a parent or same directory as' + + ' "appDir" or "baseUrl". This can result in' + + ' the deletion of source code. Stopping.'); + } } if (config.insertRequire && !lang.isArray(config.insertRequire)) { From 230dc35a5d2cc339ab03e4d6c3ddbadb0be8f860 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 18:23:54 -0700 Subject: [PATCH 012/382] Fixes #470, allow anon wrapped umd pattern with interior modules to work as dependency built into an optimized bundle for another project. --- .gitignore | 1 + build/jslib/parse.js | 41 ++++++++++++++++++- build/tests/lib/anonUmdInteriorModules/bam.js | 21 ++++++++++ .../tests/lib/anonUmdInteriorModules/build.js | 6 +++ .../tests/lib/anonUmdInteriorModules/main.js | 3 ++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 build/tests/lib/anonUmdInteriorModules/bam.js create mode 100644 build/tests/lib/anonUmdInteriorModules/build.js create mode 100644 build/tests/lib/anonUmdInteriorModules/main.js diff --git a/.gitignore b/.gitignore index 489b4b02..ec42bcf4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build/jslib/uglifyjs2/temp build/tests/builds build/tests/lib/amdefine/built.js +build/tests/lib/anonUmdInteriorModules/main-built.js build/tests/lib/appDirSrcOverwrite/www-built build/tests/lib/cjsTranslate/www-built build/tests/lib/comments/built.js diff --git a/build/jslib/parse.js b/build/jslib/parse.js index 8588126b..b735a51f 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -522,6 +522,15 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { node.left.property && node.left.property.name === 'amd'; }; + //define.amd reference, as in: if (define.amd) + parse.refsDefineAmd = function (node) { + return node && node.type === 'MemberExpression' && + node.object && node.object.name === 'define' && + node.object.type === 'Identifier' && + node.property && node.property.name === 'amd' && + node.property.type === 'Identifier'; + }; + //require(), requirejs(), require.config() and requirejs.config() parse.hasRequire = function (node) { var callName, @@ -699,7 +708,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { * Otherwise null. */ parse.parseNode = function (node, onMatch) { - var name, deps, cjsDeps, arg, factory, + var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode, args = node && node[argPropName], callName = parse.hasRequire(node); @@ -772,6 +781,36 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { } return onMatch("define", null, name, deps, node); + } else if (node.type === 'CallExpression' && node.callee && + node.callee.type === 'FunctionExpression' && + node.callee.body && node.callee.body.body && + node.callee.body.body.length === 1 && + node.callee.body.body[0].type === 'IfStatement') { + bodyNode = node.callee.body.body[0]; + //Look for a define(Identifier) case, but only if inside an + //if that has a define.amd test + if (bodyNode.consequent && bodyNode.consequent.body) { + exp = bodyNode.consequent.body[0]; + if (exp.type === 'ExpressionStatement' && exp.expression && + parse.hasDefine(exp.expression) && + exp.expression.arguments && + exp.expression.arguments.length === 1 && + exp.expression.arguments[0].type === 'Identifier') { + + //Calls define(Identifier) as first statement in body. + //Confirm the if test references define.amd + traverse(bodyNode.test, function (node) { + if (parse.refsDefineAmd(node)) { + refsDefine = true; + return false; + } + }); + + if (refsDefine) { + return onMatch("define", null, null, null, exp.expression); + } + } + } } }; diff --git a/build/tests/lib/anonUmdInteriorModules/bam.js b/build/tests/lib/anonUmdInteriorModules/bam.js new file mode 100644 index 00000000..682fdaaa --- /dev/null +++ b/build/tests/lib/anonUmdInteriorModules/bam.js @@ -0,0 +1,21 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else { + root.Bam = factory(); + } +}(this, function () { + + //Pretend almond and other stuff in here + //The build parsing should not dive into here + + define('cs',{load: function(id){throw new Error("Dynamic load not allowed: " + id);}}); + + if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); + } + + define('cs!src/view',['backbone', 'jquery', 'underscore'], function(Backbone, $, _) {}); + + return require('cs!src/main'); +})); diff --git a/build/tests/lib/anonUmdInteriorModules/build.js b/build/tests/lib/anonUmdInteriorModules/build.js new file mode 100644 index 00000000..27a971db --- /dev/null +++ b/build/tests/lib/anonUmdInteriorModules/build.js @@ -0,0 +1,6 @@ +{ + baseUrl: '.', + name: 'main', + out: 'main-built.js', + optimize: 'none' +} diff --git a/build/tests/lib/anonUmdInteriorModules/main.js b/build/tests/lib/anonUmdInteriorModules/main.js new file mode 100644 index 00000000..02898b51 --- /dev/null +++ b/build/tests/lib/anonUmdInteriorModules/main.js @@ -0,0 +1,3 @@ +define(['bam'], function (bam) { + +}); From 861aba1a4f06f8169a5981a6b13423411dff7315 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 19:01:56 -0700 Subject: [PATCH 013/382] Refs #460, finish out test wiring --- build/tests/builds.js | 21 +++++++++++++++ .../lib/anonUmdInteriorModules/expected.js | 26 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 build/tests/lib/anonUmdInteriorModules/expected.js diff --git a/build/tests/builds.js b/build/tests/builds.js index 424d357f..488fc9ea 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1897,6 +1897,27 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + //For UMD-wrapped code that is made up of interior modules, treat + //the UMD define as the entry point for the module, and do not + //parse the interior modules. + //https://github.com/jrburke/r.js/issues/460 + doh.register("anonUmdInteriorModules", + [ + function anonUmdInteriorModules(t) { + file.deleteFile("lib/anonUmdInteriorModules/main-built.js"); + + build(["lib/anonUmdInteriorModules/build.js"]); + + t.is(nol(c("lib/anonUmdInteriorModules/expected.js")), + nol(c("lib/anonUmdInteriorModules/main-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + //Test source map generation for a bundled file, //see https://github.com/jrburke/r.js/issues/397 doh.register("sourcemap", diff --git a/build/tests/lib/anonUmdInteriorModules/expected.js b/build/tests/lib/anonUmdInteriorModules/expected.js new file mode 100644 index 00000000..1dc07355 --- /dev/null +++ b/build/tests/lib/anonUmdInteriorModules/expected.js @@ -0,0 +1,26 @@ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define('bam',factory); + } else { + root.Bam = factory(); + } +}(this, function () { + + //Pretend almond and other stuff in here + //The build parsing should not dive into here + + define('cs',{load: function(id){throw new Error("Dynamic load not allowed: " + id);}}); + + if ( typeof define === "function" && define.amd && define.amd.jQuery ) { + define( "jquery", [], function () { return jQuery; } ); + } + + define('cs!src/view',['backbone', 'jquery', 'underscore'], function(Backbone, $, _) {}); + + return require('cs!src/main'); +})); + +define('main',['bam'], function (bam) { + +}); From 1fc56624f2ac6f24c306b1e5595d56bb2a08480b Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 19:18:26 -0700 Subject: [PATCH 014/382] Fixes #466, allow optimization target to be a rawText-provided value --- .gitignore | 1 + build/jslib/build.js | 6 ++++-- build/tests/builds.js | 21 +++++++++++++++++++ build/tests/lib/rawTextNameTarget/b.js | 3 +++ build/tests/lib/rawTextNameTarget/build.js | 9 ++++++++ build/tests/lib/rawTextNameTarget/c.js | 4 ++++ build/tests/lib/rawTextNameTarget/expected.js | 11 ++++++++++ 7 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 build/tests/lib/rawTextNameTarget/b.js create mode 100644 build/tests/lib/rawTextNameTarget/build.js create mode 100644 build/tests/lib/rawTextNameTarget/c.js create mode 100644 build/tests/lib/rawTextNameTarget/expected.js diff --git a/.gitignore b/.gitignore index ec42bcf4..b0886f39 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,7 @@ build/tests/lib/plugins/optimizeAllPluginResources/www-built build/tests/lib/pragmas/override/built build/tests/lib/pristineSrc/built build/tests/lib/rawText/built.js +build/tests/lib/rawTextNameTarget/a-built.js build/tests/lib/removeCombined/app-built build/tests/lib/removeCombined/baseUrl-built build/tests/lib/requireHoist/perLayer/built diff --git a/build/jslib/build.js b/build/jslib/build.js index 08b20164..5828a94e 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -304,9 +304,11 @@ define(function (require) { module._sourcePath = buildContext.nameToUrl(module.name); //If the module does not exist, and this is not a "new" module layer, //as indicated by a true "create" property on the module, and - //it is not a plugin-loaded resource, then throw an error. + //it is not a plugin-loaded resource, and there is no + //'rawText' containing the module's source then throw an error. if (!file.exists(module._sourcePath) && !module.create && - module.name.indexOf('!') === -1) { + module.name.indexOf('!') === -1 && + (!config.rawText || !lang.hasProp(config.rawText, module.name))) { throw new Error("ERROR: module path does not exist: " + module._sourcePath + " for module named: " + module.name + ". Path is relative to: " + file.absPath('.')); diff --git a/build/tests/builds.js b/build/tests/builds.js index 488fc9ea..987d0ea5 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1955,4 +1955,25 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ] ); doh.run(); + + //Allow the target of an optimization to be a module that is only + //provided in the rawText config. + //Test single file JS optimization with source map generation + doh.register("rawTextNameTarget", + [ + function rawTextNameTarget(t) { + file.deleteFile("lib/rawTextNameTarget/a-built.js"); + + build(["lib/rawTextNameTarget/build.js"]); + + t.is(nol(c("lib/rawTextNameTarget/expected.js")), + nol(c("lib/rawTextNameTarget/a-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + }); diff --git a/build/tests/lib/rawTextNameTarget/b.js b/build/tests/lib/rawTextNameTarget/b.js new file mode 100644 index 00000000..428250e1 --- /dev/null +++ b/build/tests/lib/rawTextNameTarget/b.js @@ -0,0 +1,3 @@ +define(['c'], function (c) { + +}); diff --git a/build/tests/lib/rawTextNameTarget/build.js b/build/tests/lib/rawTextNameTarget/build.js new file mode 100644 index 00000000..fe4534b2 --- /dev/null +++ b/build/tests/lib/rawTextNameTarget/build.js @@ -0,0 +1,9 @@ +{ + baseUrl: '.', + name: 'a', + rawText: { + 'a': "define(['b'], function (b) {});" + }, + out: 'a-built.js', + optimize: 'none' +} diff --git a/build/tests/lib/rawTextNameTarget/c.js b/build/tests/lib/rawTextNameTarget/c.js new file mode 100644 index 00000000..f3b27be7 --- /dev/null +++ b/build/tests/lib/rawTextNameTarget/c.js @@ -0,0 +1,4 @@ +define({ + name: 'c' +}); + diff --git a/build/tests/lib/rawTextNameTarget/expected.js b/build/tests/lib/rawTextNameTarget/expected.js new file mode 100644 index 00000000..01c62731 --- /dev/null +++ b/build/tests/lib/rawTextNameTarget/expected.js @@ -0,0 +1,11 @@ + +define('c',{ + name: 'c' +}); + + +define('b',['c'], function (c) { + +}); + +define('a',['b'], function (b) {}); \ No newline at end of file From 9e32ca1110f8a50de1b9e2966d7b963c2f341717 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 19:49:08 -0700 Subject: [PATCH 015/382] Fixes #458, switch to //# syntax for sourceMappingURL sourceURL, uglify 2.3.6 --- build/example.build.js | 2 +- build/jslib/build.js | 2 +- build/jslib/optimize.js | 4 +- build/jslib/rhino/optimize.js | 2 +- build/jslib/source-map/source-map-consumer.js | 31 ++++++--- .../jslib/source-map/source-map-generator.js | 2 +- build/jslib/source-map/util.js | 28 +++++++- build/jslib/transform.js | 2 +- build/jslib/uglifyjs2.js | 65 +++++++++++++++++-- build/jslib/uglifyjs2/README.md | 12 +--- build/jslib/x.js | 2 +- build/tests/lib/sourcemapSingle/main-built.js | 2 +- tests/node/pluginLocalId/lib/cs.js | 2 +- 13 files changed, 120 insertions(+), 36 deletions(-) diff --git a/build/example.build.js b/build/example.build.js index 9e9d41c5..423e023b 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -560,7 +560,7 @@ //Introduced in 2.0.2: a bit experimental. //Each script in the build bundle will be turned into - //a JavaScript string with a //@ sourceURL comment, and then wrapped in an + //a JavaScript string with a //# sourceURL comment, and then wrapped in an //eval call. This allows some browsers to see each evaled script as a //separate script in the script debugger even though they are all combined //in the same file. Some important limitations: diff --git a/build/jslib/build.js b/build/jslib/build.js index 5828a94e..27390237 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -447,7 +447,7 @@ define(function (require) { if (builtModule.sourceMap) { baseName = module._buildPath.split('/'); baseName = baseName.pop(); - finalText += '\n//@ sourceMappingURL=' + baseName + '.map'; + finalText += '\n//# sourceMappingURL=' + baseName + '.map'; file.saveUtf8File(module._buildPath + '.map', builtModule.sourceMap); } file.saveUtf8File(module._buildPath + '-temp', finalText); diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index 9919fe3f..eff36ea8 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -432,7 +432,7 @@ function (lang, logger, envOptimize, file, parse, logger.trace("Uglify2 file: " + fileName); try { - //var tempContents = fileContents.replace(/\/\/\@ sourceMappingURL=.*$/, ''); + //var tempContents = fileContents.replace(/\/\/\# sourceMappingURL=.*$/, ''); result = uglify2.minify(fileContents, uconfig, baseName + '.src.js'); if (uconfig.outSourceMap && result.map) { resultMap = result.map; @@ -445,7 +445,7 @@ function (lang, logger, envOptimize, file, parse, file.saveFile(outFileName + '.src.js', fileContents); } file.saveFile(outFileName + '.map', resultMap); - fileContents = result.code + "\n//@ sourceMappingURL=" + baseName + ".map"; + fileContents = result.code + "\n//# sourceMappingURL=" + baseName + ".map"; } else { fileContents = result.code; } diff --git a/build/jslib/rhino/optimize.js b/build/jslib/rhino/optimize.js index a326a528..9580d739 100644 --- a/build/jslib/rhino/optimize.js +++ b/build/jslib/rhino/optimize.js @@ -136,7 +136,7 @@ define(['logger', 'env!env/file'], function (logger, file) { file.saveFile(outFileNameMap, file.readFile(outFileNameMap).replace(mapRegExp, '"file":"' + baseName + '"')); - fileContents = optimized + "\n//@ sourceMappingURL=" + outBaseName + ".map"; + fileContents = optimized + "\n//# sourceMappingURL=" + outBaseName + ".map"; } else { fileContents = optimized; } diff --git a/build/jslib/source-map/source-map-consumer.js b/build/jslib/source-map/source-map-consumer.js index 3ad7bd15..db8df1a2 100644 --- a/build/jslib/source-map/source-map-consumer.js +++ b/build/jslib/source-map/source-map-consumer.js @@ -296,9 +296,9 @@ define(function (require, exports, module) { }; /** - * 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. + * 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) { @@ -307,17 +307,32 @@ define(function (require, exports, module) { } 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)]; - } + aSource = util.relative(this.sourceRoot, aSource); } if (this._sources.has(aSource)) { return this.sourcesContent[this._sources.indexOf(aSource)]; } + 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)]; + } + } + throw new Error('"' + aSource + '" is not in the SourceMap.'); }; diff --git a/build/jslib/source-map/source-map-generator.js b/build/jslib/source-map/source-map-generator.js index dd7c3f1a..e85ca06e 100644 --- a/build/jslib/source-map/source-map-generator.js +++ b/build/jslib/source-map/source-map-generator.js @@ -282,7 +282,7 @@ define(function (require, exports, module) { var result = ''; var mapping; - // The mappings must be guarenteed to be in sorted order before we start + // 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 diff --git a/build/jslib/source-map/util.js b/build/jslib/source-map/util.js index b540c299..99d54ef1 100644 --- a/build/jslib/source-map/util.js +++ b/build/jslib/source-map/util.js @@ -43,6 +43,25 @@ define(function (require, exports, module) { path: match[7] }; } + exports.urlParse = urlParse; + + 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; function join(aRoot, aPath) { var url; @@ -52,7 +71,8 @@ define(function (require, exports, module) { } if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - return aRoot.replace(url.path, '') + aPath; + url.path = aPath; + return urlGenerate(url); } return aRoot.replace(/\/$/, '') + '/' + aPath; @@ -80,6 +100,12 @@ define(function (require, exports, module) { 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; diff --git a/build/jslib/transform.js b/build/jslib/transform.js index 71f6a044..0540c51b 100644 --- a/build/jslib/transform.js +++ b/build/jslib/transform.js @@ -249,7 +249,7 @@ function (esprima, parse, logger, lang) { if (options.useSourceUrl) { contents = 'eval("' + lang.jsEscape(contents) + - '\\n//@ sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') + + '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') + path + '");\n'; } diff --git a/build/jslib/uglifyjs2.js b/build/jslib/uglifyjs2.js index d59cabec..92bcc833 100644 --- a/build/jslib/uglifyjs2.js +++ b/build/jslib/uglifyjs2.js @@ -184,6 +184,10 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M } return new Function("str", f); } + function all(array, predicate) { + for (var i = array.length; --i >= 0; ) if (!predicate(array[i])) return false; + return true; + } function Dictionary() { this._values = Object.create(null); this._size = 0; @@ -1055,7 +1059,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M var RE_OCT_NUMBER = /^0[0-7]+$/; var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; var OPERATORS = makePredicate([ "in", "instanceof", "typeof", "new", "void", "delete", "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]); - var WHITESPACE_CHARS = makePredicate(characters("  \n\r \f ​᠎              ")); + var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); var REGEXP_MODIFIERS = makePredicate(characters("gmsiy")); @@ -1093,6 +1097,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M function is_identifier_string(str) { var i = str.length; if (i == 0) return false; + if (is_digit(str.charCodeAt(0))) return false; while (--i >= 0) { if (!is_identifier_char(str.charAt(i))) return false; } @@ -1453,7 +1458,8 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M options = defaults(options, { strict: false, filename: null, - toplevel: null + toplevel: null, + expression: false }); var S = { input: typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT, @@ -1587,7 +1593,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M case "do": return new AST_Do({ body: in_loop(statement), - condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), + condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp) }); @@ -1609,7 +1615,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M case "return": if (S.in_function == 0) croak("'return' outside of function"); return new AST_Return({ - value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true), + value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true), semicolon(), tmp) }); @@ -2217,6 +2223,9 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M --S.in_loop; return ret; } + if (options.expression) { + return expression(true); + } return function() { var start = S.token; var body = []; @@ -2488,6 +2497,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M } else { g = new SymbolDef(self, globals.size(), node); g.undeclared = true; + g.global = true; globals.set(name, g); } node.thedef = g; @@ -2787,7 +2797,8 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M bracketize: false, semicolons: true, comments: false, - preserve_line: false + preserve_line: false, + negate_iife: !(options && options.beautify) }, true); var indentation = 0; var current_col = 0; @@ -3074,7 +3085,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M var self = this, generator = self._codegen; stream.push_node(self); var needs_parens = self.needs_parens(stream); - var fc = self instanceof AST_Function && !stream.option("beautify"); + var fc = self instanceof AST_Function && stream.option("negate_iife"); if (force_parens || needs_parens && !fc) { stream.with_parens(function() { self.add_comments(stream); @@ -3688,7 +3699,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M var a = output.stack(), i = a.length, node = a[--i], p = a[--i]; while (i > 0) { if (p instanceof AST_Statement && p.body === node) return true; - if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) { + if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) { node = p; p = a[--i]; } else { @@ -5215,6 +5226,45 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M value: "" }) }); + + case "Function": + if (all(self.args, function(x) { + return x instanceof AST_String; + })) { + try { + var code = "(function(" + self.args.slice(0, -1).map(function(arg) { + return arg.value; + }).join(",") + "){" + self.args[self.args.length - 1].value + "})()"; + var ast = parse(code); + ast.figure_out_scope(); + var comp = new Compressor(compressor.options); + ast = ast.transform(comp); + ast.figure_out_scope(); + ast.mangle_names(); + var fun = ast.body[0].body.expression; + var args = fun.argnames.map(function(arg, i) { + return make_node(AST_String, self.args[i], { + value: arg.print_to_string() + }); + }); + var code = OutputStream(); + AST_BlockStatement.prototype._codegen.call(fun, fun, code); + code = code.toString().replace(/^\{|\}$/g, ""); + args.push(make_node(AST_String, self.args[self.args.length - 1], { + value: code + })); + self.args = args; + return self; + } catch (ex) { + if (ex instanceof JS_Parse_Error) { + compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start); + compressor.warn(ex.toString()); + } else { + console.log(ex); + } + } + } + break; } } else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { return make_node(AST_Binary, self, { @@ -5818,6 +5868,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M exports["set_difference"] = set_difference; exports["set_intersection"] = set_intersection; exports["makePredicate"] = makePredicate; + exports["all"] = all; exports["Dictionary"] = Dictionary; exports["DEFNODE"] = DEFNODE; exports["AST_Token"] = AST_Token; diff --git a/build/jslib/uglifyjs2/README.md b/build/jslib/uglifyjs2/README.md index e5883df8..682435a1 100644 --- a/build/jslib/uglifyjs2/README.md +++ b/build/jslib/uglifyjs2/README.md @@ -1,6 +1,6 @@ Sets up uglifyjs2 for use in the optimizer. -Current embedded version: 2.3.2, source-map 0.1.22 +Current embedded version: 2.3.6, source-map 0.1.25 Steps: @@ -9,15 +9,7 @@ Steps: Then update this file with the uglifyjs2 version fetched. * UPDATE VERSION NUMBERS IN X.JS - -This will update: - -* ../source-map.js -* ../uglifyjs2.js - -THEN: - -Copy WHITESPACE_CHARS from node_modules/uglify-js2/lib/parse.js and replace the one in ../uglifyjs2.js +* Copy WHITESPACE_CHARS from node_modules/uglify-js2/lib/parse.js and replace the one in ../uglifyjs2.js THINGS TO CHECK: diff --git a/build/jslib/x.js b/build/jslib/x.js index a252ba20..bdc40908 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -402,7 +402,7 @@ var requirejs, require, define, xpcUtil; } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.3.2, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.3.6, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); diff --git a/build/tests/lib/sourcemapSingle/main-built.js b/build/tests/lib/sourcemapSingle/main-built.js index 500b0838..ae68aa30 100644 --- a/build/tests/lib/sourcemapSingle/main-built.js +++ b/build/tests/lib/sourcemapSingle/main-built.js @@ -1,2 +1,2 @@ define("a",{name:"a",doSomething:function(e){console.log("Hello "+e)}}),console.log("a is done"),define("b",[],function(){var e="b";return{name:e}}),require(["a","b"],function(e,t){console.log("a message below:"),e.doSomething("world"),console.log("b name: "+t.name)}),define("main",function(){}); -//@ sourceMappingURL=main-built.js.map \ No newline at end of file +//# sourceMappingURL=main-built.js.map \ No newline at end of file diff --git a/tests/node/pluginLocalId/lib/cs.js b/tests/node/pluginLocalId/lib/cs.js index 50401905..07b70985 100644 --- a/tests/node/pluginLocalId/lib/cs.js +++ b/tests/node/pluginLocalId/lib/cs.js @@ -143,7 +143,7 @@ define(['coffee-script'], function (CoffeeScript) { //sourceURL trick, so skip it if enabled. /*@if (@_jscript) @else @*/ if (!config.isBuild) { - text += "\r\n//@ sourceURL=" + path; + text += "\r\n//# sourceURL=" + path; } /*@end@*/ From c20d61d516dd97b098a25ba88f66f236613f34ae Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 19:49:24 -0700 Subject: [PATCH 016/382] snapshot --- dist/r.js | 189 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 161 insertions(+), 28 deletions(-) diff --git a/dist/r.js b/dist/r.js index edcd5c1f..3a9ed039 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Sun, 07 Jul 2013 23:44:07 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.6+ Mon, 08 Jul 2013 02:49:19 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+ Sun, 07 Jul 2013 23:44:07 GMT', + version = '2.1.6+ Mon, 08 Jul 2013 02:49:19 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -13804,9 +13804,9 @@ define('source-map/source-map-consumer', function (require, exports, module) { }; /** - * 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. + * 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) { @@ -13815,17 +13815,32 @@ define('source-map/source-map-consumer', function (require, exports, module) { } 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)]; - } + aSource = util.relative(this.sourceRoot, aSource); } if (this._sources.has(aSource)) { return this.sourcesContent[this._sources.indexOf(aSource)]; } + 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)]; + } + } + throw new Error('"' + aSource + '" is not in the SourceMap.'); }; @@ -14214,7 +14229,7 @@ define('source-map/source-map-generator', function (require, exports, module) { var result = ''; var mapping; - // The mappings must be guarenteed to be in sorted order before we start + // 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 @@ -14705,6 +14720,25 @@ define('source-map/util', function (require, exports, module) { path: match[7] }; } + exports.urlParse = urlParse; + + 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; function join(aRoot, aPath) { var url; @@ -14714,7 +14748,8 @@ define('source-map/util', function (require, exports, module) { } if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - return aRoot.replace(url.path, '') + aPath; + url.path = aPath; + return urlGenerate(url); } return aRoot.replace(/\/$/, '') + '/' + aPath; @@ -14742,6 +14777,12 @@ define('source-map/util', function (require, exports, module) { 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; @@ -14948,6 +14989,10 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio } return new Function("str", f); } + function all(array, predicate) { + for (var i = array.length; --i >= 0; ) if (!predicate(array[i])) return false; + return true; + } function Dictionary() { this._values = Object.create(null); this._size = 0; @@ -15819,7 +15864,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio var RE_OCT_NUMBER = /^0[0-7]+$/; var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; var OPERATORS = makePredicate([ "in", "instanceof", "typeof", "new", "void", "delete", "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]); - var WHITESPACE_CHARS = makePredicate(characters("  \n\r \f ​᠎              ")); + var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); var REGEXP_MODIFIERS = makePredicate(characters("gmsiy")); @@ -15857,6 +15902,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio function is_identifier_string(str) { var i = str.length; if (i == 0) return false; + if (is_digit(str.charCodeAt(0))) return false; while (--i >= 0) { if (!is_identifier_char(str.charAt(i))) return false; } @@ -16217,7 +16263,8 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio options = defaults(options, { strict: false, filename: null, - toplevel: null + toplevel: null, + expression: false }); var S = { input: typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT, @@ -16351,7 +16398,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio case "do": return new AST_Do({ body: in_loop(statement), - condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), + condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp) }); @@ -16373,7 +16420,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio case "return": if (S.in_function == 0) croak("'return' outside of function"); return new AST_Return({ - value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true), + value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true), semicolon(), tmp) }); @@ -16981,6 +17028,9 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio --S.in_loop; return ret; } + if (options.expression) { + return expression(true); + } return function() { var start = S.token; var body = []; @@ -17252,6 +17302,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio } else { g = new SymbolDef(self, globals.size(), node); g.undeclared = true; + g.global = true; globals.set(name, g); } node.thedef = g; @@ -17551,7 +17602,8 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio bracketize: false, semicolons: true, comments: false, - preserve_line: false + preserve_line: false, + negate_iife: !(options && options.beautify) }, true); var indentation = 0; var current_col = 0; @@ -17838,7 +17890,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio var self = this, generator = self._codegen; stream.push_node(self); var needs_parens = self.needs_parens(stream); - var fc = self instanceof AST_Function && !stream.option("beautify"); + var fc = self instanceof AST_Function && stream.option("negate_iife"); if (force_parens || needs_parens && !fc) { stream.with_parens(function() { self.add_comments(stream); @@ -18452,7 +18504,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio var a = output.stack(), i = a.length, node = a[--i], p = a[--i]; while (i > 0) { if (p instanceof AST_Statement && p.body === node) return true; - if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) { + if (p instanceof AST_Seq && p.car === node || p instanceof AST_Call && p.expression === node && !(p instanceof AST_New) || p instanceof AST_Dot && p.expression === node || p instanceof AST_Sub && p.expression === node || p instanceof AST_Conditional && p.condition === node || p instanceof AST_Binary && p.left === node || p instanceof AST_UnaryPostfix && p.expression === node) { node = p; p = a[--i]; } else { @@ -19979,6 +20031,45 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio value: "" }) }); + + case "Function": + if (all(self.args, function(x) { + return x instanceof AST_String; + })) { + try { + var code = "(function(" + self.args.slice(0, -1).map(function(arg) { + return arg.value; + }).join(",") + "){" + self.args[self.args.length - 1].value + "})()"; + var ast = parse(code); + ast.figure_out_scope(); + var comp = new Compressor(compressor.options); + ast = ast.transform(comp); + ast.figure_out_scope(); + ast.mangle_names(); + var fun = ast.body[0].body.expression; + var args = fun.argnames.map(function(arg, i) { + return make_node(AST_String, self.args[i], { + value: arg.print_to_string() + }); + }); + var code = OutputStream(); + AST_BlockStatement.prototype._codegen.call(fun, fun, code); + code = code.toString().replace(/^\{|\}$/g, ""); + args.push(make_node(AST_String, self.args[self.args.length - 1], { + value: code + })); + self.args = args; + return self; + } catch (ex) { + if (ex instanceof JS_Parse_Error) { + compressor.warn("Error parsing code passed to new Function [{file}:{line},{col}]", self.args[self.args.length - 1].start); + compressor.warn(ex.toString()); + } else { + console.log(ex); + } + } + } + break; } } else if (exp instanceof AST_Dot && exp.property == "toString" && self.args.length == 0) { return make_node(AST_Binary, self, { @@ -20582,6 +20673,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio exports["set_difference"] = set_difference; exports["set_intersection"] = set_intersection; exports["makePredicate"] = makePredicate; + exports["all"] = all; exports["Dictionary"] = Dictionary; exports["DEFNODE"] = DEFNODE; exports["AST_Token"] = AST_Token; @@ -21365,6 +21457,15 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { node.left.property && node.left.property.name === 'amd'; }; + //define.amd reference, as in: if (define.amd) + parse.refsDefineAmd = function (node) { + return node && node.type === 'MemberExpression' && + node.object && node.object.name === 'define' && + node.object.type === 'Identifier' && + node.property && node.property.name === 'amd' && + node.property.type === 'Identifier'; + }; + //require(), requirejs(), require.config() and requirejs.config() parse.hasRequire = function (node) { var callName, @@ -21542,7 +21643,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { * Otherwise null. */ parse.parseNode = function (node, onMatch) { - var name, deps, cjsDeps, arg, factory, + var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode, args = node && node[argPropName], callName = parse.hasRequire(node); @@ -21615,6 +21716,36 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { } return onMatch("define", null, name, deps, node); + } else if (node.type === 'CallExpression' && node.callee && + node.callee.type === 'FunctionExpression' && + node.callee.body && node.callee.body.body && + node.callee.body.body.length === 1 && + node.callee.body.body[0].type === 'IfStatement') { + bodyNode = node.callee.body.body[0]; + //Look for a define(Identifier) case, but only if inside an + //if that has a define.amd test + if (bodyNode.consequent && bodyNode.consequent.body) { + exp = bodyNode.consequent.body[0]; + if (exp.type === 'ExpressionStatement' && exp.expression && + parse.hasDefine(exp.expression) && + exp.expression.arguments && + exp.expression.arguments.length === 1 && + exp.expression.arguments[0].type === 'Identifier') { + + //Calls define(Identifier) as first statement in body. + //Confirm the if test references define.amd + traverse(bodyNode.test, function (node) { + if (parse.refsDefineAmd(node)) { + refsDefine = true; + return false; + } + }); + + if (refsDefine) { + return onMatch("define", null, null, null, exp.expression); + } + } + } } }; @@ -21969,7 +22100,7 @@ function (esprima, parse, logger, lang) { if (options.useSourceUrl) { contents = 'eval("' + lang.jsEscape(contents) + - '\\n//@ sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') + + '\\n//# sourceURL=' + (path.indexOf('/') === 0 ? '' : '/') + path + '");\n'; } @@ -22567,7 +22698,7 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { file.saveFile(outFileNameMap, file.readFile(outFileNameMap).replace(mapRegExp, '"file":"' + baseName + '"')); - fileContents = optimized + "\n//@ sourceMappingURL=" + outBaseName + ".map"; + fileContents = optimized + "\n//# sourceMappingURL=" + outBaseName + ".map"; } else { fileContents = optimized; } @@ -23021,7 +23152,7 @@ function (lang, logger, envOptimize, file, parse, logger.trace("Uglify2 file: " + fileName); try { - //var tempContents = fileContents.replace(/\/\/\@ sourceMappingURL=.*$/, ''); + //var tempContents = fileContents.replace(/\/\/\# sourceMappingURL=.*$/, ''); result = uglify2.minify(fileContents, uconfig, baseName + '.src.js'); if (uconfig.outSourceMap && result.map) { resultMap = result.map; @@ -23034,7 +23165,7 @@ function (lang, logger, envOptimize, file, parse, file.saveFile(outFileName + '.src.js', fileContents); } file.saveFile(outFileName + '.map', resultMap); - fileContents = result.code + "\n//@ sourceMappingURL=" + baseName + ".map"; + fileContents = result.code + "\n//# sourceMappingURL=" + baseName + ".map"; } else { fileContents = result.code; } @@ -23930,9 +24061,11 @@ define('build', function (require) { module._sourcePath = buildContext.nameToUrl(module.name); //If the module does not exist, and this is not a "new" module layer, //as indicated by a true "create" property on the module, and - //it is not a plugin-loaded resource, then throw an error. + //it is not a plugin-loaded resource, and there is no + //'rawText' containing the module's source then throw an error. if (!file.exists(module._sourcePath) && !module.create && - module.name.indexOf('!') === -1) { + module.name.indexOf('!') === -1 && + (!config.rawText || !lang.hasProp(config.rawText, module.name))) { throw new Error("ERROR: module path does not exist: " + module._sourcePath + " for module named: " + module.name + ". Path is relative to: " + file.absPath('.')); @@ -24071,7 +24204,7 @@ define('build', function (require) { if (builtModule.sourceMap) { baseName = module._buildPath.split('/'); baseName = baseName.pop(); - finalText += '\n//@ sourceMappingURL=' + baseName + '.map'; + finalText += '\n//# sourceMappingURL=' + baseName + '.map'; file.saveUtf8File(module._buildPath + '.map', builtModule.sourceMap); } file.saveUtf8File(module._buildPath + '-temp', finalText); @@ -25578,7 +25711,7 @@ function (args, quit, logger, build) { } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.3.2, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.3.6, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); From 5092541c4e8ec33159b0d7ad4c36ffe50e6e79df Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Jul 2013 22:03:37 -0700 Subject: [PATCH 017/382] Rev for 2.1.7 --- build/jslib/x.js | 4 ++-- dist/r.js | 8 ++++---- require.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index bdc40908..21171304 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+', + version = '2.1.7', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index 3a9ed039..dea946b1 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.6+ Mon, 08 Jul 2013 02:49:19 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.6+ Mon, 08 Jul 2013 02:49:19 GMT', + version = '2.1.7', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -232,7 +232,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.6+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.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 */ @@ -245,7 +245,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.6+', + version = '2.1.7', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, diff --git a/require.js b/require.js index 6e24bc39..3a061fdb 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.6+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.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 */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.6+', + version = '2.1.7', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, From 71b1c42c5ba99b5d902e420ae46cff9744ea8956 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 8 Jul 2013 16:54:27 -0700 Subject: [PATCH 018/382] Fixes #476, correctly calculate node range when it occurs on first line. --- build/jslib/parse.js | 5 ++++- build/tests/transform/addPath.js | 2 +- build/tests/transform/expected/addPath.js | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/build/jslib/parse.js b/build/jslib/parse.js index b735a51f..f4e95a72 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -825,7 +825,10 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { parse.nodeToString = function (contents, node) { var loc = node.loc, lines = contents.split('\n'), - preamble = lines.slice(0, loc.start.line - 1).join('\n') + '\n' + + firstLine = loc.start.line > 1 ? + lines.slice(0, loc.start.line - 1).join('\n') + '\n' : + '', + preamble = firstLine + lines[loc.start.line - 1].substring(0, loc.start.column), extracted = lines[loc.start.line - 1].substring(loc.start.column) + '\n' + diff --git a/build/tests/transform/addPath.js b/build/tests/transform/addPath.js index 8ffdba02..871e34e1 100644 --- a/build/tests/transform/addPath.js +++ b/build/tests/transform/addPath.js @@ -1,4 +1,3 @@ -//A test of a config modification that adds a path. requirejs.config({ 'something/else': 'ok', _another_thing: 'ok', @@ -6,3 +5,4 @@ requirejs.config({ bad: false, baseUrl: 'some/thing' }); +//DO NOT put a comment first in this file. Need to test 0 position requirejs.config. diff --git a/build/tests/transform/expected/addPath.js b/build/tests/transform/expected/addPath.js index 20761673..b198cc03 100644 --- a/build/tests/transform/expected/addPath.js +++ b/build/tests/transform/expected/addPath.js @@ -1,4 +1,3 @@ -//A test of a config modification that adds a path. requirejs.config({ 'something/else': 'ok', _another_thing: 'ok', @@ -9,3 +8,4 @@ requirejs.config({ newlyAdded: 'some/added/path' } }); +//DO NOT put a comment first in this file. Need to test 0 position requirejs.config. From 723d89eaf337d08cb0e0a5e9598eeff801eb0e2e Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 8 Jul 2013 16:54:53 -0700 Subject: [PATCH 019/382] indicate dev version --- build/jslib/x.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 21171304..d804361b 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.7', + version = '2.1.7+', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, From 18f0c6a434701387fcab77fe94a8e1460f745943 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 8 Jul 2013 16:55:09 -0700 Subject: [PATCH 020/382] snapshot --- dist/r.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index dea946b1..b2ef4d0d 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.7+ Mon, 08 Jul 2013 23:55:02 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.7', + version = '2.1.7+ Mon, 08 Jul 2013 23:55:02 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -21760,7 +21760,10 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { parse.nodeToString = function (contents, node) { var loc = node.loc, lines = contents.split('\n'), - preamble = lines.slice(0, loc.start.line - 1).join('\n') + '\n' + + firstLine = loc.start.line > 1 ? + lines.slice(0, loc.start.line - 1).join('\n') + '\n' : + '', + preamble = firstLine + lines[loc.start.line - 1].substring(0, loc.start.column), extracted = lines[loc.start.line - 1].substring(loc.start.column) + '\n' + From 12c3e11fb1a5d43ad4a10e80901ebce477c919ab Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 8 Jul 2013 23:28:47 -0700 Subject: [PATCH 021/382] Rev for 2.1.8 release --- build/jslib/x.js | 4 ++-- dist/r.js | 8 ++++---- require.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index d804361b..0fa26302 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.7+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.7+', + version = '2.1.8', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index b2ef4d0d..bf8db4ca 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.7+ Mon, 08 Jul 2013 23:55:02 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.7+ Mon, 08 Jul 2013 23:55:02 GMT', + version = '2.1.8', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -232,7 +232,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.8 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 */ @@ -245,7 +245,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.7', + version = '2.1.8', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, diff --git a/require.js b/require.js index 3a061fdb..52c2b076 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.8 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 */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.7', + version = '2.1.8', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, From f2489fd594ea4285a5308e546499eba655cdc8d5 Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 19 Jul 2013 15:35:42 -0700 Subject: [PATCH 022/382] Fixes #489 xpcshell: windows FileUtils.File does not like / paths --- build/jslib/x.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 0fa26302..e785f26a 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8', + version = '2.1.8+', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -136,6 +136,7 @@ var requirejs, require, define, xpcUtil; } xpcUtil = { + isWindows: ('@mozilla.org/windows-registry-key;1' in Cc), cwd: function () { return FileUtils.getFile("CurWorkD", []).path; }, @@ -169,10 +170,15 @@ var requirejs, require, define, xpcUtil; }, xpfile: function (path) { + var fullPath; try { - return new FileUtils.File(xpcUtil.normalize(path)); + fullPath = xpcUtil.normalize(path); + if (xpcUtil.isWindows) { + fullPath = fullPath.replace(/\//g, '\\'); + } + return new FileUtils.File(fullPath); } catch (e) { - throw new Error(path + ' failed: ' + e); + throw new Error((fullPath || path) + ' failed: ' + e); } }, From d563dc51438d564438e2c78ccf36e828ea42772f Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 19 Jul 2013 15:36:04 -0700 Subject: [PATCH 023/382] snapshot --- dist/r.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index bf8db4ca..ca1fbabb 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 19 Jul 2013 22:35:53 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8', + version = '2.1.8+ Fri, 19 Jul 2013 22:35:53 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -136,6 +136,7 @@ var requirejs, require, define, xpcUtil; } xpcUtil = { + isWindows: ('@mozilla.org/windows-registry-key;1' in Cc), cwd: function () { return FileUtils.getFile("CurWorkD", []).path; }, @@ -169,10 +170,15 @@ var requirejs, require, define, xpcUtil; }, xpfile: function (path) { + var fullPath; try { - return new FileUtils.File(xpcUtil.normalize(path)); + fullPath = xpcUtil.normalize(path); + if (xpcUtil.isWindows) { + fullPath = fullPath.replace(/\//g, '\\'); + } + return new FileUtils.File(fullPath); } catch (e) { - throw new Error(path + ' failed: ' + e); + throw new Error((fullPath || path) + ' failed: ' + e); } }, From 49a8f59487387a17d1b567472252e80cc509a686 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 12 Aug 2013 19:53:44 -0700 Subject: [PATCH 024/382] Fixes #506, allow option to turn of r.js semicolon insertion --- .gitignore | 1 + build/example.build.js | 14 ++++++++++++-- build/jslib/build.js | 14 +++++++------- build/tests/builds.js | 19 +++++++++++++++++++ build/tests/lib/semicolonInsert/a.js | 4 ++++ build/tests/lib/semicolonInsert/b.js | 3 +++ build/tests/lib/semicolonInsert/build.js | 7 +++++++ build/tests/lib/semicolonInsert/c.js | 4 ++++ build/tests/lib/semicolonInsert/expected.js | 16 ++++++++++++++++ 9 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 build/tests/lib/semicolonInsert/a.js create mode 100644 build/tests/lib/semicolonInsert/b.js create mode 100644 build/tests/lib/semicolonInsert/build.js create mode 100644 build/tests/lib/semicolonInsert/c.js create mode 100644 build/tests/lib/semicolonInsert/expected.js diff --git a/.gitignore b/.gitignore index b0886f39..07188b1c 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,7 @@ build/tests/lib/removeCombined/app-built build/tests/lib/removeCombined/baseUrl-built build/tests/lib/requireHoist/perLayer/built build/tests/lib/rhino-186/built +build/tests/lib/semicolonInsert/a-built.js build/tests/lib/shimFakeDefine/main-built.js build/tests/lib/sourcemap/www-built build/tests/lib/stubModules/create/foobar-built.js diff --git a/build/example.build.js b/build/example.build.js index 423e023b..6e7659c8 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -575,6 +575,16 @@ //dependencies and the size of the involved libraries, increasing the wait //interval may be required. Default is 7 seconds. Setting the value to 0 //disables the waiting interval. - waitSeconds: 7 - + waitSeconds: 7, + + //Introduced in 2.1.9: normally r.js inserts a semicolon at the end of a + //file if there is not already one present, to avoid issues with + //concatenated files and automatic semicolon insertion (ASI) rules for + //JavaScript. It is a very blunt fix that is safe to do, but if you want to + //lint the build output, depending on the linter rules, it may not like it. + //Setting this option to true skips this insertion. However, by doing this, + //you take responsibility for making sure your concatenated code works with + //JavaScript's ASI rules, and that you use a minifier that understands when + //to insert semicolons to avoid ASI pitfalls. + skipSemiColonInsertion: false }) diff --git a/build/jslib/build.js b/build/jslib/build.js index 27390237..2647eded 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -78,8 +78,8 @@ define(function (require) { * the style of omitting semicolons and rely on ASI. Add a semicolon in * those cases. */ - function addSemiColon(text) { - if (endsWithSemiColonRegExp.test(text)) { + function addSemiColon(text, config) { + if (config.skipSemiColonInsertion || endsWithSemiColonRegExp.test(text)) { return text; } else { return text + ";"; @@ -1583,7 +1583,7 @@ define(function (require) { if (builder.write) { writeApi = function (input) { - singleContents += "\n" + addSemiColon(input); + singleContents += "\n" + addSemiColon(input, config); if (config.onBuildWrite) { singleContents = config.onBuildWrite(moduleName, path, singleContents); } @@ -1592,7 +1592,7 @@ define(function (require) { singleContents += "\n" + addSemiColon(build.toTransport(namespace, moduleName, path, input, layer, { useSourceUrl: layer.context.config.useSourceUrl - })); + }), config); if (config.onBuildWrite) { singleContents = config.onBuildWrite(moduleName, path, singleContents); } @@ -1643,7 +1643,7 @@ define(function (require) { }); if (packageConfig && !hasPackageName) { - currContents = addSemiColon(currContents) + '\n'; + currContents = addSemiColon(currContents, config) + '\n'; currContents += namespaceWithDot + "define('" + packageConfig.name + "', ['" + moduleName + "'], function (main) { return main; });\n"; @@ -1655,7 +1655,7 @@ define(function (require) { //Semicolon is for files that are not well formed when //concatenated with other content. - singleContents += "\n" + addSemiColon(currContents); + singleContents += "\n" + addSemiColon(currContents, config); }); } }).then(function () { @@ -1722,7 +1722,7 @@ define(function (require) { path = module._buildPath; } builder.onLayerEnd(function (input) { - fileContents += "\n" + addSemiColon(input); + fileContents += "\n" + addSemiColon(input, config); }, { name: module.name, path: path diff --git a/build/tests/builds.js b/build/tests/builds.js index 987d0ea5..0e5e7cd6 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1976,4 +1976,23 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + //Allow skipping semicolon insertion + //https://github.com/jrburke/r.js/issues/506 + doh.register("semicolonInsert", + [ + function semicolonInsert(t) { + file.deleteFile("lib/semicolonInsert/a-built.js"); + + build(["lib/semicolonInsert/build.js"]); + + t.is(nol(c("lib/semicolonInsert/expected.js")), + nol(c("lib/semicolonInsert/a-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + }); diff --git a/build/tests/lib/semicolonInsert/a.js b/build/tests/lib/semicolonInsert/a.js new file mode 100644 index 00000000..99c1cc5e --- /dev/null +++ b/build/tests/lib/semicolonInsert/a.js @@ -0,0 +1,4 @@ +var foo = { + +} + diff --git a/build/tests/lib/semicolonInsert/b.js b/build/tests/lib/semicolonInsert/b.js new file mode 100644 index 00000000..6bee38fd --- /dev/null +++ b/build/tests/lib/semicolonInsert/b.js @@ -0,0 +1,3 @@ +define(['c'], function (c) { + +}) diff --git a/build/tests/lib/semicolonInsert/build.js b/build/tests/lib/semicolonInsert/build.js new file mode 100644 index 00000000..91d96b30 --- /dev/null +++ b/build/tests/lib/semicolonInsert/build.js @@ -0,0 +1,7 @@ +{ + baseUrl: '.', + include: ['a', 'b'], + out: 'a-built.js', + skipSemiColonInsertion: true, + optimize: 'none' +} diff --git a/build/tests/lib/semicolonInsert/c.js b/build/tests/lib/semicolonInsert/c.js new file mode 100644 index 00000000..03b586c4 --- /dev/null +++ b/build/tests/lib/semicolonInsert/c.js @@ -0,0 +1,4 @@ +define({ + name: 'c' +}) + diff --git a/build/tests/lib/semicolonInsert/expected.js b/build/tests/lib/semicolonInsert/expected.js new file mode 100644 index 00000000..6c2e438f --- /dev/null +++ b/build/tests/lib/semicolonInsert/expected.js @@ -0,0 +1,16 @@ + +var foo = { + +} + + +define("a", function(){}); + +define('c',{ + name: 'c' +}) + + +define('b',['c'], function (c) { + +}) From d9400ebe791b2104af9a3d5894e8926d9187bce7 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 12 Aug 2013 19:54:19 -0700 Subject: [PATCH 025/382] snapshot --- dist/r.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/dist/r.js b/dist/r.js index ca1fbabb..e96af065 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 19 Jul 2013 22:35:53 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Tue, 13 Aug 2013 02:54:07 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 19 Jul 2013 22:35:53 GMT', + version = '2.1.8+ Tue, 13 Aug 2013 02:54:07 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -23844,8 +23844,8 @@ define('build', function (require) { * the style of omitting semicolons and rely on ASI. Add a semicolon in * those cases. */ - function addSemiColon(text) { - if (endsWithSemiColonRegExp.test(text)) { + function addSemiColon(text, config) { + if (config.skipSemiColonInsertion || endsWithSemiColonRegExp.test(text)) { return text; } else { return text + ";"; @@ -25349,7 +25349,7 @@ define('build', function (require) { if (builder.write) { writeApi = function (input) { - singleContents += "\n" + addSemiColon(input); + singleContents += "\n" + addSemiColon(input, config); if (config.onBuildWrite) { singleContents = config.onBuildWrite(moduleName, path, singleContents); } @@ -25358,7 +25358,7 @@ define('build', function (require) { singleContents += "\n" + addSemiColon(build.toTransport(namespace, moduleName, path, input, layer, { useSourceUrl: layer.context.config.useSourceUrl - })); + }), config); if (config.onBuildWrite) { singleContents = config.onBuildWrite(moduleName, path, singleContents); } @@ -25409,7 +25409,7 @@ define('build', function (require) { }); if (packageConfig && !hasPackageName) { - currContents = addSemiColon(currContents) + '\n'; + currContents = addSemiColon(currContents, config) + '\n'; currContents += namespaceWithDot + "define('" + packageConfig.name + "', ['" + moduleName + "'], function (main) { return main; });\n"; @@ -25421,7 +25421,7 @@ define('build', function (require) { //Semicolon is for files that are not well formed when //concatenated with other content. - singleContents += "\n" + addSemiColon(currContents); + singleContents += "\n" + addSemiColon(currContents, config); }); } }).then(function () { @@ -25488,7 +25488,7 @@ define('build', function (require) { path = module._buildPath; } builder.onLayerEnd(function (input) { - fileContents += "\n" + addSemiColon(input); + fileContents += "\n" + addSemiColon(input, config); }, { name: module.name, path: path From b7a4c2b8e745de9c07c59557306ff7ff07b79b72 Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 11:20:19 -0700 Subject: [PATCH 026/382] Update expected test result since text plugin has changed --- build/tests/lib/moduleThenPlugin/expected.js | 27 +++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/build/tests/lib/moduleThenPlugin/expected.js b/build/tests/lib/moduleThenPlugin/expected.js index df90802b..237894d9 100644 --- a/build/tests/lib/moduleThenPlugin/expected.js +++ b/build/tests/lib/moduleThenPlugin/expected.js @@ -7,7 +7,7 @@ require(['sub1'], function (sub1) {}); define("main", function(){}); /** - * @license RequireJS text 2.0.7 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/requirejs/text for details */ @@ -19,7 +19,7 @@ define("main", function(){}); define('text',['module'], function (module) { - var text, fs, Cc, Ci, + var text, fs, Cc, Ci, xpcIsWindows, progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, @@ -31,7 +31,7 @@ define('text',['module'], function (module) { masterConfig = (module.config && module.config()) || {}; text = { - version: '2.0.7', + version: '2.0.10', strip: function (content) { //Strips declarations so that external SVG and XML @@ -184,6 +184,12 @@ define('text',['module'], function (module) { useXhr = (masterConfig.useXhr) || text.useXhr; + // Do not load if it is an empty: url + if (url.indexOf('empty:') === 0) { + onLoad(); + return; + } + //Load the text. Use XHR if possible and in a browser. if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { text.get(url, function (content) { @@ -245,7 +251,8 @@ define('text',['module'], function (module) { if (masterConfig.env === 'node' || (!masterConfig.env && typeof process !== "undefined" && process.versions && - !!process.versions.node)) { + !!process.versions.node && + !process.versions['node-webkit'])) { //Using special require.nodeRequire, something added by r.js. fs = require.nodeRequire('fs'); @@ -351,11 +358,17 @@ define('text',['module'], function (module) { Cc = Components.classes, Ci = Components.interfaces; Components.utils['import']('resource://gre/modules/FileUtils.jsm'); + xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); text.get = function (url, callback) { - var inStream, convertStream, - readData = {}, - fileObj = new FileUtils.File(url); + var inStream, convertStream, fileObj, + readData = {}; + + if (xpcIsWindows) { + url = url.replace(/\//g, '\\'); + } + + fileObj = new FileUtils.File(url); //XPCOM, you so crazy try { From b0397ce126cf36bf83518fecc8e9fd8d16f3cfd9 Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 11:32:10 -0700 Subject: [PATCH 027/382] Fixes #495, make sure baseUrl set for node is JS-escaped --- build/jslib/x.js | 3 ++- tests/node/canvasTest.js | 39 --------------------------------------- 2 files changed, 2 insertions(+), 40 deletions(-) delete mode 100644 tests/node/canvasTest.js diff --git a/build/jslib/x.js b/build/jslib/x.js index e785f26a..2f61c550 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -287,7 +287,8 @@ var requirejs, require, define, xpcUtil; dir = dir.split('/'); dir.pop(); dir = dir.join('/'); - exec("require({baseUrl: '" + dir + "'});"); + //Make sure dir is JS-escaped, since it will be part of a JS string. + exec("require({baseUrl: '" + dir.replace(/[\\"']/g, '\\$&') + "'});"); } } diff --git a/tests/node/canvasTest.js b/tests/node/canvasTest.js deleted file mode 100644 index b6b1a520..00000000 --- a/tests/node/canvasTest.js +++ /dev/null @@ -1,39 +0,0 @@ -//Tested with nave, node 0.2.5, -//npm install canvas -//npm install express - -/*jslint strict: false */ -/*global require: false, console: false */ - -var require = require('../../r'); - -require(['canvas', 'express'], function (Canvas, express) { - var canvas = new Canvas(200, 200), - ctx = canvas.getContext('2d'), - app = express.createServer(); - - - app.configure(function () { - - app.get('/', function (req, res) { - res.send('hello world'); - }); - - //app.use(express.gzip()); - app.listen(3000); - }); - - - ctx.font = '30px Impact'; - ctx.rotate(0.1); - ctx.fillText("Awesome!", 50, 100); - - var te = ctx.measureText('Awesome!'); - ctx.strokeStyle = 'rgba(0,0,0,0.5)'; - ctx.beginPath(); - ctx.lineTo(50, 102); - ctx.lineTo(50 + te.width, 102); - ctx.stroke(); - - console.log(''); -}); From 3775b6741c5b961d921b5e88835b13c192bd626d Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 11:32:53 -0700 Subject: [PATCH 028/382] snapshot --- dist/r.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index e96af065..b2e66ef8 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Tue, 13 Aug 2013 02:54:07 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Tue, 13 Aug 2013 18:32:42 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Tue, 13 Aug 2013 02:54:07 GMT', + version = '2.1.8+ Tue, 13 Aug 2013 18:32:42 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25570,7 +25570,8 @@ define('build', function (require) { dir = dir.split('/'); dir.pop(); dir = dir.join('/'); - exec("require({baseUrl: '" + dir + "'});"); + //Make sure dir is JS-escaped, since it will be part of a JS string. + exec("require({baseUrl: '" + dir.replace(/[\\"']/g, '\\$&') + "'});"); } } From eb3884882f4524e8d0f381edbf6d2fb9bc74a3bd Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 12:43:33 -0700 Subject: [PATCH 029/382] Fixes #508, make sure _buildPaths are normalized for later comparisions --- build/jslib/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 2647eded..82431831 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -361,7 +361,7 @@ define(function (require) { return function () { //Save off buildPath to module index in a hash for quicker //lookup later. - config._buildPathToModuleIndex[module._buildPath] = i; + config._buildPathToModuleIndex[file.normalize(module._buildPath)] = i; //Call require to calculate dependencies. return build.traceDependencies(module, config) From d85ae3c4a4be33b09ac8391872bfe4b16b8f0908 Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 12:43:51 -0700 Subject: [PATCH 030/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index b2e66ef8..ddd89816 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Tue, 13 Aug 2013 18:32:42 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Tue, 13 Aug 2013 19:43:43 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Tue, 13 Aug 2013 18:32:42 GMT', + version = '2.1.8+ Tue, 13 Aug 2013 19:43:43 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24127,7 +24127,7 @@ define('build', function (require) { return function () { //Save off buildPath to module index in a hash for quicker //lookup later. - config._buildPathToModuleIndex[module._buildPath] = i; + config._buildPathToModuleIndex[file.normalize(module._buildPath)] = i; //Call require to calculate dependencies. return build.traceDependencies(module, config) From c3a998941e3d1fe638e4659725042aca77280be6 Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 16:17:01 -0700 Subject: [PATCH 031/382] Fixes #500, make sure layer overrides are pristine --- .gitignore | 1 + build/jslib/build.js | 39 ++++++++++++++++++++++----------------- build/jslib/lang.js | 40 ++++++++++++++++++++++++++++++++++++++-- build/tests/builds.js | 22 ++++++++++++++++++++++ 4 files changed, 83 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 07188b1c..69468239 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ build/tests/lib/cssRemoveCombined/www-built build/tests/lib/depsConfig/main-built.js build/tests/lib/dormant213/main-built.js build/tests/lib/dotpackage/built +build/tests/lib/dualLayerOverride/built build/tests/lib/empty/built build/tests/lib/hasOwnProperty/built.js build/tests/lib/iife/main-built.js diff --git a/build/jslib/build.js b/build/jslib/build.js index 82431831..a59a4630 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -353,6 +353,8 @@ define(function (require) { if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) { buildFileContents += optimize.css(config.dir, config); } + }).then(function() { + baseConfig = lang.deeplikeCopy(require.s.contexts._.config); }).then(function () { var actions = []; @@ -364,7 +366,7 @@ define(function (require) { config._buildPathToModuleIndex[file.normalize(module._buildPath)] = i; //Call require to calculate dependencies. - return build.traceDependencies(module, config) + return build.traceDependencies(module, config, baseConfig) .then(function (layer) { module.layer = layer; }); @@ -392,7 +394,7 @@ define(function (require) { if (found) { module.excludeLayers[i] = found; } else { - return build.traceDependencies({name: exclude}, config) + return build.traceDependencies({name: exclude}, config, baseConfig) .then(function (layer) { module.excludeLayers[i] = { layer: layer }; }); @@ -1303,13 +1305,14 @@ define(function (require) { * given module. * * @param {Object} module the module object from the build config info. - * @param {Object} the build config object. + * @param {Object} config the build config object. + * @param {Object} [baseLoaderConfig] the base loader config to use for env resets. * * @returns {Object} layer information about what paths and modules should * be in the flattened module. */ - build.traceDependencies = function (module, config) { - var include, override, layer, context, baseConfig, oldContext, + build.traceDependencies = function (module, config, baseLoaderConfig) { + var include, override, layer, context, oldContext, rawTextByIds, syncChecks = { rhino: true, @@ -1324,15 +1327,13 @@ define(function (require) { //Grab the reset layer and context after the reset, but keep the //old config to reuse in the new context. - baseConfig = oldContext.config; layer = require._layer; context = layer.context; //Put back basic config, use a fresh object for it. - //WARNING: probably not robust for paths and packages/packagePaths, - //since those property's objects can be modified. But for basic - //config clone it works out. - require(lang.mixin({}, baseConfig, true)); + if (baseLoaderConfig) { + require(lang.deeplikeCopy(baseLoaderConfig)); + } logger.trace("\nTracing dependencies for: " + (module.name || module.out)); include = module.name && !module.create ? [module.name] : []; @@ -1342,8 +1343,11 @@ define(function (require) { //If there are overrides to basic config, set that up now.; if (module.override) { - override = lang.mixin({}, baseConfig, true); - lang.mixin(override, module.override, true); + if (baseLoaderConfig) { + override = build.createOverrideConfig(baseLoaderConfig, module.override); + } else { + override = lang.deeplikeCopy(module.override); + } require(override); } @@ -1389,8 +1393,8 @@ define(function (require) { return deferred.promise.then(function () { //Reset config - if (module.override) { - require(baseConfig); + if (module.override && baseLoaderConfig) { + require(lang.deeplikeCopy(baseLoaderConfig)); } build.checkForErrors(context); @@ -1471,10 +1475,10 @@ define(function (require) { }; build.createOverrideConfig = function (config, override) { - var cfg = {}; + var cfg = lang.deeplikeCopy(config), + oride = lang.deeplikeCopy(override); - lang.mixin(cfg, config, true); - lang.eachProp(override, function (value, prop) { + lang.eachProp(oride, function (value, prop) { if (hasProp(build.objProps, prop)) { //An object property, merge keys. Start a new object //so that source object in config does not get modified. @@ -1485,6 +1489,7 @@ define(function (require) { cfg[prop] = override[prop]; } }); + return cfg; }; diff --git a/build/jslib/lang.js b/build/jslib/lang.js index 7a5bdac5..bedd8fbb 100644 --- a/build/jslib/lang.js +++ b/build/jslib/lang.js @@ -49,8 +49,8 @@ define(function () { _mixin: function(dest, source, override){ var name; for (name in source) { - if(source.hasOwnProperty(name) - && (override || !dest.hasOwnProperty(name))) { + if(source.hasOwnProperty(name) && + (override || !dest.hasOwnProperty(name))) { dest[name] = source[name]; } } @@ -78,6 +78,42 @@ define(function () { return dest; // Object }, + + /** + * Does a type of deep copy. Do not give it anything fancy, best + * for basic object copies of objects that also work well as + * JSON-serialized things, or has properties pointing to functions. + * For non-array/object values, just returns the same object. + * @param {Object} obj copy properties from this object + * @param {Object} [result] optional result object to use + * @return {Object} + */ + deeplikeCopy: function (obj) { + var type, result; + + if (lang.isArray(obj)) { + result = []; + obj.forEach(function(value) { + result.push(lang.deeplikeCopy(value)); + }); + return result; + } + + type = typeof obj; + if (obj === null || obj === undefined || type === 'boolean' || + type === 'string' || type === 'number' || lang.isFunction(obj) || + lang.isRegExp(obj)) { + return obj; + } + + //Anything else is an object, hopefully. + result = {}; + lang.eachProp(obj, function(value, key) { + result[key] = lang.deeplikeCopy(value); + }); + return result; + }, + delegate: (function () { // boodman/crockford delegation w/ cornford optimization function TMP() {} diff --git a/build/tests/builds.js b/build/tests/builds.js index 0e5e7cd6..fe79d2b0 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1995,4 +1995,26 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + + //Make sure overrides for each build layer are pristine + //https://github.com/jrburke/r.js/issues/500 + doh.register("dualLayerOverride", + [ + function dualLayerOverride(t) { + file.deleteFile("lib/dualLayerOverride/built"); + + build(["lib/dualLayerOverride/build.js"]); + + t.is(nol(c("lib/dualLayerOverride/expectedMessage.js")), + nol(c("lib/dualLayerOverride/built/message.js"))); + t.is(nol(c("lib/dualLayerOverride/expectedWho.js")), + nol(c("lib/dualLayerOverride/built/who.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + }); From 15d9dea96702b67b5a4054cc03a8c8e9e4f4949c Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 16:17:22 -0700 Subject: [PATCH 032/382] snapshot --- dist/r.js | 83 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/dist/r.js b/dist/r.js index ddd89816..663f9b57 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Tue, 13 Aug 2013 19:43:43 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Tue, 13 Aug 2013 23:17:08 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Tue, 13 Aug 2013 19:43:43 GMT', + version = '2.1.8+ Tue, 13 Aug 2013 23:17:08 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -2663,8 +2663,8 @@ define('lang', function () { _mixin: function(dest, source, override){ var name; for (name in source) { - if(source.hasOwnProperty(name) - && (override || !dest.hasOwnProperty(name))) { + if(source.hasOwnProperty(name) && + (override || !dest.hasOwnProperty(name))) { dest[name] = source[name]; } } @@ -2692,6 +2692,42 @@ define('lang', function () { return dest; // Object }, + + /** + * Does a type of deep copy. Do not give it anything fancy, best + * for basic object copies of objects that also work well as + * JSON-serialized things, or has properties pointing to functions. + * For non-array/object values, just returns the same object. + * @param {Object} obj copy properties from this object + * @param {Object} [result] optional result object to use + * @return {Object} + */ + deeplikeCopy: function (obj) { + var type, result; + + if (lang.isArray(obj)) { + result = []; + obj.forEach(function(value) { + result.push(lang.deeplikeCopy(value)); + }); + return result; + } + + type = typeof obj; + if (obj === null || obj === undefined || type === 'boolean' || + type === 'string' || type === 'number' || lang.isFunction(obj) || + lang.isRegExp(obj)) { + return obj; + } + + //Anything else is an object, hopefully. + result = {}; + lang.eachProp(obj, function(value, key) { + result[key] = lang.deeplikeCopy(value); + }); + return result; + }, + delegate: (function () { // boodman/crockford delegation w/ cornford optimization function TMP() {} @@ -24119,6 +24155,8 @@ define('build', function (require) { if (config.optimizeCss && config.optimizeCss !== "none" && config.dir) { buildFileContents += optimize.css(config.dir, config); } + }).then(function() { + baseConfig = lang.deeplikeCopy(require.s.contexts._.config); }).then(function () { var actions = []; @@ -24130,7 +24168,7 @@ define('build', function (require) { config._buildPathToModuleIndex[file.normalize(module._buildPath)] = i; //Call require to calculate dependencies. - return build.traceDependencies(module, config) + return build.traceDependencies(module, config, baseConfig) .then(function (layer) { module.layer = layer; }); @@ -24158,7 +24196,7 @@ define('build', function (require) { if (found) { module.excludeLayers[i] = found; } else { - return build.traceDependencies({name: exclude}, config) + return build.traceDependencies({name: exclude}, config, baseConfig) .then(function (layer) { module.excludeLayers[i] = { layer: layer }; }); @@ -25069,13 +25107,14 @@ define('build', function (require) { * given module. * * @param {Object} module the module object from the build config info. - * @param {Object} the build config object. + * @param {Object} config the build config object. + * @param {Object} [baseLoaderConfig] the base loader config to use for env resets. * * @returns {Object} layer information about what paths and modules should * be in the flattened module. */ - build.traceDependencies = function (module, config) { - var include, override, layer, context, baseConfig, oldContext, + build.traceDependencies = function (module, config, baseLoaderConfig) { + var include, override, layer, context, oldContext, rawTextByIds, syncChecks = { rhino: true, @@ -25090,15 +25129,13 @@ define('build', function (require) { //Grab the reset layer and context after the reset, but keep the //old config to reuse in the new context. - baseConfig = oldContext.config; layer = require._layer; context = layer.context; //Put back basic config, use a fresh object for it. - //WARNING: probably not robust for paths and packages/packagePaths, - //since those property's objects can be modified. But for basic - //config clone it works out. - require(lang.mixin({}, baseConfig, true)); + if (baseLoaderConfig) { + require(lang.deeplikeCopy(baseLoaderConfig)); + } logger.trace("\nTracing dependencies for: " + (module.name || module.out)); include = module.name && !module.create ? [module.name] : []; @@ -25108,8 +25145,11 @@ define('build', function (require) { //If there are overrides to basic config, set that up now.; if (module.override) { - override = lang.mixin({}, baseConfig, true); - lang.mixin(override, module.override, true); + if (baseLoaderConfig) { + override = build.createOverrideConfig(baseLoaderConfig, module.override); + } else { + override = lang.deeplikeCopy(module.override); + } require(override); } @@ -25155,8 +25195,8 @@ define('build', function (require) { return deferred.promise.then(function () { //Reset config - if (module.override) { - require(baseConfig); + if (module.override && baseLoaderConfig) { + require(lang.deeplikeCopy(baseLoaderConfig)); } build.checkForErrors(context); @@ -25237,10 +25277,10 @@ define('build', function (require) { }; build.createOverrideConfig = function (config, override) { - var cfg = {}; + var cfg = lang.deeplikeCopy(config), + oride = lang.deeplikeCopy(override); - lang.mixin(cfg, config, true); - lang.eachProp(override, function (value, prop) { + lang.eachProp(oride, function (value, prop) { if (hasProp(build.objProps, prop)) { //An object property, merge keys. Start a new object //so that source object in config does not get modified. @@ -25251,6 +25291,7 @@ define('build', function (require) { cfg[prop] = override[prop]; } }); + return cfg; }; From 1c3e04d25e948920b80bc01cd1ec57d55003b5ab Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 13 Aug 2013 17:46:20 -0700 Subject: [PATCH 033/382] forgot test files --- build/tests/lib/dualLayerOverride/build.js | 9 +++++++++ build/tests/lib/dualLayerOverride/expectedMessage.js | 5 +++++ build/tests/lib/dualLayerOverride/expectedWho.js | 4 ++++ build/tests/lib/dualLayerOverride/message.js | 4 ++++ build/tests/lib/dualLayerOverride/who.js | 3 +++ 5 files changed, 25 insertions(+) create mode 100644 build/tests/lib/dualLayerOverride/build.js create mode 100644 build/tests/lib/dualLayerOverride/expectedMessage.js create mode 100644 build/tests/lib/dualLayerOverride/expectedWho.js create mode 100644 build/tests/lib/dualLayerOverride/message.js create mode 100644 build/tests/lib/dualLayerOverride/who.js diff --git a/build/tests/lib/dualLayerOverride/build.js b/build/tests/lib/dualLayerOverride/build.js new file mode 100644 index 00000000..9e8e9627 --- /dev/null +++ b/build/tests/lib/dualLayerOverride/build.js @@ -0,0 +1,9 @@ +({ + "optimize": "none", + "dir" : "built", + "modules" : [ + { "name" : "message", "override" : { "paths" : { "who" : "empty:" } } }, + { "name" : "who", "override" : { "paths" : { "message" : "empty:" } } } + ] +}) + diff --git a/build/tests/lib/dualLayerOverride/expectedMessage.js b/build/tests/lib/dualLayerOverride/expectedMessage.js new file mode 100644 index 00000000..4b56a608 --- /dev/null +++ b/build/tests/lib/dualLayerOverride/expectedMessage.js @@ -0,0 +1,5 @@ + +define( 'message',[ 'who' ], function ( who ) { + return 'hello ' + who; +} ); + diff --git a/build/tests/lib/dualLayerOverride/expectedWho.js b/build/tests/lib/dualLayerOverride/expectedWho.js new file mode 100644 index 00000000..4816640f --- /dev/null +++ b/build/tests/lib/dualLayerOverride/expectedWho.js @@ -0,0 +1,4 @@ + +define( 'who',[],function ( ) { + return 'world'; +} ); diff --git a/build/tests/lib/dualLayerOverride/message.js b/build/tests/lib/dualLayerOverride/message.js new file mode 100644 index 00000000..7a097c6d --- /dev/null +++ b/build/tests/lib/dualLayerOverride/message.js @@ -0,0 +1,4 @@ +define( [ 'who' ], function ( who ) { + return 'hello ' + who; +} ); + diff --git a/build/tests/lib/dualLayerOverride/who.js b/build/tests/lib/dualLayerOverride/who.js new file mode 100644 index 00000000..afcd6477 --- /dev/null +++ b/build/tests/lib/dualLayerOverride/who.js @@ -0,0 +1,3 @@ +define( function ( ) { + return 'world'; +} ); From 917e44871f60082b5a1073c94c45f4284f1e477b Mon Sep 17 00:00:00 2001 From: mone Date: Wed, 28 Aug 2013 18:29:21 +0200 Subject: [PATCH 034/382] use the default externs when compiling code with the closure compiler. --- build/jslib/rhino/optimize.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/build/jslib/rhino/optimize.js b/build/jslib/rhino/optimize.js index 9580d739..11c3dbb3 100644 --- a/build/jslib/rhino/optimize.js +++ b/build/jslib/rhino/optimize.js @@ -79,12 +79,12 @@ define(['logger', 'env!env/file'], function (logger, file) { outBaseName, outFileNameMap, outFileNameMapContent, jscomp = Packages.com.google.javascript.jscomp, flags = Packages.com.google.common.flags, - //Fake extern - externSourceFile = closurefromCode("fakeextern.js", " "), //Set up source input jsSourceFile = closurefromCode(String(fileName), String(fileContents)), + sourceListArray = new java.util.ArrayList(), options, option, FLAG_compilation_level, compiler, - Compiler = Packages.com.google.javascript.jscomp.Compiler; + Compiler = Packages.com.google.javascript.jscomp.Compiler, + CommandLineRunner = Packages.com.google.javascript.jscomp.CommandLineRunner; logger.trace("Minifying file: " + fileName); @@ -115,8 +115,12 @@ define(['logger', 'env!env/file'], function (logger, file) { //Trigger the compiler Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']); compiler = new Compiler(); + + //fill the sourceArrrayList; we need the ArrayList because the only overload of compile + //accepting the getDefaultExterns return value (a List) also wants the sources as a List + sourceListArray.add(jsSourceFile); - result = compiler.compile(externSourceFile, jsSourceFile, options); + result = compiler.compile(CommandLineRunner.getDefaultExterns(), sourceListArray, options); if (result.success) { optimized = String(compiler.toSource()); From fc90c5ce7875168a79fa49d94f3c94cdc3726c0d Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 29 Aug 2013 20:18:51 -0700 Subject: [PATCH 035/382] Fixes #755 removeCombined could delete files outside the output dir --- .gitignore | 1 + build/jslib/build.js | 11 +++++++++-- build/tests/builds.js | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 69468239..612b8118 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ build/tests/lib/rawText/built.js build/tests/lib/rawTextNameTarget/a-built.js build/tests/lib/removeCombined/app-built build/tests/lib/removeCombined/baseUrl-built +build/tests/lib/removeCombinedPaths/testcase/project/build/build_output build/tests/lib/requireHoist/perLayer/built build/tests/lib/rhino-186/built build/tests/lib/semicolonInsert/a-built.js diff --git a/build/jslib/build.js b/build/jslib/build.js index a59a4630..ccad44e9 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -477,9 +477,16 @@ define(function (require) { //Be sure not to remove other build layers. if (config.removeCombined) { module.layer.buildFilePaths.forEach(function (path) { - if (file.exists(path) && !modules.some(function (mod) { + var isLayer = modules.some(function (mod) { return mod._buildPath === path; - })) { + }), + relPath = build.makeRelativeFilePath(config.dir, path); + + if (file.exists(path) && + // not a build layer target + !isLayer && + // not outside the build directory + relPath.indexOf('..') !== 0) { file.deleteFile(path); } }); diff --git a/build/tests/builds.js b/build/tests/builds.js index fe79d2b0..08c8fb5d 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2017,4 +2017,23 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + //Do not removeCombined files that are outside the build dir. + //https://github.com/jrburke/requirejs/issues/755 + doh.register("removeCombinedPaths", + [ + function removeCombinedPaths(t) { + file.deleteFile("lib/removeCombinedPaths/testcase/project/build/build_output"); + + build(["lib/removeCombinedPaths/testcase/project/build/build.js"]); + + + t.is(true, file.exists("lib/removeCombinedPaths/testcase/lib/main.js")); + t.is(true, file.exists("lib/removeCombinedPaths/testcase/project/build/build_output/main.js")); + + require._buildReset(); + } + + ] + ); + doh.run(); }); From 218628f8dd92e57dfa71306ea8ba746130370223 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 29 Aug 2013 20:19:17 -0700 Subject: [PATCH 036/382] Relates to #755 removeCombined could delete files outside the output dir --- .../lib/removeCombinedPaths/testcase/lib/main.js | 4 ++++ .../testcase/project/build/build.js | 16 ++++++++++++++++ .../testcase/project/src/main.js | 5 +++++ 3 files changed, 25 insertions(+) create mode 100644 build/tests/lib/removeCombinedPaths/testcase/lib/main.js create mode 100644 build/tests/lib/removeCombinedPaths/testcase/project/build/build.js create mode 100644 build/tests/lib/removeCombinedPaths/testcase/project/src/main.js diff --git a/build/tests/lib/removeCombinedPaths/testcase/lib/main.js b/build/tests/lib/removeCombinedPaths/testcase/lib/main.js new file mode 100644 index 00000000..2f8dc741 --- /dev/null +++ b/build/tests/lib/removeCombinedPaths/testcase/lib/main.js @@ -0,0 +1,4 @@ +define(function(require, exports, module) { + console.log("lib main"); +}); + diff --git a/build/tests/lib/removeCombinedPaths/testcase/project/build/build.js b/build/tests/lib/removeCombinedPaths/testcase/project/build/build.js new file mode 100644 index 00000000..58132762 --- /dev/null +++ b/build/tests/lib/removeCombinedPaths/testcase/project/build/build.js @@ -0,0 +1,16 @@ +({ + appDir: "../src", + baseUrl: ".", + dir: "./build_output", + paths: { + 'the_lib': '../../lib', + }, + modules: [ + { + name: "main" + } + ], + optimize: "none", + removeCombined: true +}) + diff --git a/build/tests/lib/removeCombinedPaths/testcase/project/src/main.js b/build/tests/lib/removeCombinedPaths/testcase/project/src/main.js new file mode 100644 index 00000000..372d2fa7 --- /dev/null +++ b/build/tests/lib/removeCombinedPaths/testcase/project/src/main.js @@ -0,0 +1,5 @@ +define(function(require, exports, module) { + var lib = require('the_lib/main'); + console.log("project main"); +}); + From f90941666a1ab0ff3ef1c572363f0f796e59c911 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 29 Aug 2013 20:19:49 -0700 Subject: [PATCH 037/382] snapshot --- dist/r.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index 663f9b57..5aa49209 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Tue, 13 Aug 2013 23:17:08 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 30 Aug 2013 03:19:39 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Tue, 13 Aug 2013 23:17:08 GMT', + version = '2.1.8+ Fri, 30 Aug 2013 03:19:39 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24279,9 +24279,16 @@ define('build', function (require) { //Be sure not to remove other build layers. if (config.removeCombined) { module.layer.buildFilePaths.forEach(function (path) { - if (file.exists(path) && !modules.some(function (mod) { + var isLayer = modules.some(function (mod) { return mod._buildPath === path; - })) { + }), + relPath = build.makeRelativeFilePath(config.dir, path); + + if (file.exists(path) && + // not a build layer target + !isLayer && + // not outside the build directory + relPath.indexOf('..') !== 0) { file.deleteFile(path); } }); From e3a73cbc5dc67c82ec664a5d066b977dba643e17 Mon Sep 17 00:00:00 2001 From: Magnus Dahlstrand Date: Mon, 9 Sep 2013 17:05:52 +0100 Subject: [PATCH 038/382] CSS optimization updated to remove unnecessary whitespace. --- build/example.build.js | 4 +++- build/jslib/build.js | 2 +- build/jslib/optimize.js | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/build/example.build.js b/build/example.build.js index 6e7659c8..971ee2de 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -185,7 +185,8 @@ }, //Allow CSS optimizations. Allowed values: - //- "standard": @import inlining, comment removal and line returns. + //- "standard": @import inlining and removal of comments, unnecessary + //whitespace and line returns. //Removing line returns may have problems in IE, depending on the type //of CSS. //- "standard.keepLines": like "standard" but keeps line returns. @@ -194,6 +195,7 @@ //returns. (r.js 1.0.8+) //- "standard.keepComments.keepLines": keeps the file comments and line //returns. (r.js 1.0.8+) + //- "standard.keepWhitespace": like "standard" but keeps unnecessary whitespace. optimizeCss: "standard.keepLines", //If optimizeCss is in use, a list of of files to ignore for the @import diff --git a/build/jslib/build.js b/build/jslib/build.js index ccad44e9..b2325a9b 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -61,7 +61,7 @@ define(function (require) { pragmas: {}, paths: {}, optimize: "uglify", - optimizeCss: "standard.keepLines", + optimizeCss: "standard.keepLines.keepWhitespace", inlineText: true, isBuild: true, optimizeAllPluginResources: false, diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index eff36ea8..f84e495a 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -315,6 +315,20 @@ function (lang, logger, envOptimize, file, parse, fileContents = fileContents.replace(/(\r\n)+/g, "\r\n"); fileContents = fileContents.replace(/(\n)+/g, "\n"); } + //Remove unnecessary whitespace + if (config.optimizeCss.indexOf(".keepWhitespace") === -1) { + //Remove leading and trailing whitespace from lines + fileContents = fileContents.replace(/^[ \t]+/gm, ""); + fileContents = fileContents.replace(/[ \t]+$/gm, ""); + //Remove whitespace after semicolon, colon, curly brackets and commas + fileContents = fileContents.replace(/(;|:|\{|}|,)[ \t]+/g, "$1"); + //Remove whitespace before opening curly brackets + fileContents = fileContents.replace(/[ \t]+(\{)/g, "$1"); + //Truncate double whitespace + fileContents = fileContents.replace(/([ \t])+/g, "$1"); + //Remove empty lines + fileContents = fileContents.replace(/^[ \t]*[\r\n]/gm,''); + } } catch (e) { fileContents = originalFileContents; logger.error("Could not optimized CSS file: " + fileName + ", error: " + e); From ec0e5ae2de70080804f19e5dd83e189f1ff93f66 Mon Sep 17 00:00:00 2001 From: Magnus Dahlstrand Date: Mon, 9 Sep 2013 17:41:27 +0100 Subject: [PATCH 039/382] Fix #518 by replacing removed line breaks with whitespace. --- build/jslib/optimize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index eff36ea8..594ed983 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -306,7 +306,7 @@ function (lang, logger, envOptimize, file, parse, } //Get rid of newlines. if (config.optimizeCss.indexOf(".keepLines") === -1) { - fileContents = fileContents.replace(/[\r\n]/g, ""); + fileContents = fileContents.replace(/[\r\n]/g, " "); fileContents = fileContents.replace(/\s+/g, " "); fileContents = fileContents.replace(/\{\s/g, "{"); fileContents = fileContents.replace(/\s\}/g, "}"); From c3941702c29d642fcf68395a776f2246e62bf335 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 19 Sep 2013 17:42:47 -0700 Subject: [PATCH 040/382] Fixes #536, removeCombined should not do anything when out is in play --- build/jslib/build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index ccad44e9..fcdae566 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -475,7 +475,7 @@ define(function (require) { //And finally, if removeCombined is specified, remove //any of the files that were used in this layer. //Be sure not to remove other build layers. - if (config.removeCombined) { + if (config.removeCombined && !config.out) { module.layer.buildFilePaths.forEach(function (path) { var isLayer = modules.some(function (mod) { return mod._buildPath === path; From 783b6e0ea25494205bf9694eab6827e826925a40 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 19 Sep 2013 17:42:59 -0700 Subject: [PATCH 041/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 5aa49209..906e81db 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 30 Aug 2013 03:19:39 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 20 Sep 2013 00:42:53 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 30 Aug 2013 03:19:39 GMT', + version = '2.1.8+ Fri, 20 Sep 2013 00:42:53 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24277,7 +24277,7 @@ define('build', function (require) { //And finally, if removeCombined is specified, remove //any of the files that were used in this layer. //Be sure not to remove other build layers. - if (config.removeCombined) { + if (config.removeCombined && !config.out) { module.layer.buildFilePaths.forEach(function (path) { var isLayer = modules.some(function (mod) { return mod._buildPath === path; From 721ee94e24e52223fe5874f0d84dd7550b91abf4 Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 20 Sep 2013 12:18:06 -0700 Subject: [PATCH 042/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 906e81db..42050b8f 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 20 Sep 2013 00:42:53 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 20 Sep 2013 19:17:59 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 20 Sep 2013 00:42:53 GMT', + version = '2.1.8+ Fri, 20 Sep 2013 19:17:59 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -23071,7 +23071,7 @@ function (lang, logger, envOptimize, file, parse, } //Get rid of newlines. if (config.optimizeCss.indexOf(".keepLines") === -1) { - fileContents = fileContents.replace(/[\r\n]/g, ""); + fileContents = fileContents.replace(/[\r\n]/g, " "); fileContents = fileContents.replace(/\s+/g, " "); fileContents = fileContents.replace(/\{\s/g, "{"); fileContents = fileContents.replace(/\s\}/g, "}"); From a052f093dd1e2c80d57986f3079ff70943f0fb3c Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 5 Oct 2013 17:00:21 -0700 Subject: [PATCH 043/382] requirejs snapshot update. Fixes #520 --- dist/r.js | 17 +++++++++-------- require.js | 13 +++++++------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/dist/r.js b/dist/r.js index 42050b8f..9c59c5ba 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 20 Sep 2013 19:17:59 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Sat, 05 Oct 2013 23:59:02 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 20 Sep 2013 19:17:59 GMT', + version = '2.1.8+ Sat, 05 Oct 2013 23:59:02 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.8 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.8+ 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 */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.8', + version = '2.1.8+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -261,7 +261,7 @@ var requirejs, require, define, xpcUtil; hasOwn = op.hasOwnProperty, ap = Array.prototype, apsp = ap.splice, - isBrowser = !!(typeof window !== 'undefined' && navigator && window.document), + isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), isWebWorker = !isBrowser && typeof importScripts !== 'undefined', //PS3 indicates loaded and complete, but need to wait for complete //specifically. Sequence is 'loading', 'loaded', execution, @@ -612,7 +612,6 @@ var requirejs, require, define, xpcUtil; function hasPathFallback(id) { var pathConfig = getOwn(config.paths, id); if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { - removeScript(id); //Pop off the first array value, since it failed, and //retry pathConfig.shift(); @@ -1703,6 +1702,8 @@ var requirejs, require, define, xpcUtil; var map = makeModuleMap(id, relMap, true), mod = getOwn(registry, id); + removeScript(id); + delete defined[id]; delete urlFetched[map.url]; delete undefEvents[id]; @@ -1848,7 +1849,7 @@ var requirejs, require, define, xpcUtil; //Join the path parts together, then figure out if baseUrl is needed. url = syms.join('/'); - url += (ext || (/\?/.test(url) || skipExt ? '' : '.js')); + url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js')); url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; } @@ -2157,7 +2158,7 @@ var requirejs, require, define, xpcUtil; } //Look for a data-main script attribute, which could also adjust the baseUrl. - if (isBrowser) { + if (isBrowser && !cfg.skipDataMain) { //Figure out baseUrl. Get it from the script tag with require.js in it. eachReverse(scripts(), function (script) { //Set the 'head' where we can append children by diff --git a/require.js b/require.js index 52c2b076..c7c3150e 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.8 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.8+ 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 */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.8', + version = '2.1.8+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -22,7 +22,7 @@ var requirejs, require, define; hasOwn = op.hasOwnProperty, ap = Array.prototype, apsp = ap.splice, - isBrowser = !!(typeof window !== 'undefined' && navigator && window.document), + isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document), isWebWorker = !isBrowser && typeof importScripts !== 'undefined', //PS3 indicates loaded and complete, but need to wait for complete //specifically. Sequence is 'loading', 'loaded', execution, @@ -373,7 +373,6 @@ var requirejs, require, define; function hasPathFallback(id) { var pathConfig = getOwn(config.paths, id); if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { - removeScript(id); //Pop off the first array value, since it failed, and //retry pathConfig.shift(); @@ -1464,6 +1463,8 @@ var requirejs, require, define; var map = makeModuleMap(id, relMap, true), mod = getOwn(registry, id); + removeScript(id); + delete defined[id]; delete urlFetched[map.url]; delete undefEvents[id]; @@ -1609,7 +1610,7 @@ var requirejs, require, define; //Join the path parts together, then figure out if baseUrl is needed. url = syms.join('/'); - url += (ext || (/\?/.test(url) || skipExt ? '' : '.js')); + url += (ext || (/^data\:|\?/.test(url) || skipExt ? '' : '.js')); url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; } @@ -1918,7 +1919,7 @@ var requirejs, require, define; } //Look for a data-main script attribute, which could also adjust the baseUrl. - if (isBrowser) { + if (isBrowser && !cfg.skipDataMain) { //Figure out baseUrl. Get it from the script tag with require.js in it. eachReverse(scripts(), function (script) { //Set the 'head' where we can append children by From 57bdc7ce7db04fcf9af87c1d4badcf347d27722d Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 5 Oct 2013 17:23:00 -0700 Subject: [PATCH 044/382] Fixes jrburke/requirejs#812, allow minified require.js to be namespaced --- .gitignore | 1 + build/jslib/pragma.js | 2 +- build/tests/builds.js | 15 +++ build/tests/lib/namespaceMinified/build.js | 9 ++ build/tests/lib/namespaceMinified/expected.js | 113 ++++++++++++++++++ build/tests/lib/namespaceMinified/index.html | 18 +++ build/tests/lib/namespaceMinified/main.js | 8 ++ .../lib/namespaceMinified/modules/five.js | 8 ++ .../lib/namespaceMinified/modules/four.js | 7 ++ .../lib/namespaceMinified/modules/one.js | 9 ++ .../lib/namespaceMinified/modules/six.js | 5 + .../lib/namespaceMinified/modules/three.js | 16 +++ .../lib/namespaceMinified/modules/two.js | 8 ++ build/tests/lib/namespaceMinified/reqlib.js | 36 ++++++ 14 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 build/tests/lib/namespaceMinified/build.js create mode 100644 build/tests/lib/namespaceMinified/expected.js create mode 100644 build/tests/lib/namespaceMinified/index.html create mode 100644 build/tests/lib/namespaceMinified/main.js create mode 100644 build/tests/lib/namespaceMinified/modules/five.js create mode 100644 build/tests/lib/namespaceMinified/modules/four.js create mode 100644 build/tests/lib/namespaceMinified/modules/one.js create mode 100644 build/tests/lib/namespaceMinified/modules/six.js create mode 100644 build/tests/lib/namespaceMinified/modules/three.js create mode 100644 build/tests/lib/namespaceMinified/modules/two.js create mode 100644 build/tests/lib/namespaceMinified/reqlib.js diff --git a/.gitignore b/.gitignore index 612b8118..2fe25c36 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ build/tests/lib/nameInsertion/built.js build/tests/lib/nameInsertion/nested/built.js build/tests/lib/namespace/foo.js build/tests/lib/namespaceConfig/foo.js +build/tests/lib/namespaceMinified/foo.js build/tests/lib/nested/main-built.js build/tests/lib/nested/main-builtWithCE.js build/tests/lib/nestedHas/main-built.js diff --git a/build/jslib/pragma.js b/build/jslib/pragma.js index 93d8b2a2..ec35044b 100644 --- a/build/jslib/pragma.js +++ b/build/jslib/pragma.js @@ -35,7 +35,7 @@ define(['parse', 'logger'], function (parse, logger) { hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g, configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g, nsWrapRegExp: /\/\*requirejs namespace: true \*\//, - apiDefRegExp: /var requirejs, require, define;/, + apiDefRegExp: /var requirejs,\s*require,\s*define;/, defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g, defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g, defineTypeFirstCheckRegExp: /\s*["']function["']\s*===\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, diff --git a/build/tests/builds.js b/build/tests/builds.js index 08c8fb5d..52fd2093 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -394,6 +394,21 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + doh.register("buildNamespaceMinified", + [ + function buildNamespaceMinified(t) { + build(["lib/namespaceMinified/build.js"]); + + t.is(nol(c("lib/namespaceMinified/expected.js")), + nol(c("lib/namespaceMinified/foo.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + doh.register("useDotPackage", [ function useDotPackage(t) { diff --git a/build/tests/lib/namespaceMinified/build.js b/build/tests/lib/namespaceMinified/build.js new file mode 100644 index 00000000..aa4fab7c --- /dev/null +++ b/build/tests/lib/namespaceMinified/build.js @@ -0,0 +1,9 @@ +({ + baseUrl: '.', + optimize: 'none', + namespace: 'foo', + name: 'main', + include: ['reqlib'], + out: 'foo.js' +}) + diff --git a/build/tests/lib/namespaceMinified/expected.js b/build/tests/lib/namespaceMinified/expected.js new file mode 100644 index 00000000..006e385c --- /dev/null +++ b/build/tests/lib/namespaceMinified/expected.js @@ -0,0 +1,113 @@ + +var foo;(function () { if (!foo || !foo.requirejs) { +if (!foo) { foo = {}; } else { require = foo; } +/* + RequireJS 2.1.8 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 +*/ +var requirejs,require,define; +(function(Z){function H(b){return"[object Function]"===L.call(b)}function I(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(H(m)){if(this.events.error&&this.map.isDefine||j.onError!==aa)try{e=i.execCb(c,m,b,e)}catch(d){a=d}else e=i.execCb(c,m,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!== +this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",v(this.error=a)}else e=m;this.exports=e;if(this.map.isDefine&&!this.ignore&&(r[c]=e,j.onResourceLoad))j.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete= +!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=n(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var m,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=n(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})), +d=l(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else m=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),m.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];F(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),m.fromText=u(this,function(e,c){var d=a.name,g=n(d),B=O;c&&(e=c);B&&(O=!1);q(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{j.exec(e)}catch(ca){return v(A("fromtexteval", +"fromText eval for "+b+" failed: "+ca,ca,[b]))}B&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],m)}),e.load(a.name,h,m,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){T[this.map.id]=this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=n(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=l(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b, +a);this.check()}));this.errback&&t(a,"error",u(this,this.errback))}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));F(this.pluginMaps,u(this,function(a){var b=l(p,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:r,urlFetched:S,defQueue:G,Module:X,makeModuleMap:n, +nextTick:j.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};F(a,function(a,b){e[b]?"map"===b?(k.map||(k.map={}),Q(k[b],a,!0,!0)):Q(k[b],a,!0):k[b]=a});a.shim&&(F(a.shim,function(a,b){I(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name, +location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);F(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=n(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(Z,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&H(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(H(c))return v(A("requireargs", +"Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(j.get)return j.get(i,e,a,d);g=n(e,a,!1,!0);g=g.id;return!s(r,g)?v(A("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[g]}K();i.nextTick(function(){K();k=q(n(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});C()});return d}f=f||{};Q(d,{isBrowser:z,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!W?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error", +b.onScriptError,!1)),h.src=d,K=h,C?x.insertBefore(h,C):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(l){b.onError(A("importscripts","importScripts failed for "+c+" at "+d,l,[c]))}};z&&M(document.getElementsByTagName("script"),function(b){x||(x=b.parentNode);if(J=b.getAttribute("data-main"))return q=J,t.baseUrl||(D=q.split("/"),q=D.pop(),fa=D.length?D.join("/")+"/":"./",t.baseUrl=fa),q=q.replace(ea,""),j.jsExtRegExp.test(q)&&(q=J),t.deps=t.deps?t.deps.concat(q):[q],!0}); +define=function(b,c,d){var h,j;"string"!==typeof b&&(d=c,c=b,b=null);I(c)||(d=c,c=null);!c&&H(d)&&(c=[],d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(O){if(!(h=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),h=P;h&&(b||(b=h.getAttribute("data-requiremodule")),j=E[h.getAttribute("data-requirecontext")])}(j?j.defQueue: +R).push([b,c,d])};define.amd={jQuery:!0};j.exec=function(b){return eval(b)};j(t)}})(this); + +foo.requirejs = requirejs;foo.require = require;foo.define = define; +} +}()); +foo.define("reqlib", function(){}); + +(function (define) { + foo.define( 'modules/one',[],function ( ){ + return { name: 'one' }; + }); + +}(typeof foo.define === 'function' && foo.define.amd ? foo.define : function () { + + +})); + +if (typeof foo.define === 'function' && foo.define.amd && foo.define.amd.jQuery) { + foo.define('modules/two',['require','exports','module'],function (require, exports, module) { + return { + name: 'two', + color: module.config().color + }; + }); +} +; +if(false){ + +}else if(typeof foo.define === 'function' && typeof foo.define.amd === 'object' && foo.define.amd){ + foo.define('modules/four',{ + name: 'four' + }); +}; +if (typeof foo.define === 'function' && foo.define['amd']) { + foo.define('modules/six',{ + name: 'six' + }); +} +; +if ('function' === typeof foo.define && foo.define.amd) { + foo.define('modules/five',['require','./six'],function (require) { + return { + name: 'five', + six: require('./six') + }; + }); +} +; +(function (define) { + foo.define('modules/three', ['require','./four','./five'],function (require) { + //If have dependencies, get them here + var four = require('./four'), + five = require('./five'); + + //Return the module definition. + return { + name: 'three', + fourName: four.name, + fiveName: five.name, + }; + }); +}(typeof foo.define === 'function' && foo.define.amd ? foo.define : function (id, factory) { + +})); + +foo.require(['modules/one', 'modules/two', 'modules/three'], function (one, two, three) { + console.log("One's name is: " + one.name); + console.log("Two's name is: " + two.name); + console.log("Two's color is: " + two.color); + console.log("Two's name is: " + three.name); + console.log("Three's fourName is: " + three.fourName); + console.log("Three's fiveName is: " + three.fiveName); +}); + +foo.define("main", function(){}); diff --git a/build/tests/lib/namespaceMinified/index.html b/build/tests/lib/namespaceMinified/index.html new file mode 100644 index 00000000..866d8938 --- /dev/null +++ b/build/tests/lib/namespaceMinified/index.html @@ -0,0 +1,18 @@ + + + + + + + +

Hello World

+ + diff --git a/build/tests/lib/namespaceMinified/main.js b/build/tests/lib/namespaceMinified/main.js new file mode 100644 index 00000000..ae0712c9 --- /dev/null +++ b/build/tests/lib/namespaceMinified/main.js @@ -0,0 +1,8 @@ +require(['modules/one', 'modules/two', 'modules/three'], function (one, two, three) { + console.log("One's name is: " + one.name); + console.log("Two's name is: " + two.name); + console.log("Two's color is: " + two.color); + console.log("Two's name is: " + three.name); + console.log("Three's fourName is: " + three.fourName); + console.log("Three's fiveName is: " + three.fiveName); +}); diff --git a/build/tests/lib/namespaceMinified/modules/five.js b/build/tests/lib/namespaceMinified/modules/five.js new file mode 100644 index 00000000..ed0b3196 --- /dev/null +++ b/build/tests/lib/namespaceMinified/modules/five.js @@ -0,0 +1,8 @@ +if ("function" === typeof define && define.amd) { + define(function (require) { + return { + name: 'five', + six: require('./six') + }; + }); +} diff --git a/build/tests/lib/namespaceMinified/modules/four.js b/build/tests/lib/namespaceMinified/modules/four.js new file mode 100644 index 00000000..42eac723 --- /dev/null +++ b/build/tests/lib/namespaceMinified/modules/four.js @@ -0,0 +1,7 @@ +if(false){ + +}else if(typeof define == "function" && typeof define.amd == "object" && define.amd){ + define({ + name: 'four' + }); +} \ No newline at end of file diff --git a/build/tests/lib/namespaceMinified/modules/one.js b/build/tests/lib/namespaceMinified/modules/one.js new file mode 100644 index 00000000..259201d1 --- /dev/null +++ b/build/tests/lib/namespaceMinified/modules/one.js @@ -0,0 +1,9 @@ +(function (define) { + define( function ( ){ + return { name: 'one' }; + }); + +}(typeof define === 'function' && define.amd ? define : function () { + + +})); diff --git a/build/tests/lib/namespaceMinified/modules/six.js b/build/tests/lib/namespaceMinified/modules/six.js new file mode 100644 index 00000000..27c86c87 --- /dev/null +++ b/build/tests/lib/namespaceMinified/modules/six.js @@ -0,0 +1,5 @@ +if (typeof define === 'function' && define['amd']) { + define({ + name: 'six' + }); +} diff --git a/build/tests/lib/namespaceMinified/modules/three.js b/build/tests/lib/namespaceMinified/modules/three.js new file mode 100644 index 00000000..733f42a6 --- /dev/null +++ b/build/tests/lib/namespaceMinified/modules/three.js @@ -0,0 +1,16 @@ +(function (define) { + define('modules/three', function (require) { + //If have dependencies, get them here + var four = require('./four'), + five = require('./five'); + + //Return the module definition. + return { + name: 'three', + fourName: four.name, + fiveName: five.name, + }; + }); +}(typeof define === 'function' && define.amd ? define : function (id, factory) { + +})); diff --git a/build/tests/lib/namespaceMinified/modules/two.js b/build/tests/lib/namespaceMinified/modules/two.js new file mode 100644 index 00000000..3377b5a7 --- /dev/null +++ b/build/tests/lib/namespaceMinified/modules/two.js @@ -0,0 +1,8 @@ +if (typeof define === 'function' && define.amd && define.amd.jQuery) { + define(function (require, exports, module) { + return { + name: 'two', + color: module.config().color + }; + }); +} diff --git a/build/tests/lib/namespaceMinified/reqlib.js b/build/tests/lib/namespaceMinified/reqlib.js new file mode 100644 index 00000000..7ff409d9 --- /dev/null +++ b/build/tests/lib/namespaceMinified/reqlib.js @@ -0,0 +1,36 @@ +/* + RequireJS 2.1.8 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 +*/ +var requirejs,require,define; +(function(Z){function H(b){return"[object Function]"===L.call(b)}function I(b){return"[object Array]"===L.call(b)}function y(b,c){if(b){var d;for(d=0;dthis.depCount&&!this.defined){if(H(m)){if(this.events.error&&this.map.isDefine||j.onError!==aa)try{e=i.execCb(c,m,b,e)}catch(d){a=d}else e=i.execCb(c,m,b,e);this.map.isDefine&&((b=this.module)&&void 0!==b.exports&&b.exports!== +this.exports?e=b.exports:void 0===e&&this.usingExports&&(e=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",v(this.error=a)}else e=m;this.exports=e;if(this.map.isDefine&&!this.ignore&&(r[c]=e,j.onResourceLoad))j.onResourceLoad(i,this.map,this.depMaps);x(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete= +!0)}}else this.fetch()}},callPlugin:function(){var a=this.map,b=a.id,d=n(a.prefix);this.depMaps.push(d);t(d,"defined",u(this,function(e){var m,d;d=this.map.name;var g=this.map.parentMap?this.map.parentMap.name:null,h=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(e.normalize&&(d=e.normalize(d,function(a){return c(a,g,!0)})||""),e=n(a.prefix+"!"+d,this.map.parentMap),t(e,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})), +d=l(p,e.id)){this.depMaps.push(e);if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else m=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),m.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];F(p,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&x(a.map.id)});v(a)}),m.fromText=u(this,function(e,c){var d=a.name,g=n(d),B=O;c&&(e=c);B&&(O=!1);q(g);s(k.config,b)&&(k.config[d]=k.config[b]);try{j.exec(e)}catch(ca){return v(A("fromtexteval", +"fromText eval for "+b+" failed: "+ca,ca,[b]))}B&&(O=!0);this.depMaps.push(g);i.completeLoad(d);h([d],m)}),e.load(a.name,h,m,k)}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){T[this.map.id]=this;this.enabling=this.enabled=!0;y(this.depMaps,u(this,function(a,b){var c,e;if("string"===typeof a){a=n(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=l(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;t(a,"defined",u(this,function(a){this.defineDep(b, +a);this.check()}));this.errback&&t(a,"error",u(this,this.errback))}c=a.id;e=p[c];!s(N,c)&&(e&&!e.enabled)&&i.enable(a,this)}));F(this.pluginMaps,u(this,function(a){var b=l(p,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){y(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:k,contextName:b,registry:p,defined:r,urlFetched:S,defQueue:G,Module:X,makeModuleMap:n, +nextTick:j.nextTick,onError:v,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=k.pkgs,c=k.shim,e={paths:!0,config:!0,map:!0};F(a,function(a,b){e[b]?"map"===b?(k.map||(k.map={}),Q(k[b],a,!0,!0)):Q(k[b],a,!0):k[b]=a});a.shim&&(F(a.shim,function(a,b){I(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);c[b]=a}),k.shim=c);a.packages&&(y(a.packages,function(a){a="string"===typeof a?{name:a}:a;b[a.name]={name:a.name, +location:a.location||a.name,main:(a.main||"main").replace(ja,"").replace(ea,"")}}),k.pkgs=b);F(p,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=n(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(Z,arguments));return b||a.exports&&ba(a.exports)}},makeRequire:function(a,f){function d(e,c,h){var g,k;f.enableBuildCallback&&(c&&H(c))&&(c.__requireJsBuild=!0);if("string"===typeof e){if(H(c))return v(A("requireargs", +"Invalid require call"),h);if(a&&s(N,e))return N[e](p[a.id]);if(j.get)return j.get(i,e,a,d);g=n(e,a,!1,!0);g=g.id;return!s(r,g)?v(A("notloaded",'Module name "'+g+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[g]}K();i.nextTick(function(){K();k=q(n(null,a));k.skipMap=f.skipMap;k.init(e,c,h,{enabled:!0});C()});return d}f=f||{};Q(d,{isBrowser:z,toUrl:function(b){var d,f=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==f&&(!("."===g||".."===g)||1h.attachEvent.toString().indexOf("[native code"))&&!W?(O=!0,h.attachEvent("onreadystatechange",b.onScriptLoad)):(h.addEventListener("load",b.onScriptLoad,!1),h.addEventListener("error", +b.onScriptError,!1)),h.src=d,K=h,C?x.insertBefore(h,C):x.appendChild(h),K=null,h;if(da)try{importScripts(d),b.completeLoad(c)}catch(l){b.onError(A("importscripts","importScripts failed for "+c+" at "+d,l,[c]))}};z&&M(document.getElementsByTagName("script"),function(b){x||(x=b.parentNode);if(J=b.getAttribute("data-main"))return q=J,t.baseUrl||(D=q.split("/"),q=D.pop(),fa=D.length?D.join("/")+"/":"./",t.baseUrl=fa),q=q.replace(ea,""),j.jsExtRegExp.test(q)&&(q=J),t.deps=t.deps?t.deps.concat(q):[q],!0}); +define=function(b,c,d){var h,j;"string"!==typeof b&&(d=c,c=b,b=null);I(c)||(d=c,c=null);!c&&H(d)&&(c=[],d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(O){if(!(h=K))P&&"interactive"===P.readyState||M(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),h=P;h&&(b||(b=h.getAttribute("data-requiremodule")),j=E[h.getAttribute("data-requirecontext")])}(j?j.defQueue: +R).push([b,c,d])};define.amd={jQuery:!0};j.exec=function(b){return eval(b)};j(t)}})(this); From 7d3345c3cb9e4187cf1941bd185e679a060822eb Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 5 Oct 2013 17:23:13 -0700 Subject: [PATCH 045/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 9c59c5ba..6ea6637a 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Sat, 05 Oct 2013 23:59:02 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Sun, 06 Oct 2013 00:23:06 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Sat, 05 Oct 2013 23:59:02 GMT', + version = '2.1.8+ Sun, 06 Oct 2013 00:23:06 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22350,7 +22350,7 @@ define('pragma', ['parse', 'logger'], function (parse, logger) { hasRegExp: /has\s*\(\s*['"]([^'"]+)['"]\s*\)/g, configRegExp: /(^|[^\.])(requirejs|require)(\.config)\s*\(/g, nsWrapRegExp: /\/\*requirejs namespace: true \*\//, - apiDefRegExp: /var requirejs, require, define;/, + apiDefRegExp: /var requirejs,\s*require,\s*define;/, defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g, defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g, defineTypeFirstCheckRegExp: /\s*["']function["']\s*===\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, From f6a98c1222d26e1413ea6eb2ae8e281ff995dfeb Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 6 Oct 2013 18:26:01 -0700 Subject: [PATCH 046/382] Fixes #813, make sure minified jquery gets namespace rewrite --- build/jslib/pragma.js | 2 +- build/tests/all.js | 1 + build/tests/pragma.js | 23 +++++++++++++++++++++++ build/tests/pragma/good1.js | 7 +++++++ build/tests/pragma/good1Expected.js | 7 +++++++ build/tests/pragma/good2.js | 1 + build/tests/pragma/good2Expected.js | 1 + 7 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 build/tests/pragma.js create mode 100644 build/tests/pragma/good1.js create mode 100644 build/tests/pragma/good1Expected.js create mode 100644 build/tests/pragma/good2.js create mode 100644 build/tests/pragma/good2Expected.js diff --git a/build/jslib/pragma.js b/build/jslib/pragma.js index ec35044b..8214e3b2 100644 --- a/build/jslib/pragma.js +++ b/build/jslib/pragma.js @@ -38,7 +38,7 @@ define(['parse', 'logger'], function (parse, logger) { apiDefRegExp: /var requirejs,\s*require,\s*define;/, defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g, defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g, - defineTypeFirstCheckRegExp: /\s*["']function["']\s*===\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, + defineTypeFirstCheckRegExp: /\s*["']function["']\s*==(=?)\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g, defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g, defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/, diff --git a/build/tests/all.js b/build/tests/all.js index 269626b6..32b8dece 100644 --- a/build/tests/all.js +++ b/build/tests/all.js @@ -34,6 +34,7 @@ require({ 'env!../../tests/doh/_{env}Runner.js', 'tests/convert', 'tests/parse', + 'tests/pragma', 'tests/transform', 'tests/buildUtils', diff --git a/build/tests/pragma.js b/build/tests/pragma.js new file mode 100644 index 00000000..1bd42b13 --- /dev/null +++ b/build/tests/pragma.js @@ -0,0 +1,23 @@ +/*global define, doh */ + +define(['pragma', 'env!env/file'], function (pragma, file) { + 'use strict'; + + function c(fileName) { + return file.readFile(fileName); + } + + //Remove line returns to make comparisons easier. + function nol(contents) { + return contents.replace(/[\r\n]/g, ""); + } + + doh.register("pragmaNamespace", + [ + function pragmaNamespace(t) { + t.is(c('pragma/good1Expected.js'), pragma.namespace(c('pragma/good1.js'), 'foo')); + t.is(c('pragma/good2Expected.js'), pragma.namespace(c('pragma/good2.js'), 'foo')); + } + ]); + doh.run(); +}); diff --git a/build/tests/pragma/good1.js b/build/tests/pragma/good1.js new file mode 100644 index 00000000..8fd58bac --- /dev/null +++ b/build/tests/pragma/good1.js @@ -0,0 +1,7 @@ +if ( typeof module === "object" && module && typeof module.exports === "object" ) { + module.exports = jQuery; +} else { + if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function () { return jQuery; } ); + } +} diff --git a/build/tests/pragma/good1Expected.js b/build/tests/pragma/good1Expected.js new file mode 100644 index 00000000..2c9e6f0a --- /dev/null +++ b/build/tests/pragma/good1Expected.js @@ -0,0 +1,7 @@ +if ( typeof module === "object" && module && typeof module.exports === "object" ) { + module.exports = jQuery; +} else { + if ( typeof foo.define === 'function' && foo.define.amd ) { + foo.define( "jquery", [], function () { return jQuery; } ); + } +} diff --git a/build/tests/pragma/good2.js b/build/tests/pragma/good2.js new file mode 100644 index 00000000..ce368e64 --- /dev/null +++ b/build/tests/pragma/good2.js @@ -0,0 +1 @@ +"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}) \ No newline at end of file diff --git a/build/tests/pragma/good2Expected.js b/build/tests/pragma/good2Expected.js new file mode 100644 index 00000000..4908fdf2 --- /dev/null +++ b/build/tests/pragma/good2Expected.js @@ -0,0 +1 @@ +"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:'function' === typeof foo.define && foo.define.amd&&foo.define("jquery",[],function(){return x}) \ No newline at end of file From a6776d8863ea6044e64c1dd36c3626ba931fa664 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 6 Oct 2013 18:26:18 -0700 Subject: [PATCH 047/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 6ea6637a..074e2773 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Sun, 06 Oct 2013 00:23:06 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Mon, 07 Oct 2013 01:26:09 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Sun, 06 Oct 2013 00:23:06 GMT', + version = '2.1.8+ Mon, 07 Oct 2013 01:26:09 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22353,7 +22353,7 @@ define('pragma', ['parse', 'logger'], function (parse, logger) { apiDefRegExp: /var requirejs,\s*require,\s*define;/, defineCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd/g, defineStringCheckRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\[\s*["']amd["']\s*\]/g, - defineTypeFirstCheckRegExp: /\s*["']function["']\s*===\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, + defineTypeFirstCheckRegExp: /\s*["']function["']\s*==(=?)\s*typeof\s+define\s*&&\s*define\s*\.\s*amd/g, defineJQueryRegExp: /typeof\s+define\s*===\s*["']function["']\s*&&\s*define\s*\.\s*amd\s*&&\s*define\s*\.\s*amd\s*\.\s*jQuery/g, defineHasRegExp: /typeof\s+define\s*==(=)?\s*['"]function['"]\s*&&\s*typeof\s+define\.amd\s*==(=)?\s*['"]object['"]\s*&&\s*define\.amd/g, defineTernaryRegExp: /typeof\s+define\s*===\s*['"]function["']\s*&&\s*define\s*\.\s*amd\s*\?\s*define/, From 02b6716b15a1e3540eb44e52231628ba2ce41074 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 6 Oct 2013 18:35:17 -0700 Subject: [PATCH 048/382] Fixes jrburke/requirejs#814, print FUNCTION with out is used for layer name output --- build/jslib/build.js | 3 ++- build/tests/tools/outFunc/expected.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index fcdae566..cf51d5e0 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1342,7 +1342,8 @@ define(function (require) { require(lang.deeplikeCopy(baseLoaderConfig)); } - logger.trace("\nTracing dependencies for: " + (module.name || module.out)); + logger.trace("\nTracing dependencies for: " + (module.name || + (typeof module.out === 'function' ? 'FUNCTION' : module.out))); include = module.name && !module.create ? [module.name] : []; if (module.include) { include = include.concat(module.include); diff --git a/build/tests/tools/outFunc/expected.js b/build/tests/tools/outFunc/expected.js index 0f674c8b..af5b6406 100644 --- a/build/tests/tools/outFunc/expected.js +++ b/build/tests/tools/outFunc/expected.js @@ -1 +1 @@ -define("a",{name:"a"}),define("main",["a"],function(e){return{name:"main",a:e}}) +define("a",{name:"a"}),define("main",["a"],function(e){return{name:"main",a:e}}); From ca6a9d99307886eb65f1970bd7a8d1dfe02c7f40 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 6 Oct 2013 18:35:40 -0700 Subject: [PATCH 049/382] snapshot --- dist/r.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 074e2773..91725731 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Mon, 07 Oct 2013 01:26:09 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Mon, 07 Oct 2013 01:35:32 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Mon, 07 Oct 2013 01:26:09 GMT', + version = '2.1.8+ Mon, 07 Oct 2013 01:35:32 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25145,7 +25145,8 @@ define('build', function (require) { require(lang.deeplikeCopy(baseLoaderConfig)); } - logger.trace("\nTracing dependencies for: " + (module.name || module.out)); + logger.trace("\nTracing dependencies for: " + (module.name || + (typeof module.out === 'function' ? 'FUNCTION' : module.out))); include = module.name && !module.create ? [module.name] : []; if (module.include) { include = include.concat(module.include); From 0b4f8d33c2d99fc62036fba609803cb064c44d57 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 7 Oct 2013 16:30:27 -0700 Subject: [PATCH 050/382] Fixes #834, give good error when two IDs map to same path and only one anon ID --- build/jslib/build.js | 61 +++++++++++++++++-------- build/tests/lib/paths/dupePath/a.js | 4 ++ build/tests/lib/paths/dupePath/build.js | 10 ++++ build/tests/lib/paths/dupePath/main.js | 5 ++ 4 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 build/tests/lib/paths/dupePath/a.js create mode 100644 build/tests/lib/paths/dupePath/build.js create mode 100644 build/tests/lib/paths/dupePath/main.js diff --git a/build/jslib/build.js b/build/jslib/build.js index cf51d5e0..5d8a92a8 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1399,6 +1399,13 @@ define(function (require) { //Figure out module layer dependencies by calling require to do the work. require(include, includeFinished, deferred.reject); + // If a sync env, then with the "two IDs to same anon module path" + // issue, the require never completes, need to check for errors + // here. + if (syncChecks[env.get()]) { + build.checkForErrors(context); + } + return deferred.promise.then(function () { //Reset config if (module.override && baseLoaderConfig) { @@ -1414,7 +1421,7 @@ define(function (require) { build.checkForErrors = function (context) { //Check to see if it all loaded. If not, then throw, and give //a message on what is left. - var id, prop, mod, errUrl, idParts, pluginId, + var id, prop, mod, idParts, pluginId, errMessage = '', failedPluginMap = {}, failedPluginIds = [], @@ -1422,28 +1429,37 @@ define(function (require) { errUrlMap = {}, errUrlConflicts = {}, hasErrUrl = false, + hasUndefined = false, + defined = context.defined, registry = context.registry; + function populateErrUrlMap(id, errUrl, skipNew) { + if (!skipNew) { + errIds.push(id); + } + + if (errUrlMap[errUrl]) { + hasErrUrl = true; + //This error module has the same URL as another + //error module, could be misconfiguration. + if (!errUrlConflicts[errUrl]) { + errUrlConflicts[errUrl] = []; + //Store the original module that had the same URL. + errUrlConflicts[errUrl].push(errUrlMap[errUrl]); + } + errUrlConflicts[errUrl].push(id); + } else if (!skipNew) { + errUrlMap[errUrl] = id; + } + } + for (id in registry) { if (hasProp(registry, id) && id.indexOf('_@r') !== 0) { + hasUndefined = true; mod = getOwn(registry, id); + if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) { - errIds.push(id); - errUrl = mod.map.url; - - if (errUrlMap[errUrl]) { - hasErrUrl = true; - //This error module has the same URL as another - //error module, could be misconfiguration. - if (!errUrlConflicts[errUrl]) { - errUrlConflicts[errUrl] = []; - //Store the original module that had the same URL. - errUrlConflicts[errUrl].push(errUrlMap[errUrl]); - } - errUrlConflicts[errUrl].push(id); - } else { - errUrlMap[errUrl] = id; - } + populateErrUrlMap(id, mod.map.url); } //Look for plugins that did not call load() @@ -1456,6 +1472,16 @@ define(function (require) { } } + // If have some modules that are not defined/stuck in the registry, + // then check defined modules for URL overlap. + if (hasUndefined) { + for (id in defined) { + if (hasProp(defined, id) && id.indexOf('!') === -1) { + populateErrUrlMap(id, require.toUrl(id) + '.js', true); + } + } + } + if (errIds.length || failedPluginIds.length) { if (failedPluginIds.length) { errMessage += 'Loader plugin' + @@ -1479,7 +1505,6 @@ define(function (require) { } throw new Error(errMessage); } - }; build.createOverrideConfig = function (config, override) { diff --git a/build/tests/lib/paths/dupePath/a.js b/build/tests/lib/paths/dupePath/a.js new file mode 100644 index 00000000..7dabf8af --- /dev/null +++ b/build/tests/lib/paths/dupePath/a.js @@ -0,0 +1,4 @@ +define({ + name: 'a' +}); + diff --git a/build/tests/lib/paths/dupePath/build.js b/build/tests/lib/paths/dupePath/build.js new file mode 100644 index 00000000..5ea4a722 --- /dev/null +++ b/build/tests/lib/paths/dupePath/build.js @@ -0,0 +1,10 @@ +({ + baseUrl: './', + optimize: 'none', + paths: { + 'aprime': 'a' + }, + name: 'main', + out: 'built.js' +}) + diff --git a/build/tests/lib/paths/dupePath/main.js b/build/tests/lib/paths/dupePath/main.js new file mode 100644 index 00000000..bd0577e7 --- /dev/null +++ b/build/tests/lib/paths/dupePath/main.js @@ -0,0 +1,5 @@ +require(['a', 'aprime'], function(a, aprime) { + console.log("a's name: " + a.name); + console.log("aprime's name: " + aprime.name); +}); + From a682c55ea950a30d1503b44f67147cb3f695a569 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 7 Oct 2013 16:30:39 -0700 Subject: [PATCH 051/382] snapshot --- dist/r.js | 77 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 53 insertions(+), 24 deletions(-) diff --git a/dist/r.js b/dist/r.js index 91725731..84995019 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Mon, 07 Oct 2013 01:35:32 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Mon, 07 Oct 2013 23:30:32 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Mon, 07 Oct 2013 01:35:32 GMT', + version = '2.1.8+ Mon, 07 Oct 2013 23:30:32 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22687,12 +22687,12 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { outBaseName, outFileNameMap, outFileNameMapContent, jscomp = Packages.com.google.javascript.jscomp, flags = Packages.com.google.common.flags, - //Fake extern - externSourceFile = closurefromCode("fakeextern.js", " "), //Set up source input jsSourceFile = closurefromCode(String(fileName), String(fileContents)), + sourceListArray = new java.util.ArrayList(), options, option, FLAG_compilation_level, compiler, - Compiler = Packages.com.google.javascript.jscomp.Compiler; + Compiler = Packages.com.google.javascript.jscomp.Compiler, + CommandLineRunner = Packages.com.google.javascript.jscomp.CommandLineRunner; logger.trace("Minifying file: " + fileName); @@ -22723,8 +22723,12 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { //Trigger the compiler Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']); compiler = new Compiler(); + + //fill the sourceArrrayList; we need the ArrayList because the only overload of compile + //accepting the getDefaultExterns return value (a List) also wants the sources as a List + sourceListArray.add(jsSourceFile); - result = compiler.compile(externSourceFile, jsSourceFile, options); + result = compiler.compile(CommandLineRunner.getDefaultExterns(), sourceListArray, options); if (result.success) { optimized = String(compiler.toSource()); @@ -25202,6 +25206,13 @@ define('build', function (require) { //Figure out module layer dependencies by calling require to do the work. require(include, includeFinished, deferred.reject); + // If a sync env, then with the "two IDs to same anon module path" + // issue, the require never completes, need to check for errors + // here. + if (syncChecks[env.get()]) { + build.checkForErrors(context); + } + return deferred.promise.then(function () { //Reset config if (module.override && baseLoaderConfig) { @@ -25217,7 +25228,7 @@ define('build', function (require) { build.checkForErrors = function (context) { //Check to see if it all loaded. If not, then throw, and give //a message on what is left. - var id, prop, mod, errUrl, idParts, pluginId, + var id, prop, mod, idParts, pluginId, errMessage = '', failedPluginMap = {}, failedPluginIds = [], @@ -25225,28 +25236,37 @@ define('build', function (require) { errUrlMap = {}, errUrlConflicts = {}, hasErrUrl = false, + hasUndefined = false, + defined = context.defined, registry = context.registry; + function populateErrUrlMap(id, errUrl, skipNew) { + if (!skipNew) { + errIds.push(id); + } + + if (errUrlMap[errUrl]) { + hasErrUrl = true; + //This error module has the same URL as another + //error module, could be misconfiguration. + if (!errUrlConflicts[errUrl]) { + errUrlConflicts[errUrl] = []; + //Store the original module that had the same URL. + errUrlConflicts[errUrl].push(errUrlMap[errUrl]); + } + errUrlConflicts[errUrl].push(id); + } else if (!skipNew) { + errUrlMap[errUrl] = id; + } + } + for (id in registry) { if (hasProp(registry, id) && id.indexOf('_@r') !== 0) { + hasUndefined = true; mod = getOwn(registry, id); + if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) { - errIds.push(id); - errUrl = mod.map.url; - - if (errUrlMap[errUrl]) { - hasErrUrl = true; - //This error module has the same URL as another - //error module, could be misconfiguration. - if (!errUrlConflicts[errUrl]) { - errUrlConflicts[errUrl] = []; - //Store the original module that had the same URL. - errUrlConflicts[errUrl].push(errUrlMap[errUrl]); - } - errUrlConflicts[errUrl].push(id); - } else { - errUrlMap[errUrl] = id; - } + populateErrUrlMap(id, mod.map.url); } //Look for plugins that did not call load() @@ -25259,6 +25279,16 @@ define('build', function (require) { } } + // If have some modules that are not defined/stuck in the registry, + // then check defined modules for URL overlap. + if (hasUndefined) { + for (id in defined) { + if (hasProp(defined, id) && id.indexOf('!') === -1) { + populateErrUrlMap(id, require.toUrl(id) + '.js', true); + } + } + } + if (errIds.length || failedPluginIds.length) { if (failedPluginIds.length) { errMessage += 'Loader plugin' + @@ -25282,7 +25312,6 @@ define('build', function (require) { } throw new Error(errMessage); } - }; build.createOverrideConfig = function (config, override) { From efc79edd754e290303b4a5add5110b88058fd813 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 7 Oct 2013 17:45:39 -0700 Subject: [PATCH 052/382] Fixes #476, parse.nodeToString handle single line configs correctly --- build/jslib/parse.js | 11 +++++++-- build/tests/transform.js | 24 +++++++++++++++++++ build/tests/transform/bothLineBreak.js | 3 +++ build/tests/transform/emptyObject.js | 1 + .../tests/transform/expected/bothLineBreak.js | 7 ++++++ build/tests/transform/expected/emptyObject.js | 5 ++++ .../transform/expected/startLineBreak.js | 6 +++++ build/tests/transform/startLineBreak.js | 2 ++ 8 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 build/tests/transform/bothLineBreak.js create mode 100644 build/tests/transform/emptyObject.js create mode 100644 build/tests/transform/expected/bothLineBreak.js create mode 100644 build/tests/transform/expected/emptyObject.js create mode 100644 build/tests/transform/expected/startLineBreak.js create mode 100644 build/tests/transform/startLineBreak.js diff --git a/build/jslib/parse.js b/build/jslib/parse.js index f4e95a72..3f941ec1 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -823,18 +823,25 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { * @returns {String} a JS source string. */ parse.nodeToString = function (contents, node) { - var loc = node.loc, + var extracted, + loc = node.loc, lines = contents.split('\n'), firstLine = loc.start.line > 1 ? lines.slice(0, loc.start.line - 1).join('\n') + '\n' : '', preamble = firstLine + - lines[loc.start.line - 1].substring(0, loc.start.column), + lines[loc.start.line - 1].substring(0, loc.start.column); + + if (loc.start.line === loc.end.line) { + extracted = lines[loc.start.line - 1].substring(loc.start.column, + loc.end.column); + } else { extracted = lines[loc.start.line - 1].substring(loc.start.column) + '\n' + lines.slice(loc.start.line, loc.end.line - 1).join('\n') + '\n' + lines[loc.end.line - 1].substring(0, loc.end.column); + } return { value: extracted, diff --git a/build/tests/transform.js b/build/tests/transform.js index 55ef3ad8..1564b163 100644 --- a/build/tests/transform.js +++ b/build/tests/transform.js @@ -35,6 +35,30 @@ define(['transform', 'env!env/file'], function (transform, file) { return config; }); + test(t, 'emptyObject.js', function (config) { + if (!config.paths) { + config.paths = {}; + } + config.paths.a = 'a'; + return config; + }); + + test(t, 'startLineBreak.js', function (config) { + if (!config.paths) { + config.paths = {}; + } + config.paths.a = 'a'; + return config; + }); + + test(t, 'bothLineBreak.js', function (config) { + if (!config.paths) { + config.paths = {}; + } + config.paths.a = 'a'; + return config; + }); + //Rhino's Function.toString strips comments and //does not maintain indentation, so need a different //comparison file to use for the results. xpconnect diff --git a/build/tests/transform/bothLineBreak.js b/build/tests/transform/bothLineBreak.js new file mode 100644 index 00000000..1662502a --- /dev/null +++ b/build/tests/transform/bothLineBreak.js @@ -0,0 +1,3 @@ +requirejs( +{} +); \ No newline at end of file diff --git a/build/tests/transform/emptyObject.js b/build/tests/transform/emptyObject.js new file mode 100644 index 00000000..ecba01b4 --- /dev/null +++ b/build/tests/transform/emptyObject.js @@ -0,0 +1 @@ +requirejs({}); \ No newline at end of file diff --git a/build/tests/transform/expected/bothLineBreak.js b/build/tests/transform/expected/bothLineBreak.js new file mode 100644 index 00000000..d1c4dce7 --- /dev/null +++ b/build/tests/transform/expected/bothLineBreak.js @@ -0,0 +1,7 @@ +requirejs( +{ + paths: { + a: "a" + } +} +); \ No newline at end of file diff --git a/build/tests/transform/expected/emptyObject.js b/build/tests/transform/expected/emptyObject.js new file mode 100644 index 00000000..71a8bf49 --- /dev/null +++ b/build/tests/transform/expected/emptyObject.js @@ -0,0 +1,5 @@ +requirejs({ + paths: { + a: "a" + } +}); \ No newline at end of file diff --git a/build/tests/transform/expected/startLineBreak.js b/build/tests/transform/expected/startLineBreak.js new file mode 100644 index 00000000..a70c2787 --- /dev/null +++ b/build/tests/transform/expected/startLineBreak.js @@ -0,0 +1,6 @@ +requirejs( +{ + paths: { + a: "a" + } +}); \ No newline at end of file diff --git a/build/tests/transform/startLineBreak.js b/build/tests/transform/startLineBreak.js new file mode 100644 index 00000000..0342cfcb --- /dev/null +++ b/build/tests/transform/startLineBreak.js @@ -0,0 +1,2 @@ +requirejs( +{}); \ No newline at end of file From d5f9485fb08f6eb98c6b89ec9a5dc90c6526e1d7 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 7 Oct 2013 17:45:50 -0700 Subject: [PATCH 053/382] snapshot --- dist/r.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index 84995019..df7b6d2e 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Mon, 07 Oct 2013 23:30:32 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Tue, 08 Oct 2013 00:45:43 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Mon, 07 Oct 2013 23:30:32 GMT', + version = '2.1.8+ Tue, 08 Oct 2013 00:45:43 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -21801,18 +21801,25 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { * @returns {String} a JS source string. */ parse.nodeToString = function (contents, node) { - var loc = node.loc, + var extracted, + loc = node.loc, lines = contents.split('\n'), firstLine = loc.start.line > 1 ? lines.slice(0, loc.start.line - 1).join('\n') + '\n' : '', preamble = firstLine + - lines[loc.start.line - 1].substring(0, loc.start.column), + lines[loc.start.line - 1].substring(0, loc.start.column); + + if (loc.start.line === loc.end.line) { + extracted = lines[loc.start.line - 1].substring(loc.start.column, + loc.end.column); + } else { extracted = lines[loc.start.line - 1].substring(loc.start.column) + '\n' + lines.slice(loc.start.line, loc.end.line - 1).join('\n') + '\n' + lines[loc.end.line - 1].substring(0, loc.end.column); + } return { value: extracted, From c71faf8c5c81abe0921d4213b014146d33442857 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 7 Oct 2013 21:18:18 -0700 Subject: [PATCH 054/382] Commit #535, retain original error info on new error thrown. --- build/jslib/build.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 5d8a92a8..6b4682bd 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -156,6 +156,8 @@ define(function (require) { return build._run(cmdConfig); }).then(null, function (e) { + var err; + errorMsg = e.toString(); errorTree = e.moduleTree; stackMatch = stackRegExp.exec(errorMsg); @@ -196,7 +198,9 @@ define(function (require) { } } - throw new Error(errorMsg); + err = new Error(errorMsg); + err.originalError = e; + throw err; }); }; From 06931fa6b81bc85c78b7a3920cb5cb08564a152f Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 6 Oct 2013 22:27:04 -0700 Subject: [PATCH 055/382] Fixes #545, updates of esprima and uglifyjs --- build/jslib/esprima.js | 36 +++--- build/jslib/source-map/array-set.js | 19 +-- build/jslib/source-map/binary-search.js | 2 +- build/jslib/source-map/source-map-consumer.js | 72 ++++++------ .../jslib/source-map/source-map-generator.js | 91 ++++++++------- build/jslib/source-map/source-node.js | 62 ++++++---- build/jslib/source-map/util.js | 90 ++++++++++++++- build/jslib/uglifyjs2.js | 108 ++++++++++++------ build/jslib/uglifyjs2/README.md | 2 +- build/jslib/uglifyjs2/post.txt | 23 ++-- build/jslib/x.js | 2 +- build/tests/lib/sourcemapSingle/main-built.js | 2 +- 12 files changed, 327 insertions(+), 182 deletions(-) diff --git a/build/jslib/esprima.js b/build/jslib/esprima.js index 34a07b5f..f1320daf 100644 --- a/build/jslib/esprima.js +++ b/build/jslib/esprima.js @@ -968,19 +968,19 @@ parseStatement: true, parseSourceElement: true */ while (index < length) { ch = source[index++]; str += ch; - if (classMarker) { + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch)) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (classMarker) { if (ch === ']') { classMarker = false; } } else { - if (ch === '\\') { - ch = source[index++]; - // ECMA-262 7.8.5 - if (isLineTerminator(ch)) { - throwError({}, Messages.UnterminatedRegExp); - } - str += ch; - } else if (ch === '/') { + if (ch === '/') { terminated = true; break; } else if (ch === '[') { @@ -1712,9 +1712,8 @@ parseStatement: true, parseSourceElement: true */ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { throwErrorTolerant({}, Messages.StrictLHSPostfix); } - if (!isLeftHandSide(expr)) { - throwError({}, Messages.InvalidLHSInAssignment); + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } expr = { @@ -1747,7 +1746,7 @@ parseStatement: true, parseSourceElement: true */ } if (!isLeftHandSide(expr)) { - throwError({}, Messages.InvalidLHSInAssignment); + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } expr = { @@ -1996,7 +1995,7 @@ parseStatement: true, parseSourceElement: true */ if (matchAssign()) { // LeftHandSideExpression if (!isLeftHandSide(expr)) { - throwError({}, Messages.InvalidLHSInAssignment); + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } // 11.13.1 @@ -2314,7 +2313,7 @@ parseStatement: true, parseSourceElement: true */ if (matchKeyword('in')) { // LeftHandSideExpression if (!isLeftHandSide(init)) { - throwError({}, Messages.InvalidLHSInForIn); + throwErrorTolerant({}, Messages.InvalidLHSInForIn); } lex(); @@ -2593,16 +2592,17 @@ parseStatement: true, parseSourceElement: true */ expect('{'); + cases = []; + if (match('}')) { lex(); return { type: Syntax.SwitchStatement, - discriminant: discriminant + discriminant: discriminant, + cases: cases }; } - cases = []; - oldInSwitch = state.inSwitch; state.inSwitch = true; defaultFound = false; @@ -3879,7 +3879,7 @@ parseStatement: true, parseSourceElement: true */ } // Sync with package.json. - exports.version = '1.0.3'; + exports.version = '1.0.4'; exports.parse = parse; diff --git a/build/jslib/source-map/array-set.js b/build/jslib/source-map/array-set.js index a0adcf0f..5055d254 100644 --- a/build/jslib/source-map/array-set.js +++ b/build/jslib/source-map/array-set.js @@ -23,10 +23,10 @@ define(function (require, exports, module) { /** * Static method for creating ArraySet instances from an existing array. */ - ArraySet.fromArray = function ArraySet_fromArray(aArray) { + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { var set = new ArraySet(); for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i]); + set.add(aArray[i], aAllowDuplicates); } return set; }; @@ -36,14 +36,15 @@ define(function (require, exports, module) { * * @param String aStr */ - ArraySet.prototype.add = function ArraySet_add(aStr) { - if (this.has(aStr)) { - // Already a member; nothing to do. - return; - } + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); var idx = this._array.length; - this._array.push(aStr); - this._set[util.toSetString(aStr)] = idx; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } }; /** diff --git a/build/jslib/source-map/binary-search.js b/build/jslib/source-map/binary-search.js index 32d90513..5c3cb02c 100644 --- a/build/jslib/source-map/binary-search.js +++ b/build/jslib/source-map/binary-search.js @@ -28,7 +28,7 @@ define(function (require, exports, module) { // 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]); + var cmp = aCompare(aNeedle, aHaystack[mid], true); if (cmp === 0) { // Found the element we are looking for. return aHaystack[mid]; diff --git a/build/jslib/source-map/source-map-consumer.js b/build/jslib/source-map/source-map-consumer.js index db8df1a2..a5bc2c49 100644 --- a/build/jslib/source-map/source-map-consumer.js +++ b/build/jslib/source-map/source-map-consumer.js @@ -54,14 +54,18 @@ define(function (require, exports, module) { 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'); + var file = util.getArg(sourceMap, 'file', null); if (version !== this._version) { throw new Error('Unsupported version: ' + version); } - this._names = ArraySet.fromArray(names); - this._sources = ArraySet.fromArray(sources); + // Pass `true` below to allow duplicate names and sources. While source maps + // are intended to be compressed and deduplicated, the TypeScript compiler + // sometimes generates source maps with duplicates in them. See Github issue + // #72 and bugzil.la/889492. + this._names = ArraySet.fromArray(names, true); + this._sources = ArraySet.fromArray(sources, true); this.sourceRoot = sourceRoot; this.sourcesContent = sourcesContent; this.file = file; @@ -94,6 +98,32 @@ define(function (require, exports, module) { this._parseMappings(mappings, sourceRoot); } + /** + * Create a SourceMapConsumer from a SourceMapGenerator. + * + * @param SourceMapGenerator aSourceMap + * The source map that will be consumed. + * @returns SourceMapConsumer + */ + SourceMapConsumer.fromSourceMap = + function SourceMapConsumer_fromSourceMap(aSourceMap) { + var smc = Object.create(SourceMapConsumer.prototype); + + smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); + smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); + smc.sourceRoot = aSourceMap._sourceRoot; + smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), + smc.sourceRoot); + smc.file = aSourceMap._file; + + smc._generatedMappings = aSourceMap._mappings.slice() + .sort(util.compareByGeneratedPositions); + smc._originalMappings = aSourceMap._mappings.slice() + .sort(util.compareByOriginalPositions); + + return smc; + }; + /** * The version of the source mapping spec that we are consuming. */ @@ -189,37 +219,7 @@ define(function (require, exports, module) { } } - this._originalMappings.sort(this._compareOriginalPositions); - }; - - /** - * Comparator between two mappings where the original positions are compared. - */ - SourceMapConsumer.prototype._compareOriginalPositions = - function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) { - if (mappingA.source > mappingB.source) { - return 1; - } - else if (mappingA.source < mappingB.source) { - return -1; - } - else { - var cmp = mappingA.originalLine - mappingB.originalLine; - return cmp === 0 - ? mappingA.originalColumn - mappingB.originalColumn - : cmp; - } - }; - - /** - * Comparator between two mappings where the generated positions are compared. - */ - SourceMapConsumer.prototype._compareGeneratedPositions = - function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - return cmp === 0 - ? mappingA.generatedColumn - mappingB.generatedColumn - : cmp; + this._originalMappings.sort(util.compareByOriginalPositions); }; /** @@ -272,7 +272,7 @@ define(function (require, exports, module) { this._generatedMappings, "generatedLine", "generatedColumn", - this._compareGeneratedPositions); + util.compareByGeneratedPositions); if (mapping) { var source = util.getArg(mapping, 'source', null); @@ -366,7 +366,7 @@ define(function (require, exports, module) { this._originalMappings, "originalLine", "originalColumn", - this._compareOriginalPositions); + util.compareByOriginalPositions); if (mapping) { return { diff --git a/build/jslib/source-map/source-map-generator.js b/build/jslib/source-map/source-map-generator.js index e85ca06e..e4147722 100644 --- a/build/jslib/source-map/source-map-generator.js +++ b/build/jslib/source-map/source-map-generator.js @@ -105,8 +105,10 @@ define(function (require, exports, module) { } this._mappings.push({ - generated: generated, - original: original, + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, source: source, name: name }); @@ -167,11 +169,11 @@ define(function (require, exports, module) { // Find mappings for the "aSourceFile" this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.original) { + if (mapping.source === aSourceFile && mapping.originalLine) { // 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 + line: mapping.originalLine, + column: mapping.originalColumn }); if (original.source !== null) { // Copy mapping @@ -180,8 +182,8 @@ define(function (require, exports, module) { } else { mapping.source = original.source; } - mapping.original.line = original.line; - mapping.original.column = original.column; + mapping.originalLine = original.line; + mapping.originalColumn = original.column; if (original.name !== null && mapping.name !== null) { // Only use the identifier name if it's an identifier // in both SourceMaps @@ -245,28 +247,15 @@ define(function (require, exports, module) { return; } else { - throw new Error('Invalid mapping.'); + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); } }; - function cmpLocation(loc1, loc2) { - var cmp = (loc1 && loc1.line) - (loc2 && loc2.line); - return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column); - } - - function strcmp(str1, str2) { - str1 = str1 || ''; - str2 = str2 || ''; - return (str1 > str2) - (str1 < str2); - } - - 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); - } - /** * Serialize the accumulated mappings in to the stream of base 64 VLQs * specified by the source map format. @@ -287,44 +276,44 @@ define(function (require, exports, module) { // 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); + this._mappings.sort(util.compareByGeneratedPositions); for (var i = 0, len = this._mappings.length; i < len; i++) { mapping = this._mappings[i]; - if (mapping.generated.line !== previousGeneratedLine) { + if (mapping.generatedLine !== previousGeneratedLine) { previousGeneratedColumn = 0; - while (mapping.generated.line !== previousGeneratedLine) { + while (mapping.generatedLine !== previousGeneratedLine) { result += ';'; previousGeneratedLine++; } } else { if (i > 0) { - if (!cmpMapping(mapping, this._mappings[i - 1])) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { continue; } result += ','; } } - result += base64VLQ.encode(mapping.generated.column + result += base64VLQ.encode(mapping.generatedColumn - previousGeneratedColumn); - previousGeneratedColumn = mapping.generated.column; + previousGeneratedColumn = mapping.generatedColumn; - if (mapping.source && mapping.original) { + if (mapping.source) { result += base64VLQ.encode(this._sources.indexOf(mapping.source) - previousSource); previousSource = this._sources.indexOf(mapping.source); // lines are stored 0-based in SourceMap spec version 3 - result += base64VLQ.encode(mapping.original.line - 1 + result += base64VLQ.encode(mapping.originalLine - 1 - previousOriginalLine); - previousOriginalLine = mapping.original.line - 1; + previousOriginalLine = mapping.originalLine - 1; - result += base64VLQ.encode(mapping.original.column + result += base64VLQ.encode(mapping.originalColumn - previousOriginalColumn); - previousOriginalColumn = mapping.original.column; + previousOriginalColumn = mapping.originalColumn; if (mapping.name) { result += base64VLQ.encode(this._names.indexOf(mapping.name) @@ -337,6 +326,23 @@ define(function (require, exports, module) { return result; }; + SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, + key) + ? this._sourcesContents[key] + : null; + }, this); + }; + /** * Externalize the source map. */ @@ -353,16 +359,9 @@ define(function (require, exports, module) { 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); + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); } + return map; }; diff --git a/build/jslib/source-map/source-node.js b/build/jslib/source-map/source-node.js index 6f20ed5f..7a418170 100644 --- a/build/jslib/source-map/source-node.js +++ b/build/jslib/source-map/source-node.js @@ -123,7 +123,7 @@ define(function (require, exports, module) { return node; function addMappingWithCode(mapping, code) { - if (mapping.source === undefined) { + if (mapping === null || mapping.source === undefined) { node.add(code); } else { node.add(new SourceNode(mapping.originalLine, @@ -191,7 +191,9 @@ define(function (require, exports, module) { * @param aFn The traversal function. */ SourceNode.prototype.walk = function SourceNode_walk(aFn) { - this.children.forEach(function (chunk) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; if (chunk instanceof SourceNode) { chunk.walk(aFn); } @@ -203,7 +205,7 @@ define(function (require, exports, module) { name: this.name }); } } - }, this); + } }; /** @@ -269,14 +271,16 @@ define(function (require, exports, module) { */ SourceNode.prototype.walkSourceContents = function SourceNode_walkSourceContents(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walkSourceContents(aFn); + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); } - }, this); - Object.keys(this.sourceContents).forEach(function (sourceFileKey) { - aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); - }, this); + } + + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); + } }; /** @@ -303,23 +307,36 @@ define(function (require, exports, module) { }; var map = new SourceMapGenerator(aArgs); var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; 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 - }); + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; sourceMappingActive = true; } else if (sourceMappingActive) { map.addMapping({ @@ -328,6 +345,7 @@ define(function (require, exports, module) { column: generated.column } }); + lastOriginalSource = null; sourceMappingActive = false; } chunk.split('').forEach(function (ch) { diff --git a/build/jslib/source-map/util.js b/build/jslib/source-map/util.js index 99d54ef1..683c16e9 100644 --- a/build/jslib/source-map/util.js +++ b/build/jslib/source-map/util.js @@ -29,6 +29,7 @@ define(function (require, exports, module) { exports.getArg = getArg; var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; function urlParse(aUrl) { var match = aUrl.match(urlRegexp); @@ -66,7 +67,7 @@ define(function (require, exports, module) { function join(aRoot, aPath) { var url; - if (aPath.match(urlRegexp)) { + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { return aPath; } @@ -112,4 +113,91 @@ define(function (require, exports, module) { } exports.relative = relative; + function strcmp(aStr1, aStr2) { + var s1 = aStr1 || ""; + var s2 = aStr2 || ""; + return (s1 > s2) - (s1 < s2); + } + + /** + * Comparator between two mappings where the original positions are compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. + */ + function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp; + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp || onlyCompareOriginal) { + return cmp; + } + + cmp = strcmp(mappingA.name, mappingB.name); + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + return mappingA.generatedColumn - mappingB.generatedColumn; + }; + exports.compareByOriginalPositions = compareByOriginalPositions; + + /** + * Comparator between two mappings where the generated positions are + * compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. + */ + function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) { + var cmp; + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp || onlyCompareGenerated) { + return cmp; + } + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp) { + return cmp; + } + + return strcmp(mappingA.name, mappingB.name); + }; + exports.compareByGeneratedPositions = compareByGeneratedPositions; + }); diff --git a/build/jslib/uglifyjs2.js b/build/jslib/uglifyjs2.js index 92bcc833..ce535068 100644 --- a/build/jslib/uglifyjs2.js +++ b/build/jslib/uglifyjs2.js @@ -1016,6 +1016,9 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M if (x instanceof type) return x; } }, + has_directive: function(type) { + return this.find_parent(AST_Scope).has_directive(type); + }, in_boolean_context: function() { var stack = this.stack; var i = stack.length, self = stack[--i]; @@ -1169,7 +1172,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M S.tokpos = S.pos; } function token(type, value, is_comment) { - S.regex_allowed = type == "operator" && !UNARY_POSTFIX[value] || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value); + S.regex_allowed = type == "operator" && !UNARY_POSTFIX(value) || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value); var ret = { type: type, value: value, @@ -1255,7 +1258,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M return "\f"; case 48: - return "\0"; + return "\x00"; case 120: return String.fromCharCode(hex_bytes(2)); @@ -2340,6 +2343,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M self.definitions = do_list(self.definitions, tw); }); _(AST_VarDef, function(self, tw) { + self.name = self.name.transform(tw); if (self.value) self.value = self.value.transform(tw); }); _(AST_Lambda, function(self, tw) { @@ -2791,14 +2795,13 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M inline_script: false, width: 80, max_line_len: 32e3, - ie_proof: true, beautify: false, source_map: null, bracketize: false, semicolons: true, comments: false, preserve_line: false, - negate_iife: !(options && options.beautify) + screw_ie8: false }, true); var indentation = 0; var current_col = 0; @@ -2850,8 +2853,8 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M ++sq; return "'"; - case "\0": - return "\\0"; + case "\x00": + return "\\x00"; } return s; }); @@ -3083,21 +3086,17 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M } AST_Node.DEFMETHOD("print", function(stream, force_parens) { var self = this, generator = self._codegen; - stream.push_node(self); - var needs_parens = self.needs_parens(stream); - var fc = self instanceof AST_Function && stream.option("negate_iife"); - if (force_parens || needs_parens && !fc) { - stream.with_parens(function() { - self.add_comments(stream); - self.add_source_map(stream); - generator(self, stream); - }); - } else { + function doit() { self.add_comments(stream); - if (needs_parens && fc) stream.print("!"); self.add_source_map(stream); generator(self, stream); } + stream.push_node(self); + if (force_parens || self.needs_parens(stream)) { + stream.with_parens(doit); + } else { + doit(); + } stream.pop_node(); }); AST_Node.DEFMETHOD("print_to_string", function(options) { @@ -3393,7 +3392,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M return; } if (!self.body) return output.force_semicolon(); - if (self.body instanceof AST_Do && output.option("ie_proof")) { + if (self.body instanceof AST_Do && !output.option("screw_ie8")) { make_block(self.body, output); return; } @@ -3612,6 +3611,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M a.forEach(function(exp, i) { if (i) output.comma(); exp.print(output); + if (i === len - 1 && exp instanceof AST_Hole) output.comma(); }); if (len > 0) output.space(); }); @@ -3635,10 +3635,10 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M output.print_string(key + ""); } else if ((typeof key == "number" || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) { output.print(make_num(key)); - } else if (!is_identifier(key)) { - output.print_string(key); - } else { + } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) { output.print_name(key); + } else { + output.print_string(key); } output.colon(); self.value.print(output); @@ -3800,6 +3800,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M join_vars: !false_by_default, cascade: !false_by_default, side_effects: !false_by_default, + negate_iife: !false_by_default, screw_ie8: false, warnings: true, global_defs: {} @@ -3925,6 +3926,9 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M statements = join_consecutive_vars(statements, compressor); } } while (CHANGED); + if (compressor.option("negate_iife")) { + negate_iifes(statements, compressor); + } return statements; function eliminate_spurious_blocks(statements) { var seen_dirs = []; @@ -4165,6 +4169,35 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M return a; }, []); } + function negate_iifes(statements, compressor) { + statements.forEach(function(stat) { + if (stat instanceof AST_SimpleStatement) { + stat.body = function transform(thing) { + return thing.transform(new TreeTransformer(function(node) { + if (node instanceof AST_Call && node.expression instanceof AST_Function) { + return make_node(AST_UnaryPrefix, node, { + operator: "!", + expression: node + }); + } else if (node instanceof AST_Call) { + node.expression = transform(node.expression); + } else if (node instanceof AST_Seq) { + node.car = transform(node.car); + } else if (node instanceof AST_Conditional) { + var expr = transform(node.condition); + if (expr !== node.condition) { + node.condition = expr; + var tmp = node.consequent; + node.consequent = node.alternative; + node.alternative = tmp; + } + } + return node; + })); + }(stat.body); + } + }); + } } function extract_declarations_from_unreachable_code(compressor, stat, target) { compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start); @@ -4260,7 +4293,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); }); def(AST_Function, function() { - return [ this ]; + throw def; }); function ev(node) { return node._eval(); @@ -4639,7 +4672,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M }); } var tt = new TreeTransformer(function before(node, descend, in_list) { - if (node instanceof AST_Lambda) { + if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { for (var a = node.argnames, i = a.length; --i >= 0; ) { var sym = a[i]; if (sym.unreferenced()) { @@ -5377,14 +5410,14 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M }); var commutativeOperators = makePredicate("== === != !== * & | ^"); OPT(AST_Binary, function(self, compressor) { - function reverse(op, force) { + var reverse = compressor.has_directive("use asm") ? noop : function(op, force) { if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) { if (op) self.operator = op; var tmp = self.left; self.left = self.right; self.right = tmp; } - } + }; if (commutativeOperators(self.operator)) { if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { reverse(null, true); @@ -5588,7 +5621,7 @@ define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, M var prop = self.property; if (prop instanceof AST_String && compressor.option("properties")) { prop = prop.getValue(); - if (compressor.option("screw_ie8") && RESERVED_WORDS(prop) || !RESERVED_WORDS(prop) && is_identifier_string(prop)) { + if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) { return make_node(AST_Dot, self, { expression: self.expression, property: prop @@ -6027,6 +6060,8 @@ exports.minify = function(files, options, name) { if (typeof files == "string") files = [ files ]; + UglifyJS.base54.reset(); + // 1. parse var toplevel = null; files.forEach(function(file){ @@ -6056,17 +6091,18 @@ exports.minify = function(files, options, name) { } // 4. output - var map = null; - var inMap = null; - if (options.inSourceMap) { + var inMap = options.inSourceMap; + var output = {}; + if (typeof options.inSourceMap == "string") { inMap = rjsFile.readFile(options.inSourceMap, "utf8"); } - if (options.outSourceMap) map = UglifyJS.SourceMap({ - file: options.outSourceMap, - orig: inMap, - root: options.sourceRoot - }); - var output = { source_map: map }; + if (options.outSourceMap) { + output.source_map = UglifyJS.SourceMap({ + file: options.outSourceMap, + orig: inMap, + root: options.sourceRoot + }); + } if (options.output) { UglifyJS.merge(output, options.output); } @@ -6074,7 +6110,7 @@ exports.minify = function(files, options, name) { toplevel.print(stream); return { code : stream + "", - map : map + "" + map : output.source_map + "" }; }; diff --git a/build/jslib/uglifyjs2/README.md b/build/jslib/uglifyjs2/README.md index 682435a1..28304353 100644 --- a/build/jslib/uglifyjs2/README.md +++ b/build/jslib/uglifyjs2/README.md @@ -1,6 +1,6 @@ Sets up uglifyjs2 for use in the optimizer. -Current embedded version: 2.3.6, source-map 0.1.25 +Current embedded version: 2.4.0, source-map 0.1.30 Steps: diff --git a/build/jslib/uglifyjs2/post.txt b/build/jslib/uglifyjs2/post.txt index d90163ec..fb5a277f 100644 --- a/build/jslib/uglifyjs2/post.txt +++ b/build/jslib/uglifyjs2/post.txt @@ -22,6 +22,8 @@ exports.minify = function(files, options, name) { if (typeof files == "string") files = [ files ]; + UglifyJS.base54.reset(); + // 1. parse var toplevel = null; files.forEach(function(file){ @@ -51,17 +53,18 @@ exports.minify = function(files, options, name) { } // 4. output - var map = null; - var inMap = null; - if (options.inSourceMap) { + var inMap = options.inSourceMap; + var output = {}; + if (typeof options.inSourceMap == "string") { inMap = rjsFile.readFile(options.inSourceMap, "utf8"); } - if (options.outSourceMap) map = UglifyJS.SourceMap({ - file: options.outSourceMap, - orig: inMap, - root: options.sourceRoot - }); - var output = { source_map: map }; + if (options.outSourceMap) { + output.source_map = UglifyJS.SourceMap({ + file: options.outSourceMap, + orig: inMap, + root: options.sourceRoot + }); + } if (options.output) { UglifyJS.merge(output, options.output); } @@ -69,7 +72,7 @@ exports.minify = function(files, options, name) { toplevel.print(stream); return { code : stream + "", - map : map + "" + map : output.source_map + "" }; }; diff --git a/build/jslib/x.js b/build/jslib/x.js index 2f61c550..7d32a492 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -409,7 +409,7 @@ var requirejs, require, define, xpcUtil; } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.3.6, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.4.0, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); diff --git a/build/tests/lib/sourcemapSingle/main-built.js b/build/tests/lib/sourcemapSingle/main-built.js index ae68aa30..735d9197 100644 --- a/build/tests/lib/sourcemapSingle/main-built.js +++ b/build/tests/lib/sourcemapSingle/main-built.js @@ -1,2 +1,2 @@ -define("a",{name:"a",doSomething:function(e){console.log("Hello "+e)}}),console.log("a is done"),define("b",[],function(){var e="b";return{name:e}}),require(["a","b"],function(e,t){console.log("a message below:"),e.doSomething("world"),console.log("b name: "+t.name)}),define("main",function(){}); +define("a",{name:"a",doSomething:function(e){console.log("Hello "+e)}}),console.log("a is done"),define("b",[],function(){var e="b";return{name:e}}),require(["a","b"],function(e,n){console.log("a message below:"),e.doSomething("world"),console.log("b name: "+n.name)}),define("main",function(){}); //# sourceMappingURL=main-built.js.map \ No newline at end of file From de4fffd90e78c83f24bc15109b7dd0a6a17a7b34 Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 9 Oct 2013 22:56:16 -0700 Subject: [PATCH 056/382] snapshot --- dist/r.js | 492 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 319 insertions(+), 173 deletions(-) diff --git a/dist/r.js b/dist/r.js index df7b6d2e..5d016c27 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Tue, 08 Oct 2013 00:45:43 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Thu, 10 Oct 2013 05:56:08 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Tue, 08 Oct 2013 00:45:43 GMT', + version = '2.1.8+ Thu, 10 Oct 2013 05:56:08 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -5426,19 +5426,19 @@ parseStatement: true, parseSourceElement: true */ while (index < length) { ch = source[index++]; str += ch; - if (classMarker) { + if (ch === '\\') { + ch = source[index++]; + // ECMA-262 7.8.5 + if (isLineTerminator(ch)) { + throwError({}, Messages.UnterminatedRegExp); + } + str += ch; + } else if (classMarker) { if (ch === ']') { classMarker = false; } } else { - if (ch === '\\') { - ch = source[index++]; - // ECMA-262 7.8.5 - if (isLineTerminator(ch)) { - throwError({}, Messages.UnterminatedRegExp); - } - str += ch; - } else if (ch === '/') { + if (ch === '/') { terminated = true; break; } else if (ch === '[') { @@ -6170,9 +6170,8 @@ parseStatement: true, parseSourceElement: true */ if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { throwErrorTolerant({}, Messages.StrictLHSPostfix); } - if (!isLeftHandSide(expr)) { - throwError({}, Messages.InvalidLHSInAssignment); + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } expr = { @@ -6205,7 +6204,7 @@ parseStatement: true, parseSourceElement: true */ } if (!isLeftHandSide(expr)) { - throwError({}, Messages.InvalidLHSInAssignment); + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } expr = { @@ -6454,7 +6453,7 @@ parseStatement: true, parseSourceElement: true */ if (matchAssign()) { // LeftHandSideExpression if (!isLeftHandSide(expr)) { - throwError({}, Messages.InvalidLHSInAssignment); + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } // 11.13.1 @@ -6772,7 +6771,7 @@ parseStatement: true, parseSourceElement: true */ if (matchKeyword('in')) { // LeftHandSideExpression if (!isLeftHandSide(init)) { - throwError({}, Messages.InvalidLHSInForIn); + throwErrorTolerant({}, Messages.InvalidLHSInForIn); } lex(); @@ -7051,16 +7050,17 @@ parseStatement: true, parseSourceElement: true */ expect('{'); + cases = []; + if (match('}')) { lex(); return { type: Syntax.SwitchStatement, - discriminant: discriminant + discriminant: discriminant, + cases: cases }; } - cases = []; - oldInSwitch = state.inSwitch; state.inSwitch = true; defaultFound = false; @@ -8337,7 +8337,7 @@ parseStatement: true, parseSourceElement: true */ } // Sync with package.json. - exports.version = '1.0.3'; + exports.version = '1.0.4'; exports.parse = parse; @@ -13219,10 +13219,10 @@ define('source-map/array-set', function (require, exports, module) { /** * Static method for creating ArraySet instances from an existing array. */ - ArraySet.fromArray = function ArraySet_fromArray(aArray) { + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { var set = new ArraySet(); for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i]); + set.add(aArray[i], aAllowDuplicates); } return set; }; @@ -13232,14 +13232,15 @@ define('source-map/array-set', function (require, exports, module) { * * @param String aStr */ - ArraySet.prototype.add = function ArraySet_add(aStr) { - if (this.has(aStr)) { - // Already a member; nothing to do. - return; - } + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); var idx = this._array.length; - this._array.push(aStr); - this._set[util.toSetString(aStr)] = idx; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } }; /** @@ -13500,7 +13501,7 @@ define('source-map/binary-search', function (require, exports, module) { // 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]); + var cmp = aCompare(aNeedle, aHaystack[mid], true); if (cmp === 0) { // Found the element we are looking for. return aHaystack[mid]; @@ -13605,14 +13606,18 @@ define('source-map/source-map-consumer', function (require, exports, module) { 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'); + var file = util.getArg(sourceMap, 'file', null); if (version !== this._version) { throw new Error('Unsupported version: ' + version); } - this._names = ArraySet.fromArray(names); - this._sources = ArraySet.fromArray(sources); + // Pass `true` below to allow duplicate names and sources. While source maps + // are intended to be compressed and deduplicated, the TypeScript compiler + // sometimes generates source maps with duplicates in them. See Github issue + // #72 and bugzil.la/889492. + this._names = ArraySet.fromArray(names, true); + this._sources = ArraySet.fromArray(sources, true); this.sourceRoot = sourceRoot; this.sourcesContent = sourcesContent; this.file = file; @@ -13645,6 +13650,32 @@ define('source-map/source-map-consumer', function (require, exports, module) { this._parseMappings(mappings, sourceRoot); } + /** + * Create a SourceMapConsumer from a SourceMapGenerator. + * + * @param SourceMapGenerator aSourceMap + * The source map that will be consumed. + * @returns SourceMapConsumer + */ + SourceMapConsumer.fromSourceMap = + function SourceMapConsumer_fromSourceMap(aSourceMap) { + var smc = Object.create(SourceMapConsumer.prototype); + + smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); + smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); + smc.sourceRoot = aSourceMap._sourceRoot; + smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), + smc.sourceRoot); + smc.file = aSourceMap._file; + + smc._generatedMappings = aSourceMap._mappings.slice() + .sort(util.compareByGeneratedPositions); + smc._originalMappings = aSourceMap._mappings.slice() + .sort(util.compareByOriginalPositions); + + return smc; + }; + /** * The version of the source mapping spec that we are consuming. */ @@ -13740,37 +13771,7 @@ define('source-map/source-map-consumer', function (require, exports, module) { } } - this._originalMappings.sort(this._compareOriginalPositions); - }; - - /** - * Comparator between two mappings where the original positions are compared. - */ - SourceMapConsumer.prototype._compareOriginalPositions = - function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) { - if (mappingA.source > mappingB.source) { - return 1; - } - else if (mappingA.source < mappingB.source) { - return -1; - } - else { - var cmp = mappingA.originalLine - mappingB.originalLine; - return cmp === 0 - ? mappingA.originalColumn - mappingB.originalColumn - : cmp; - } - }; - - /** - * Comparator between two mappings where the generated positions are compared. - */ - SourceMapConsumer.prototype._compareGeneratedPositions = - function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - return cmp === 0 - ? mappingA.generatedColumn - mappingB.generatedColumn - : cmp; + this._originalMappings.sort(util.compareByOriginalPositions); }; /** @@ -13823,7 +13824,7 @@ define('source-map/source-map-consumer', function (require, exports, module) { this._generatedMappings, "generatedLine", "generatedColumn", - this._compareGeneratedPositions); + util.compareByGeneratedPositions); if (mapping) { var source = util.getArg(mapping, 'source', null); @@ -13917,7 +13918,7 @@ define('source-map/source-map-consumer', function (require, exports, module) { this._originalMappings, "originalLine", "originalColumn", - this._compareOriginalPositions); + util.compareByOriginalPositions); if (mapping) { return { @@ -14095,8 +14096,10 @@ define('source-map/source-map-generator', function (require, exports, module) { } this._mappings.push({ - generated: generated, - original: original, + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, source: source, name: name }); @@ -14157,11 +14160,11 @@ define('source-map/source-map-generator', function (require, exports, module) { // Find mappings for the "aSourceFile" this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.original) { + if (mapping.source === aSourceFile && mapping.originalLine) { // 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 + line: mapping.originalLine, + column: mapping.originalColumn }); if (original.source !== null) { // Copy mapping @@ -14170,8 +14173,8 @@ define('source-map/source-map-generator', function (require, exports, module) { } else { mapping.source = original.source; } - mapping.original.line = original.line; - mapping.original.column = original.column; + mapping.originalLine = original.line; + mapping.originalColumn = original.column; if (original.name !== null && mapping.name !== null) { // Only use the identifier name if it's an identifier // in both SourceMaps @@ -14235,28 +14238,15 @@ define('source-map/source-map-generator', function (require, exports, module) { return; } else { - throw new Error('Invalid mapping.'); + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); } }; - function cmpLocation(loc1, loc2) { - var cmp = (loc1 && loc1.line) - (loc2 && loc2.line); - return cmp ? cmp : (loc1 && loc1.column) - (loc2 && loc2.column); - } - - function strcmp(str1, str2) { - str1 = str1 || ''; - str2 = str2 || ''; - return (str1 > str2) - (str1 < str2); - } - - 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); - } - /** * Serialize the accumulated mappings in to the stream of base 64 VLQs * specified by the source map format. @@ -14277,44 +14267,44 @@ define('source-map/source-map-generator', function (require, exports, module) { // 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); + this._mappings.sort(util.compareByGeneratedPositions); for (var i = 0, len = this._mappings.length; i < len; i++) { mapping = this._mappings[i]; - if (mapping.generated.line !== previousGeneratedLine) { + if (mapping.generatedLine !== previousGeneratedLine) { previousGeneratedColumn = 0; - while (mapping.generated.line !== previousGeneratedLine) { + while (mapping.generatedLine !== previousGeneratedLine) { result += ';'; previousGeneratedLine++; } } else { if (i > 0) { - if (!cmpMapping(mapping, this._mappings[i - 1])) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { continue; } result += ','; } } - result += base64VLQ.encode(mapping.generated.column + result += base64VLQ.encode(mapping.generatedColumn - previousGeneratedColumn); - previousGeneratedColumn = mapping.generated.column; + previousGeneratedColumn = mapping.generatedColumn; - if (mapping.source && mapping.original) { + if (mapping.source) { result += base64VLQ.encode(this._sources.indexOf(mapping.source) - previousSource); previousSource = this._sources.indexOf(mapping.source); // lines are stored 0-based in SourceMap spec version 3 - result += base64VLQ.encode(mapping.original.line - 1 + result += base64VLQ.encode(mapping.originalLine - 1 - previousOriginalLine); - previousOriginalLine = mapping.original.line - 1; + previousOriginalLine = mapping.originalLine - 1; - result += base64VLQ.encode(mapping.original.column + result += base64VLQ.encode(mapping.originalColumn - previousOriginalColumn); - previousOriginalColumn = mapping.original.column; + previousOriginalColumn = mapping.originalColumn; if (mapping.name) { result += base64VLQ.encode(this._names.indexOf(mapping.name) @@ -14327,6 +14317,23 @@ define('source-map/source-map-generator', function (require, exports, module) { return result; }; + SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, + key) + ? this._sourcesContents[key] + : null; + }, this); + }; + /** * Externalize the source map. */ @@ -14343,16 +14350,9 @@ define('source-map/source-map-generator', function (require, exports, module) { 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); + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); } + return map; }; @@ -14492,7 +14492,7 @@ define('source-map/source-node', function (require, exports, module) { return node; function addMappingWithCode(mapping, code) { - if (mapping.source === undefined) { + if (mapping === null || mapping.source === undefined) { node.add(code); } else { node.add(new SourceNode(mapping.originalLine, @@ -14560,7 +14560,9 @@ define('source-map/source-node', function (require, exports, module) { * @param aFn The traversal function. */ SourceNode.prototype.walk = function SourceNode_walk(aFn) { - this.children.forEach(function (chunk) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; if (chunk instanceof SourceNode) { chunk.walk(aFn); } @@ -14572,7 +14574,7 @@ define('source-map/source-node', function (require, exports, module) { name: this.name }); } } - }, this); + } }; /** @@ -14638,14 +14640,16 @@ define('source-map/source-node', function (require, exports, module) { */ SourceNode.prototype.walkSourceContents = function SourceNode_walkSourceContents(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walkSourceContents(aFn); + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); } - }, this); - Object.keys(this.sourceContents).forEach(function (sourceFileKey) { - aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); - }, this); + } + + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); + } }; /** @@ -14672,23 +14676,36 @@ define('source-map/source-node', function (require, exports, module) { }; var map = new SourceMapGenerator(aArgs); var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; 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 - }); + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; sourceMappingActive = true; } else if (sourceMappingActive) { map.addMapping({ @@ -14697,6 +14714,7 @@ define('source-map/source-node', function (require, exports, module) { column: generated.column } }); + lastOriginalSource = null; sourceMappingActive = false; } chunk.split('').forEach(function (ch) { @@ -14749,6 +14767,7 @@ define('source-map/util', function (require, exports, module) { exports.getArg = getArg; var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; function urlParse(aUrl) { var match = aUrl.match(urlRegexp); @@ -14786,7 +14805,7 @@ define('source-map/util', function (require, exports, module) { function join(aRoot, aPath) { var url; - if (aPath.match(urlRegexp)) { + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { return aPath; } @@ -14832,6 +14851,93 @@ define('source-map/util', function (require, exports, module) { } exports.relative = relative; + function strcmp(aStr1, aStr2) { + var s1 = aStr1 || ""; + var s2 = aStr2 || ""; + return (s1 > s2) - (s1 < s2); + } + + /** + * Comparator between two mappings where the original positions are compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. + */ + function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp; + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp || onlyCompareOriginal) { + return cmp; + } + + cmp = strcmp(mappingA.name, mappingB.name); + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + return mappingA.generatedColumn - mappingB.generatedColumn; + }; + exports.compareByOriginalPositions = compareByOriginalPositions; + + /** + * Comparator between two mappings where the generated positions are + * compared. + * + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. + */ + function compareByGeneratedPositions(mappingA, mappingB, onlyCompareGenerated) { + var cmp; + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp || onlyCompareGenerated) { + return cmp; + } + + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp) { + return cmp; + } + + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp) { + return cmp; + } + + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp) { + return cmp; + } + + return strcmp(mappingA.name, mappingB.name); + }; + exports.compareByGeneratedPositions = compareByGeneratedPositions; + }); define('source-map', function (require, exports, module) { @@ -15864,6 +15970,9 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio if (x instanceof type) return x; } }, + has_directive: function(type) { + return this.find_parent(AST_Scope).has_directive(type); + }, in_boolean_context: function() { var stack = this.stack; var i = stack.length, self = stack[--i]; @@ -16017,7 +16126,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio S.tokpos = S.pos; } function token(type, value, is_comment) { - S.regex_allowed = type == "operator" && !UNARY_POSTFIX[value] || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value); + S.regex_allowed = type == "operator" && !UNARY_POSTFIX(value) || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value); var ret = { type: type, value: value, @@ -16103,7 +16212,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio return "\f"; case 48: - return "\0"; + return "\x00"; case 120: return String.fromCharCode(hex_bytes(2)); @@ -17188,6 +17297,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio self.definitions = do_list(self.definitions, tw); }); _(AST_VarDef, function(self, tw) { + self.name = self.name.transform(tw); if (self.value) self.value = self.value.transform(tw); }); _(AST_Lambda, function(self, tw) { @@ -17639,14 +17749,13 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio inline_script: false, width: 80, max_line_len: 32e3, - ie_proof: true, beautify: false, source_map: null, bracketize: false, semicolons: true, comments: false, preserve_line: false, - negate_iife: !(options && options.beautify) + screw_ie8: false }, true); var indentation = 0; var current_col = 0; @@ -17698,8 +17807,8 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio ++sq; return "'"; - case "\0": - return "\\0"; + case "\x00": + return "\\x00"; } return s; }); @@ -17931,21 +18040,17 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio } AST_Node.DEFMETHOD("print", function(stream, force_parens) { var self = this, generator = self._codegen; - stream.push_node(self); - var needs_parens = self.needs_parens(stream); - var fc = self instanceof AST_Function && stream.option("negate_iife"); - if (force_parens || needs_parens && !fc) { - stream.with_parens(function() { - self.add_comments(stream); - self.add_source_map(stream); - generator(self, stream); - }); - } else { + function doit() { self.add_comments(stream); - if (needs_parens && fc) stream.print("!"); self.add_source_map(stream); generator(self, stream); } + stream.push_node(self); + if (force_parens || self.needs_parens(stream)) { + stream.with_parens(doit); + } else { + doit(); + } stream.pop_node(); }); AST_Node.DEFMETHOD("print_to_string", function(options) { @@ -18241,7 +18346,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio return; } if (!self.body) return output.force_semicolon(); - if (self.body instanceof AST_Do && output.option("ie_proof")) { + if (self.body instanceof AST_Do && !output.option("screw_ie8")) { make_block(self.body, output); return; } @@ -18460,6 +18565,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio a.forEach(function(exp, i) { if (i) output.comma(); exp.print(output); + if (i === len - 1 && exp instanceof AST_Hole) output.comma(); }); if (len > 0) output.space(); }); @@ -18483,10 +18589,10 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio output.print_string(key + ""); } else if ((typeof key == "number" || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) { output.print(make_num(key)); - } else if (!is_identifier(key)) { - output.print_string(key); - } else { + } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) { output.print_name(key); + } else { + output.print_string(key); } output.colon(); self.value.print(output); @@ -18648,6 +18754,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio join_vars: !false_by_default, cascade: !false_by_default, side_effects: !false_by_default, + negate_iife: !false_by_default, screw_ie8: false, warnings: true, global_defs: {} @@ -18773,6 +18880,9 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio statements = join_consecutive_vars(statements, compressor); } } while (CHANGED); + if (compressor.option("negate_iife")) { + negate_iifes(statements, compressor); + } return statements; function eliminate_spurious_blocks(statements) { var seen_dirs = []; @@ -19013,6 +19123,35 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio return a; }, []); } + function negate_iifes(statements, compressor) { + statements.forEach(function(stat) { + if (stat instanceof AST_SimpleStatement) { + stat.body = function transform(thing) { + return thing.transform(new TreeTransformer(function(node) { + if (node instanceof AST_Call && node.expression instanceof AST_Function) { + return make_node(AST_UnaryPrefix, node, { + operator: "!", + expression: node + }); + } else if (node instanceof AST_Call) { + node.expression = transform(node.expression); + } else if (node instanceof AST_Seq) { + node.car = transform(node.car); + } else if (node instanceof AST_Conditional) { + var expr = transform(node.condition); + if (expr !== node.condition) { + node.condition = expr; + var tmp = node.consequent; + node.consequent = node.alternative; + node.alternative = tmp; + } + } + return node; + })); + }(stat.body); + } + }); + } } function extract_declarations_from_unreachable_code(compressor, stat, target) { compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start); @@ -19108,7 +19247,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); }); def(AST_Function, function() { - return [ this ]; + throw def; }); function ev(node) { return node._eval(); @@ -19487,7 +19626,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio }); } var tt = new TreeTransformer(function before(node, descend, in_list) { - if (node instanceof AST_Lambda) { + if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { for (var a = node.argnames, i = a.length; --i >= 0; ) { var sym = a[i]; if (sym.unreferenced()) { @@ -20225,14 +20364,14 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio }); var commutativeOperators = makePredicate("== === != !== * & | ^"); OPT(AST_Binary, function(self, compressor) { - function reverse(op, force) { + var reverse = compressor.has_directive("use asm") ? noop : function(op, force) { if (force || !(self.left.has_side_effects() || self.right.has_side_effects())) { if (op) self.operator = op; var tmp = self.left; self.left = self.right; self.right = tmp; } - } + }; if (commutativeOperators(self.operator)) { if (self.right instanceof AST_Constant && !(self.left instanceof AST_Constant)) { reverse(null, true); @@ -20436,7 +20575,7 @@ define('uglifyjs2', ['exports', 'source-map', 'logger', 'env!env/file'], functio var prop = self.property; if (prop instanceof AST_String && compressor.option("properties")) { prop = prop.getValue(); - if (compressor.option("screw_ie8") && RESERVED_WORDS(prop) || !RESERVED_WORDS(prop) && is_identifier_string(prop)) { + if (RESERVED_WORDS(prop) ? compressor.option("screw_ie8") : is_identifier_string(prop)) { return make_node(AST_Dot, self, { expression: self.expression, property: prop @@ -20875,6 +21014,8 @@ exports.minify = function(files, options, name) { if (typeof files == "string") files = [ files ]; + UglifyJS.base54.reset(); + // 1. parse var toplevel = null; files.forEach(function(file){ @@ -20904,17 +21045,18 @@ exports.minify = function(files, options, name) { } // 4. output - var map = null; - var inMap = null; - if (options.inSourceMap) { + var inMap = options.inSourceMap; + var output = {}; + if (typeof options.inSourceMap == "string") { inMap = rjsFile.readFile(options.inSourceMap, "utf8"); } - if (options.outSourceMap) map = UglifyJS.SourceMap({ - file: options.outSourceMap, - orig: inMap, - root: options.sourceRoot - }); - var output = { source_map: map }; + if (options.outSourceMap) { + output.source_map = UglifyJS.SourceMap({ + file: options.outSourceMap, + orig: inMap, + root: options.sourceRoot + }); + } if (options.output) { UglifyJS.merge(output, options.output); } @@ -20922,7 +21064,7 @@ exports.minify = function(files, options, name) { toplevel.print(stream); return { code : stream + "", - map : map + "" + map : output.source_map + "" }; }; @@ -23970,6 +24112,8 @@ define('build', function (require) { return build._run(cmdConfig); }).then(null, function (e) { + var err; + errorMsg = e.toString(); errorTree = e.moduleTree; stackMatch = stackRegExp.exec(errorMsg); @@ -24010,7 +24154,9 @@ define('build', function (require) { } } - throw new Error(errorMsg); + err = new Error(errorMsg); + err.originalError = e; + throw err; }); }; @@ -25807,7 +25953,7 @@ function (args, quit, logger, build) { } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.3.6, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.4.0, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); From 55dcb30b8808301c1f28eda8999c83e73cdf5465 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 10 Oct 2013 11:20:04 -0700 Subject: [PATCH 057/382] Fixes #503, allow wrap config in module layer overrides --- .gitignore | 1 + build/jslib/build.js | 43 +++++++++++++-------- build/tests/builds.js | 24 ++++++++++++ build/tests/lib/override/wrap/a.js | 4 ++ build/tests/lib/override/wrap/b.js | 4 ++ build/tests/lib/override/wrap/build.js | 24 ++++++++++++ build/tests/lib/override/wrap/c.js | 4 ++ build/tests/lib/override/wrap/expected/a.js | 6 +++ build/tests/lib/override/wrap/expected/b.js | 6 +++ build/tests/lib/override/wrap/expected/c.js | 6 +++ 10 files changed, 105 insertions(+), 17 deletions(-) create mode 100644 build/tests/lib/override/wrap/a.js create mode 100644 build/tests/lib/override/wrap/b.js create mode 100644 build/tests/lib/override/wrap/build.js create mode 100644 build/tests/lib/override/wrap/c.js create mode 100644 build/tests/lib/override/wrap/expected/a.js create mode 100644 build/tests/lib/override/wrap/expected/b.js create mode 100644 build/tests/lib/override/wrap/expected/c.js diff --git a/.gitignore b/.gitignore index 2fe25c36..f137fbbc 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ build/tests/lib/nonStrict/main-built.js build/tests/lib/onBuildAllDir/js-built build/tests/lib/onBuildRead/main-built.js build/tests/lib/onBuildWrite/main-built.js +build/tests/lib/override/wrap/built build/tests/lib/packages/main-built.js build/tests/lib/pathsNoCopy/js-built build/tests/lib/pluginBuilder/main-built.js diff --git a/build/jslib/build.js b/build/jslib/build.js index 6b4682bd..e3888567 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -942,6 +942,26 @@ define(function (require) { } } + function normalizeWrapConfig(config, absFilePath) { + //Get any wrap text. + try { + if (config.wrap) { + if (config.wrap === true) { + //Use default values. + config.wrap = { + start: '(function () {', + end: '}());' + }; + } else { + flattenWrapFile(config.wrap, 'start', absFilePath); + flattenWrapFile(config.wrap, 'end', absFilePath); + } + } + } catch (wrapError) { + throw new Error('Malformed wrap config: ' + wrapError.toString()); + } + } + /** * Creates a config object for an optimization build. * It will also read the build profile if it is available, to create @@ -1219,27 +1239,16 @@ define(function (require) { mod.stubModules._byName[id] = true; }); } - }); - } - //Get any wrap text. - try { - if (config.wrap) { - if (config.wrap === true) { - //Use default values. - config.wrap = { - start: '(function () {', - end: '}());' - }; - } else { - flattenWrapFile(config.wrap, 'start', absFilePath); - flattenWrapFile(config.wrap, 'end', absFilePath); + //Allow wrap config in overrides, but normalize it. + if (mod.override) { + normalizeWrapConfig(mod.override, absFilePath); } - } - } catch (wrapError) { - throw new Error('Malformed wrap config: ' + wrapError.toString()); + }); } + normalizeWrapConfig(config, absFilePath); + //Do final input verification if (config.context) { throw new Error('The build argument "context" is not supported' + diff --git a/build/tests/builds.js b/build/tests/builds.js index 52fd2093..59272b83 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2032,6 +2032,30 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + //Allow wrap config in overrides + //https://github.com/jrburke/r.js/issues/503 + doh.register("overrideWrap", + [ + function overrideWrap(t) { + file.deleteFile("lib/override/wrap/built"); + + build(["lib/override/wrap/build.js"]); + + t.is(nol(c("lib/override/wrap/expected/a.js")), + nol(c("lib/override/wrap/built/a.js"))); + t.is(nol(c("lib/override/wrap/expected/b.js")), + nol(c("lib/override/wrap/built/b.js"))); + t.is(nol(c("lib/override/wrap/expected/c.js")), + nol(c("lib/override/wrap/built/c.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + + //Do not removeCombined files that are outside the build dir. //https://github.com/jrburke/requirejs/issues/755 doh.register("removeCombinedPaths", diff --git a/build/tests/lib/override/wrap/a.js b/build/tests/lib/override/wrap/a.js new file mode 100644 index 00000000..7dabf8af --- /dev/null +++ b/build/tests/lib/override/wrap/a.js @@ -0,0 +1,4 @@ +define({ + name: 'a' +}); + diff --git a/build/tests/lib/override/wrap/b.js b/build/tests/lib/override/wrap/b.js new file mode 100644 index 00000000..b8bdcebb --- /dev/null +++ b/build/tests/lib/override/wrap/b.js @@ -0,0 +1,4 @@ +define({ + name: 'b' +}); + diff --git a/build/tests/lib/override/wrap/build.js b/build/tests/lib/override/wrap/build.js new file mode 100644 index 00000000..8d10b37a --- /dev/null +++ b/build/tests/lib/override/wrap/build.js @@ -0,0 +1,24 @@ +({ + baseUrl: './', + optimize: 'none', + dir: 'built', + wrap: { + start: '//START', + end: '//END' + }, + modules: [ + { + name: 'a' + }, + { + name: 'b', + override: { + wrap: true + } + }, + { + name: 'c' + } + ] +}) + diff --git a/build/tests/lib/override/wrap/c.js b/build/tests/lib/override/wrap/c.js new file mode 100644 index 00000000..ae1edd0b --- /dev/null +++ b/build/tests/lib/override/wrap/c.js @@ -0,0 +1,4 @@ +define({ + name: 'c' +}); + diff --git a/build/tests/lib/override/wrap/expected/a.js b/build/tests/lib/override/wrap/expected/a.js new file mode 100644 index 00000000..9b7cf10f --- /dev/null +++ b/build/tests/lib/override/wrap/expected/a.js @@ -0,0 +1,6 @@ +//START +define('a',{ + name: 'a' +}); + +//END \ No newline at end of file diff --git a/build/tests/lib/override/wrap/expected/b.js b/build/tests/lib/override/wrap/expected/b.js new file mode 100644 index 00000000..d95488bc --- /dev/null +++ b/build/tests/lib/override/wrap/expected/b.js @@ -0,0 +1,6 @@ +(function () { +define('b',{ + name: 'b' +}); + +}()); \ No newline at end of file diff --git a/build/tests/lib/override/wrap/expected/c.js b/build/tests/lib/override/wrap/expected/c.js new file mode 100644 index 00000000..9b8223d2 --- /dev/null +++ b/build/tests/lib/override/wrap/expected/c.js @@ -0,0 +1,6 @@ +//START +define('c',{ + name: 'c' +}); + +//END \ No newline at end of file From 2f3fccb602d8a1e4efc821ce2cbaaacc44f07b93 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 10 Oct 2013 11:20:18 -0700 Subject: [PATCH 058/382] snapshot --- dist/r.js | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/dist/r.js b/dist/r.js index 5d016c27..612a4afe 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Thu, 10 Oct 2013 05:56:08 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Thu, 10 Oct 2013 18:20:12 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Thu, 10 Oct 2013 05:56:08 GMT', + version = '2.1.8+ Thu, 10 Oct 2013 18:20:12 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24898,6 +24898,26 @@ define('build', function (require) { } } + function normalizeWrapConfig(config, absFilePath) { + //Get any wrap text. + try { + if (config.wrap) { + if (config.wrap === true) { + //Use default values. + config.wrap = { + start: '(function () {', + end: '}());' + }; + } else { + flattenWrapFile(config.wrap, 'start', absFilePath); + flattenWrapFile(config.wrap, 'end', absFilePath); + } + } + } catch (wrapError) { + throw new Error('Malformed wrap config: ' + wrapError.toString()); + } + } + /** * Creates a config object for an optimization build. * It will also read the build profile if it is available, to create @@ -25175,27 +25195,16 @@ define('build', function (require) { mod.stubModules._byName[id] = true; }); } - }); - } - //Get any wrap text. - try { - if (config.wrap) { - if (config.wrap === true) { - //Use default values. - config.wrap = { - start: '(function () {', - end: '}());' - }; - } else { - flattenWrapFile(config.wrap, 'start', absFilePath); - flattenWrapFile(config.wrap, 'end', absFilePath); + //Allow wrap config in overrides, but normalize it. + if (mod.override) { + normalizeWrapConfig(mod.override, absFilePath); } - } - } catch (wrapError) { - throw new Error('Malformed wrap config: ' + wrapError.toString()); + }); } + normalizeWrapConfig(config, absFilePath); + //Do final input verification if (config.context) { throw new Error('The build argument "context" is not supported' + From 01b95a739e3873ee4331e9156649fbf08001cc81 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 10 Oct 2013 15:04:21 -0700 Subject: [PATCH 059/382] Fixes #477, use baseUrl instead of out for relative paths in source maps for onejs builds --- .gitignore | 2 + build/jslib/build.js | 13 +- build/tests/builds.js | 20 + build/tests/lib/sourcemap/onejs/build.js | 9 + build/tests/lib/sourcemap/onejs/expected.map | 1 + .../tests/lib/sourcemap/onejs/www/index.html | 9 + build/tests/lib/sourcemap/onejs/www/js/app.js | 13 + .../tests/lib/sourcemap/onejs/www/js/app/a.js | 10 + .../lib/sourcemap/onejs/www/js/app/main.js | 11 + .../lib/sourcemap/onejs/www/js/app/sample.txt | 2 + .../sourcemap/onejs/www/js/lib/text/text.js | 386 ++++ .../lib/sourcemap/onejs/www/js/require.js | 2019 +++++++++++++++++ 12 files changed, 2493 insertions(+), 2 deletions(-) create mode 100644 build/tests/lib/sourcemap/onejs/build.js create mode 100644 build/tests/lib/sourcemap/onejs/expected.map create mode 100644 build/tests/lib/sourcemap/onejs/www/index.html create mode 100644 build/tests/lib/sourcemap/onejs/www/js/app.js create mode 100644 build/tests/lib/sourcemap/onejs/www/js/app/a.js create mode 100644 build/tests/lib/sourcemap/onejs/www/js/app/main.js create mode 100644 build/tests/lib/sourcemap/onejs/www/js/app/sample.txt create mode 100644 build/tests/lib/sourcemap/onejs/www/js/lib/text/text.js create mode 100644 build/tests/lib/sourcemap/onejs/www/js/require.js diff --git a/.gitignore b/.gitignore index f137fbbc..a7788cc7 100644 --- a/.gitignore +++ b/.gitignore @@ -75,6 +75,8 @@ build/tests/lib/rhino-186/built build/tests/lib/semicolonInsert/a-built.js build/tests/lib/shimFakeDefine/main-built.js build/tests/lib/sourcemap/www-built +build/tests/lib/sourcemap/onejs/built.js +build/tests/lib/sourcemap/onejs/built.js.map build/tests/lib/stubModules/create/foobar-built.js build/tests/lib/stubModules/main-built.js build/tests/lib/stubModules/perModule/built diff --git a/build/jslib/build.js b/build/jslib/build.js index e3888567..6e6cd6a7 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1710,7 +1710,8 @@ define(function (require) { }); } }).then(function () { - var sourceMapPath, sourceMapLineNumber, + var refPath, + sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); module.onCompleteData.included.push(shortPath); @@ -1735,7 +1736,15 @@ define(function (require) { //Add to the source map if (sourceMapGenerator) { - sourceMapPath = build.makeRelativeFilePath(module._buildPath, path); + refPath = config.out ? config.baseUrl : module._buildPath; + if (path.indexOf('!') === -1) { + //Not a plugin resource, fix the path + sourceMapPath = build.makeRelativeFilePath(refPath, path); + } else { + //Plugin resource, best to not to make it relative. + sourceMapPath = path; + } + sourceMapLineNumber = fileContents.split('\n').length - 1; lineCount = singleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { diff --git a/build/tests/builds.js b/build/tests/builds.js index 59272b83..d716bc7b 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1971,6 +1971,26 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + //Make sure "onejs" builds generate source map files relative to baseUrl, + //and not the output file: + //https://github.com/jrburke/r.js/issues/477 + doh.register("sourcemapOneJs", + [ + function sourcemapOneJs(t) { + file.deleteFile("lib/sourcemap/onejs/built.js"); + file.deleteFile("lib/sourcemap/onejs/built.js.map"); + + build(["lib/sourcemap/onejs/build.js"]); + + t.is(nol(c("lib/sourcemap/onejs/expected.map")), + nol(c("lib/sourcemap/onejs/built.js.map"))); + + require._buildReset(); + } + ] + ); + doh.run(); + //Allow the target of an optimization to be a module that is only //provided in the rawText config. //Test single file JS optimization with source map generation diff --git a/build/tests/lib/sourcemap/onejs/build.js b/build/tests/lib/sourcemap/onejs/build.js new file mode 100644 index 00000000..d8e6296c --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/build.js @@ -0,0 +1,9 @@ +({ + baseUrl: 'www/js/lib', + mainConfigFile: 'www/js/app.js', + generateSourceMaps: true, + preserveLicenseComments: false, + optimize: 'uglify2', + name: 'app', + out: 'built.js' +}) diff --git a/build/tests/lib/sourcemap/onejs/expected.map b/build/tests/lib/sourcemap/onejs/expected.map new file mode 100644 index 00000000..ffc3d770 --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/expected.map @@ -0,0 +1 @@ +{"version":3,"file":"built.js","sources":["text/text.js","text!app/sample.txt","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAWA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["\n/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","\n/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\ndefine('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","\nrequire.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemap/onejs/www/index.html b/build/tests/lib/sourcemap/onejs/www/index.html new file mode 100644 index 00000000..5d9d55eb --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/index.html @@ -0,0 +1,9 @@ + + + + + + +

Hello World

+ + diff --git a/build/tests/lib/sourcemap/onejs/www/js/app.js b/build/tests/lib/sourcemap/onejs/www/js/app.js new file mode 100644 index 00000000..a78a97ac --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/js/app.js @@ -0,0 +1,13 @@ +require.config({ + baseUrl: 'js/lib', + paths: { + app: '../app', + text: 'text/text' + } +}); + +/** + * A test of source maps on a concatenated, but not minified file. + */ +require(['app/main']); + diff --git a/build/tests/lib/sourcemap/onejs/www/js/app/a.js b/build/tests/lib/sourcemap/onejs/www/js/app/a.js new file mode 100644 index 00000000..120753fa --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/js/app/a.js @@ -0,0 +1,10 @@ +/** + * Module A + */ +define({ + name: 'a', + doSomething: function (name) { + console.log('Hello ' + name); + } +}); +console.log('a is done'); diff --git a/build/tests/lib/sourcemap/onejs/www/js/app/main.js b/build/tests/lib/sourcemap/onejs/www/js/app/main.js new file mode 100644 index 00000000..fe6a2003 --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/js/app/main.js @@ -0,0 +1,11 @@ +define(function (require) { + var text = require('text!./sample.txt'), + a = require('./a'); + + return { + name: 'main', + a: a, + text: text + }; +}); + diff --git a/build/tests/lib/sourcemap/onejs/www/js/app/sample.txt b/build/tests/lib/sourcemap/onejs/www/js/app/sample.txt new file mode 100644 index 00000000..9d79b09e --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/js/app/sample.txt @@ -0,0 +1,2 @@ +sample + diff --git a/build/tests/lib/sourcemap/onejs/www/js/lib/text/text.js b/build/tests/lib/sourcemap/onejs/www/js/lib/text/text.js new file mode 100644 index 00000000..1e4fc966 --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/js/lib/text/text.js @@ -0,0 +1,386 @@ +/** + * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/text for details + */ +/*jslint regexp: true */ +/*global require, XMLHttpRequest, ActiveXObject, + define, window, process, Packages, + java, location, Components, FileUtils */ + +define(['module'], function (module) { + 'use strict'; + + var text, fs, Cc, Ci, xpcIsWindows, + progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], + xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, + bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, + hasLocation = typeof location !== 'undefined' && location.href, + defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), + defaultHostName = hasLocation && location.hostname, + defaultPort = hasLocation && (location.port || undefined), + buildMap = {}, + masterConfig = (module.config && module.config()) || {}; + + text = { + version: '2.0.10', + + strip: function (content) { + //Strips declarations so that external SVG and XML + //documents can be added to a document without worry. Also, if the string + //is an HTML document, only the part inside the body tag is returned. + if (content) { + content = content.replace(xmlRegExp, ""); + var matches = content.match(bodyRegExp); + if (matches) { + content = matches[1]; + } + } else { + content = ""; + } + return content; + }, + + jsEscape: function (content) { + return content.replace(/(['\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r") + .replace(/[\u2028]/g, "\\u2028") + .replace(/[\u2029]/g, "\\u2029"); + }, + + createXhr: masterConfig.createXhr || function () { + //Would love to dump the ActiveX crap in here. Need IE 6 to die first. + var xhr, i, progId; + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } else if (typeof ActiveXObject !== "undefined") { + for (i = 0; i < 3; i += 1) { + progId = progIds[i]; + try { + xhr = new ActiveXObject(progId); + } catch (e) {} + + if (xhr) { + progIds = [progId]; // so faster next time + break; + } + } + } + + return xhr; + }, + + /** + * Parses a resource name into its component parts. Resource names + * look like: module/name.ext!strip, where the !strip part is + * optional. + * @param {String} name the resource name + * @returns {Object} with properties "moduleName", "ext" and "strip" + * where strip is a boolean. + */ + parseName: function (name) { + var modName, ext, temp, + strip = false, + index = name.indexOf("."), + isRelative = name.indexOf('./') === 0 || + name.indexOf('../') === 0; + + if (index !== -1 && (!isRelative || index > 1)) { + modName = name.substring(0, index); + ext = name.substring(index + 1, name.length); + } else { + modName = name; + } + + temp = ext || modName; + index = temp.indexOf("!"); + if (index !== -1) { + //Pull off the strip arg. + strip = temp.substring(index + 1) === "strip"; + temp = temp.substring(0, index); + if (ext) { + ext = temp; + } else { + modName = temp; + } + } + + return { + moduleName: modName, + ext: ext, + strip: strip + }; + }, + + xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + + /** + * Is an URL on another domain. Only works for browser use, returns + * false in non-browser environments. Only used to know if an + * optimized .js version of a text resource should be loaded + * instead. + * @param {String} url + * @returns Boolean + */ + useXhr: function (url, protocol, hostname, port) { + var uProtocol, uHostName, uPort, + match = text.xdRegExp.exec(url); + if (!match) { + return true; + } + uProtocol = match[2]; + uHostName = match[3]; + + uHostName = uHostName.split(':'); + uPort = uHostName[1]; + uHostName = uHostName[0]; + + return (!uProtocol || uProtocol === protocol) && + (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && + ((!uPort && !uHostName) || uPort === port); + }, + + finishLoad: function (name, strip, content, onLoad) { + content = strip ? text.strip(content) : content; + if (masterConfig.isBuild) { + buildMap[name] = content; + } + onLoad(content); + }, + + load: function (name, req, onLoad, config) { + //Name has format: some.module.filext!strip + //The strip part is optional. + //if strip is present, then that means only get the string contents + //inside a body tag in an HTML string. For XML/SVG content it means + //removing the declarations so the content can be inserted + //into the current doc without problems. + + // Do not bother with the work if a build and text will + // not be inlined. + if (config.isBuild && !config.inlineText) { + onLoad(); + return; + } + + masterConfig.isBuild = config.isBuild; + + var parsed = text.parseName(name), + nonStripName = parsed.moduleName + + (parsed.ext ? '.' + parsed.ext : ''), + url = req.toUrl(nonStripName), + useXhr = (masterConfig.useXhr) || + text.useXhr; + + // Do not load if it is an empty: url + if (url.indexOf('empty:') === 0) { + onLoad(); + return; + } + + //Load the text. Use XHR if possible and in a browser. + if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { + text.get(url, function (content) { + text.finishLoad(name, parsed.strip, content, onLoad); + }, function (err) { + if (onLoad.error) { + onLoad.error(err); + } + }); + } else { + //Need to fetch the resource across domains. Assume + //the resource has been optimized into a JS module. Fetch + //by the module name + extension, but do not include the + //!strip part to avoid file system issues. + req([nonStripName], function (content) { + text.finishLoad(parsed.moduleName + '.' + parsed.ext, + parsed.strip, content, onLoad); + }); + } + }, + + write: function (pluginName, moduleName, write, config) { + if (buildMap.hasOwnProperty(moduleName)) { + var content = text.jsEscape(buildMap[moduleName]); + write.asModule(pluginName + "!" + moduleName, + "define(function () { return '" + + content + + "';});\n"); + } + }, + + writeFile: function (pluginName, moduleName, req, write, config) { + var parsed = text.parseName(moduleName), + extPart = parsed.ext ? '.' + parsed.ext : '', + nonStripName = parsed.moduleName + extPart, + //Use a '.js' file name so that it indicates it is a + //script that can be loaded across domains. + fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; + + //Leverage own load() method to load plugin value, but only + //write out values that do not have the strip argument, + //to avoid any potential issues with ! in file names. + text.load(nonStripName, req, function (value) { + //Use own write() method to construct full module value. + //But need to create shell that translates writeFile's + //write() to the right interface. + var textWrite = function (contents) { + return write(fileName, contents); + }; + textWrite.asModule = function (moduleName, contents) { + return write.asModule(moduleName, fileName, contents); + }; + + text.write(pluginName, nonStripName, textWrite, config); + }, config); + } + }; + + if (masterConfig.env === 'node' || (!masterConfig.env && + typeof process !== "undefined" && + process.versions && + !!process.versions.node && + !process.versions['node-webkit'])) { + //Using special require.nodeRequire, something added by r.js. + fs = require.nodeRequire('fs'); + + text.get = function (url, callback, errback) { + try { + var file = fs.readFileSync(url, 'utf8'); + //Remove BOM (Byte Mark Order) from utf8 files if it is there. + if (file.indexOf('\uFEFF') === 0) { + file = file.substring(1); + } + callback(file); + } catch (e) { + errback(e); + } + }; + } else if (masterConfig.env === 'xhr' || (!masterConfig.env && + text.createXhr())) { + text.get = function (url, callback, errback, headers) { + var xhr = text.createXhr(), header; + xhr.open('GET', url, true); + + //Allow plugins direct access to xhr headers + if (headers) { + for (header in headers) { + if (headers.hasOwnProperty(header)) { + xhr.setRequestHeader(header.toLowerCase(), headers[header]); + } + } + } + + //Allow overrides specified in config + if (masterConfig.onXhr) { + masterConfig.onXhr(xhr, url); + } + + xhr.onreadystatechange = function (evt) { + var status, err; + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + status = xhr.status; + if (status > 399 && status < 600) { + //An http 4xx or 5xx error. Signal an error. + err = new Error(url + ' HTTP status: ' + status); + err.xhr = xhr; + errback(err); + } else { + callback(xhr.responseText); + } + + if (masterConfig.onXhrComplete) { + masterConfig.onXhrComplete(xhr, url); + } + } + }; + xhr.send(null); + }; + } else if (masterConfig.env === 'rhino' || (!masterConfig.env && + typeof Packages !== 'undefined' && typeof java !== 'undefined')) { + //Why Java, why is this so awkward? + text.get = function (url, callback) { + var stringBuffer, line, + encoding = "utf-8", + file = new java.io.File(url), + lineSeparator = java.lang.System.getProperty("line.separator"), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), + content = ''; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + + if (line !== null) { + stringBuffer.append(line); + } + + while ((line = input.readLine()) !== null) { + stringBuffer.append(lineSeparator); + stringBuffer.append(line); + } + //Make sure we return a JavaScript string and not a Java string. + content = String(stringBuffer.toString()); //String + } finally { + input.close(); + } + callback(content); + }; + } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && + typeof Components !== 'undefined' && Components.classes && + Components.interfaces)) { + //Avert your gaze! + Cc = Components.classes, + Ci = Components.interfaces; + Components.utils['import']('resource://gre/modules/FileUtils.jsm'); + xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); + + text.get = function (url, callback) { + var inStream, convertStream, fileObj, + readData = {}; + + if (xpcIsWindows) { + url = url.replace(/\//g, '\\'); + } + + fileObj = new FileUtils.File(url); + + //XPCOM, you so crazy + try { + inStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + inStream.init(fileObj, 1, 0, false); + + convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] + .createInstance(Ci.nsIConverterInputStream); + convertStream.init(inStream, "utf-8", inStream.available(), + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + + convertStream.readString(inStream.available(), readData); + convertStream.close(); + inStream.close(); + callback(readData.value); + } catch (e) { + throw new Error((fileObj && fileObj.path || '') + ': ' + e); + } + }; + } + return text; +}); diff --git a/build/tests/lib/sourcemap/onejs/www/js/require.js b/build/tests/lib/sourcemap/onejs/www/js/require.js new file mode 100644 index 00000000..062516ac --- /dev/null +++ b/build/tests/lib/sourcemap/onejs/www/js/require.js @@ -0,0 +1,2019 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.1.5 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 + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, setTimeout, opera */ + +var requirejs, require, define; +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.1.5', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && navigator && document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + function getOwn(obj, prop) { + return hasProp(obj, prop) && obj[prop]; + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (hasProp(obj, prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + //Allow getting a global that expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + //Defaults. Do not set a default for map + //config to speed up normalize(), which + //will run faster if there is no default. + waitSeconds: 7, + baseUrl: './', + paths: {}, + pkgs: {}, + shim: {}, + config: {} + }, + registry = {}, + //registry of just enabled modules, to speed + //cycle breaking code when lots of modules + //are registered, but not activated. + enabledRegistry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + requireCounter = 1, + unnormalizedCounter = 1; + + /** + * 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; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //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) { + if (getOwn(config.pkgs, baseName)) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + normalizedBaseParts = baseParts = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + } + + name = normalizedBaseParts.concat(name.split('/')); + trimDots(name); + + //Some use of packages may use a . path to reference the + //'main' module name, so normalize for that. + pkgConfig = getOwn(config.pkgs, (pkgName = name[0])); + name = name.join('/'); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && map && (baseParts || starMap)) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = getOwn(map, baseParts.slice(0, j).join('/')); + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = getOwn(mapValue, nameSegment); + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) { + foundStarMap = getOwn(starMap, nameSegment); + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = getOwn(config.paths, id); + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + removeScript(id); + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.require.undef(id); + context.require([id]); + return true; + } + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, nameParts, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + nameParts = splitPrefix(name); + prefix = nameParts[0]; + name = nameParts[1]; + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = getOwn(defined, prefix); + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + + //Normalized name may be a plugin ID due to map config + //application in normalize. The map config values must + //already be normalized, so do not need to redo that part. + nameParts = splitPrefix(normalizedName); + prefix = nameParts[0]; + normalizedName = nameParts[1]; + isNormalized = true; + + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = getOwn(registry, id); + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + getModule(depMap).on(name, fn); + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = getOwn(registry, id); + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + handlers = { + 'require': function (mod) { + if (mod.require) { + return mod.require; + } else { + return (mod.require = context.makeRequire(mod.map)); + } + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + if (mod.exports) { + return mod.exports; + } else { + return (mod.exports = defined[mod.map.id] = {}); + } + } + }, + 'module': function (mod) { + if (mod.module) { + return mod.module; + } else { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return (config.config && getOwn(config.config, mod.map.id)) || {}; + }, + exports: defined[mod.map.id] + }); + } + } + }; + + function cleanRegistry(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + delete enabledRegistry[id]; + } + + function breakCycle(mod, traced, processed) { + var id = mod.map.id; + + if (mod.error) { + mod.emit('error', mod.error); + } else { + traced[id] = true; + each(mod.depMaps, function (depMap, i) { + var depId = depMap.id, + dep = getOwn(registry, depId); + + //Only force things that have not completed + //being defined, so still in the registry, + //and only if it has not been matched up + //in the module already. + if (dep && !mod.depMatched[i] && !processed[depId]) { + if (getOwn(traced, depId)) { + mod.defineDep(i, defined[depId]); + mod.check(); //pass false? + } else { + breakCycle(dep, traced, processed); + } + } + }); + processed[id] = true; + } + } + + function checkLoaded() { + var map, modId, err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + reqCalls = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(enabledRegistry, function (mod) { + map = mod.map; + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!map.isDefine) { + reqCalls.push(mod); + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + each(reqCalls, function (mod) { + breakCycle(mod, {}, {}); + }); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = getOwn(undefEvents, map.id) || {}; + this.map = map; + this.shim = getOwn(config.shim, map.id); + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + context.makeRequire(this.map, { + enableBuildCallback: true + })(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks if the module is ready to define itself, and if so, + * define it. + */ + check: function () { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. + if (this.events.error) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + if (this.map.isDefine) { + //If setting exports via 'module' is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + cjsModule = this.module; + if (cjsModule && + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { + exports = cjsModule.exports; + } else if (exports === undefined && this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = [this.map.id]; + err.requireType = 'define'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + cleanRegistry(id); + + this.defined = true; + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + //Map already normalized the prefix. + pluginMap = makeModuleMap(map.prefix); + + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(pluginMap); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null, + localRequire = context.makeRequire(map.parentMap, { + enableBuildCallback: true + }); + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + //prefix and name should already be normalized, no need + //for applying map config again either. + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + + normalizedMod = getOwn(registry, normalizedMap.id); + if (normalizedMod) { + //Mark this as a dependency for this plugin, so it + //can be traced for cycles. + this.depMaps.push(normalizedMap); + + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + cleanRegistry(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = bind(this, function (text, textAlt) { + /*jslint evil: true */ + var moduleName = map.name, + moduleMap = makeModuleMap(moduleName), + hasInteractive = useInteractive; + + //As of 2.1.0, support just passing the text, to reinforce + //fromText only being called once per resource. Still + //support old style of passing moduleName but discard + //that moduleName in favor of the internal ref. + if (textAlt) { + text = textAlt; + } + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(moduleMap); + + //Transfer any config to this other module. + if (hasProp(config.config, id)) { + config.config[moduleName] = config.config[id]; + } + + try { + req.exec(text); + } catch (e) { + return onError(makeError('fromtexteval', + 'fromText eval for ' + id + + ' failed: ' + e, + e, + [id])); + } + + if (hasInteractive) { + useInteractive = true; + } + + //Mark this as a dependency for the plugin + //resource + this.depMaps.push(moduleMap); + + //Support anonymous modules. + context.completeLoad(moduleName); + + //Bind the value of that module to the value for this + //resource ID. + localRequire([moduleName], load); + }); + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, localRequire, load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + enabledRegistry[this.map.id] = this; + this.enabled = true; + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.skipMap); + this.depMaps[i] = depMap; + + handler = getOwn(handlers, depMap.id); + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', this.errback); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!hasProp(handlers, id) && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = getOwn(registry, pluginMap.id); + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + //Skip modules already defined. + if (!hasProp(defined, args[0])) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + function intakeDefines() { + var args; + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + } + + context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + nextTick: req.nextTick, + onError: onError, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + var pkgs = config.pkgs, + shim = config.shim, + objs = { + paths: true, + config: true, + map: true + }; + + eachProp(cfg, function (value, prop) { + if (objs[prop]) { + if (prop === 'map') { + if (!config.map) { + config.map = {}; + } + mixin(config[prop], value, true, true); + } else { + mixin(config[prop], value, true); + } + } else { + config[prop] = value; + } + }); + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if ((value.exports || value.init) && !value.exportsFn) { + value.exportsFn = context.makeShimExports(value); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + }); + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (value) { + function fn() { + var ret; + if (value.init) { + ret = value.init.apply(global, arguments); + } + return ret || (value.exports && getGlobal(value.exports)); + } + return fn; + }, + + makeRequire: function (relMap, options) { + options = options || {}; + + function localRequire(deps, callback, errback) { + var id, map, requireMod; + + if (options.enableBuildCallback && callback && isFunction(callback)) { + callback.__requireJsBuild = true; + } + + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //If require|exports|module are requested, get the + //value for them from the special handlers. Caveat: + //this only works while module is being defined. + if (relMap && hasProp(handlers, deps)) { + return handlers[deps](registry[relMap.id]); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + if (req.get) { + return req.get(context, deps, relMap, localRequire); + } + + //Normalize module name, if it contains . or .. + map = makeModuleMap(deps, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName + + (relMap ? '' : '. Use require([])'))); + } + return defined[id]; + } + + //Grab defines waiting in the global queue. + intakeDefines(); + + //Mark all the dependencies as needing to be loaded. + context.nextTick(function () { + //Some defines could have been added since the + //require call, collect them. + intakeDefines(); + + requireMod = getModule(makeModuleMap(null, relMap)); + + //Store if map config should be applied to this require + //call for dependencies. + requireMod.skipMap = options.skipMap; + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + }); + + return localRequire; + } + + mixin(localRequire, { + isBrowser: isBrowser, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt) { + var ext, + index = moduleNamePlusExt.lastIndexOf('.'), + segment = moduleNamePlusExt.split('/')[0], + isRelative = segment === '.' || segment === '..'; + + //Have a file extension alias, and it is not the + //dots from a relative path. + if (index !== -1 && (!isRelative || index > 1)) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, + relMap && relMap.id, true), ext, true); + }, + + defined: function (id) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + specified: function (id) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + } + }); + + //Only allow undef on top level require calls + if (!relMap) { + localRequire.undef = function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, relMap, true), + mod = getOwn(registry, id); + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + cleanRegistry(id); + } + }; + } + + return localRequire; + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. A second arg, parent, the parent module, + * is passed in for context, when this method is overriden by + * the optimizer. Not shown here to keep code compact. + */ + enable: function (depMap) { + var mod = getOwn(registry, depMap.id); + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = getOwn(config.shim, moduleName) || {}, + shExports = shim.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = getOwn(registry, moduleName); + + if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exportsFn]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext, skipExt) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + parentPath; + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + pkg = getOwn(pkgs, parentModule); + parentPath = getOwn(paths, parentModule); + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } else if (pkg) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/\?/.test(url) || skipExt ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callack function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error', evt, [data.id])); + } + } + }; + + context.require = context.makeRequire(); + return context; + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = getOwn(contexts, contextName); + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Execute something after the current tick + * of the event loop. Override for other envs + * that have a better solution than setTimeout. + * @param {Function} fn function to execute later. + */ + req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) { + setTimeout(fn, 4); + } : function (fn) { fn(); }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require. + each([ + 'toUrl', + 'undef', + 'defined', + 'specified' + ], function (prop) { + //Reference from contexts instead of early binding to default context, + //so that during builds, the latest instance of the default context + //with its config gets used. + req[prop] = function () { + var ctx = contexts[defContextName]; + return ctx.require[prop].apply(ctx, arguments); + }; + }); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = function (err) { + throw err; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEventListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + try { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } catch (e) { + context.onError(makeError('importscripts', + 'importScripts failed for ' + + moduleName + ' at ' + url, + e, + [moduleName])); + } + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = dataMain.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + dataMain = mainScript; + } + + //Strip off any trailing .js since dataMain is now + //like a module name. + dataMain = dataMain.replace(jsSuffixRegExp, ''); + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous modules + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = []; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps.length && isFunction(callback)) { + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); From c20ca3cf7dbf714343acc2f2d0940ad643aa1efc Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 10 Oct 2013 15:04:30 -0700 Subject: [PATCH 060/382] snapshot --- dist/r.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index 612a4afe..2ac81734 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Thu, 10 Oct 2013 18:20:12 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Thu, 10 Oct 2013 22:04:24 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Thu, 10 Oct 2013 18:20:12 GMT', + version = '2.1.8+ Thu, 10 Oct 2013 22:04:24 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25666,7 +25666,8 @@ define('build', function (require) { }); } }).then(function () { - var sourceMapPath, sourceMapLineNumber, + var refPath, + sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); module.onCompleteData.included.push(shortPath); @@ -25691,7 +25692,15 @@ define('build', function (require) { //Add to the source map if (sourceMapGenerator) { - sourceMapPath = build.makeRelativeFilePath(module._buildPath, path); + refPath = config.out ? config.baseUrl : module._buildPath; + if (path.indexOf('!') === -1) { + //Not a plugin resource, fix the path + sourceMapPath = build.makeRelativeFilePath(refPath, path); + } else { + //Plugin resource, best to not to make it relative. + sourceMapPath = path; + } + sourceMapLineNumber = fileContents.split('\n').length - 1; lineCount = singleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { From fef6a7ed584d83b4c572439347336a7f49705494 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 10 Oct 2013 23:05:16 -0700 Subject: [PATCH 061/382] Fixes #478, put plugin ID at end of resource name for plugin resource IDs that look like plain module IDs --- build/jslib/build.js | 22 +++++++++++++++----- build/tests/lib/sourcemap/onejs/expected.map | 2 +- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 6e6cd6a7..b9531dc5 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -27,7 +27,8 @@ define(function (require) { hasProp = lang.hasProp, getOwn = lang.getOwn, falseProp = lang.falseProp, - endsWithSemiColonRegExp = /;\s*$/; + endsWithSemiColonRegExp = /;\s*$/, + resourceIsModuleIdRegExp = /^[\w\/\\\.]+$/; prim.nextTick = function (fn) { fn(); @@ -1710,7 +1711,7 @@ define(function (require) { }); } }).then(function () { - var refPath, + var refPath, pluginId, resourcePath, sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); @@ -1737,12 +1738,23 @@ define(function (require) { //Add to the source map if (sourceMapGenerator) { refPath = config.out ? config.baseUrl : module._buildPath; - if (path.indexOf('!') === -1) { + parts = path.split('!'); + if (parts.length === 1) { //Not a plugin resource, fix the path sourceMapPath = build.makeRelativeFilePath(refPath, path); } else { - //Plugin resource, best to not to make it relative. - sourceMapPath = path; + //Plugin resource. If it looks like just a plugin + //followed by a module ID, pull off the plugin + //and put it at the end of the name, otherwise + //just leave it alone. + pluginId = parts.shift(); + resourcePath = parts.join('!'); + if (resourceIsModuleIdRegExp.test(resourcePath)) { + sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) + + '!' + pluginId; + } else { + sourceMapPath = path; + } } sourceMapLineNumber = fileContents.split('\n').length - 1; diff --git a/build/tests/lib/sourcemap/onejs/expected.map b/build/tests/lib/sourcemap/onejs/expected.map index ffc3d770..4a67b0d6 100644 --- a/build/tests/lib/sourcemap/onejs/expected.map +++ b/build/tests/lib/sourcemap/onejs/expected.map @@ -1 +1 @@ -{"version":3,"file":"built.js","sources":["text/text.js","text!app/sample.txt","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAWA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["\n/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","\n/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\ndefine('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","\nrequire.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAWA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["\n/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","\n/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\ndefine('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","\nrequire.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file From dbb89ed99f51a5070663c1e7022915d9a6ad26d2 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 10 Oct 2013 23:05:28 -0700 Subject: [PATCH 062/382] snapshot --- dist/r.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/dist/r.js b/dist/r.js index 2ac81734..27571708 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Thu, 10 Oct 2013 22:04:24 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 11 Oct 2013 06:05:19 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Thu, 10 Oct 2013 22:04:24 GMT', + version = '2.1.8+ Fri, 11 Oct 2013 06:05:19 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -23983,7 +23983,8 @@ define('build', function (require) { hasProp = lang.hasProp, getOwn = lang.getOwn, falseProp = lang.falseProp, - endsWithSemiColonRegExp = /;\s*$/; + endsWithSemiColonRegExp = /;\s*$/, + resourceIsModuleIdRegExp = /^[\w\/\\\.]+$/; prim.nextTick = function (fn) { fn(); @@ -25666,7 +25667,7 @@ define('build', function (require) { }); } }).then(function () { - var refPath, + var refPath, pluginId, resourcePath, sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); @@ -25693,12 +25694,23 @@ define('build', function (require) { //Add to the source map if (sourceMapGenerator) { refPath = config.out ? config.baseUrl : module._buildPath; - if (path.indexOf('!') === -1) { + parts = path.split('!'); + if (parts.length === 1) { //Not a plugin resource, fix the path sourceMapPath = build.makeRelativeFilePath(refPath, path); } else { - //Plugin resource, best to not to make it relative. - sourceMapPath = path; + //Plugin resource. If it looks like just a plugin + //followed by a module ID, pull off the plugin + //and put it at the end of the name, otherwise + //just leave it alone. + pluginId = parts.shift(); + resourcePath = parts.join('!'); + if (resourceIsModuleIdRegExp.test(resourcePath)) { + sourceMapPath = build.makeRelativeFilePath(refPath, require.toUrl(resourcePath)) + + '!' + pluginId; + } else { + sourceMapPath = path; + } } sourceMapLineNumber = fileContents.split('\n').length - 1; From bb2cbf90fb98f8e5752db2e559ff320ead929478 Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 11 Oct 2013 11:37:34 -0700 Subject: [PATCH 063/382] Fixes #523, source maps off by a line --- build/jslib/build.js | 13 ++++++++++--- build/tests/lib/sourcemap/expected-main.js.map | 2 +- build/tests/lib/sourcemap/onejs/expected.map | 2 +- .../lib/sourcemapSingle/expected-main-built.js.map | 2 +- build/tests/lib/sourcemapSingle/main-built.js.map | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index b9531dc5..7a365ef9 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1711,7 +1711,7 @@ define(function (require) { }); } }).then(function () { - var refPath, pluginId, resourcePath, + var refPath, pluginId, resourcePath, mapSingleContents, sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); @@ -1757,7 +1757,14 @@ define(function (require) { } } - sourceMapLineNumber = fileContents.split('\n').length - 1; + //singleContents always has a line break added from + //the above code. However, that line break is not in + //the original code. So the sourceMapLineNumber + //needs to start + 1 to skip over that line, and the + //singleContents put into the map also needs to + //remove the line break for things to line up. + sourceMapLineNumber = fileContents.split('\n').length - 1 + 1; + mapSingleContents = singleContents.substring(1); lineCount = singleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { sourceMapGenerator.addMapping({ @@ -1777,7 +1784,7 @@ define(function (require) { //map since other transforms later like minification //can mess up translating back to the original //source - sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); + sourceMapGenerator.setSourceContent(sourceMapPath, mapSingleContents); } //Add the file to the final contents diff --git a/build/tests/lib/sourcemap/expected-main.js.map b/build/tests/lib/sourcemap/expected-main.js.map index ec727c47..99fe1f2f 100644 --- a/build/tests/lib/sourcemap/expected-main.js.map +++ b/build/tests/lib/sourcemap/expected-main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAIA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["\n/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\n/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"main.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemap/onejs/expected.map b/build/tests/lib/sourcemap/onejs/expected.map index 4a67b0d6..6cac3f3e 100644 --- a/build/tests/lib/sourcemap/onejs/expected.map +++ b/build/tests/lib/sourcemap/onejs/expected.map @@ -1 +1 @@ -{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAWA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["\n/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","\n/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\ndefine('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","\nrequire.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAUA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,ODmYA,yBAAA,WAAA,MAAA,eEhYA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QDYA,QCXA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","define('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","define('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","require.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/expected-main-built.js.map b/build/tests/lib/sourcemapSingle/expected-main-built.js.map index 4d2baf6d..777bc73e 100644 --- a/build/tests/lib/sourcemapSingle/expected-main-built.js.map +++ b/build/tests/lib/sourcemapSingle/expected-main-built.js.map @@ -1 +1 @@ -{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAIA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["\n/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\n/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/main-built.js.map b/build/tests/lib/sourcemapSingle/main-built.js.map index 4d2baf6d..777bc73e 100644 --- a/build/tests/lib/sourcemapSingle/main-built.js.map +++ b/build/tests/lib/sourcemapSingle/main-built.js.map @@ -1 +1 @@ -{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAIA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["\n/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\n/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file From 2b40dac6c0ece1781e91f92ba79d40dd9af5d096 Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 11 Oct 2013 11:37:48 -0700 Subject: [PATCH 064/382] snapshot --- dist/r.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/dist/r.js b/dist/r.js index 27571708..e167d7ed 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 11 Oct 2013 06:05:19 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 11 Oct 2013 18:37:42 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 11 Oct 2013 06:05:19 GMT', + version = '2.1.8+ Fri, 11 Oct 2013 18:37:42 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25667,7 +25667,7 @@ define('build', function (require) { }); } }).then(function () { - var refPath, pluginId, resourcePath, + var refPath, pluginId, resourcePath, mapSingleContents, sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); @@ -25713,7 +25713,14 @@ define('build', function (require) { } } - sourceMapLineNumber = fileContents.split('\n').length - 1; + //singleContents always has a line break added from + //the above code. However, that line break is not in + //the original code. So the sourceMapLineNumber + //needs to start + 1 to skip over that line, and the + //singleContents put into the map also needs to + //remove the line break for things to line up. + sourceMapLineNumber = fileContents.split('\n').length - 1 + 1; + mapSingleContents = singleContents.substring(1); lineCount = singleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { sourceMapGenerator.addMapping({ @@ -25733,7 +25740,7 @@ define('build', function (require) { //map since other transforms later like minification //can mess up translating back to the original //source - sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); + sourceMapGenerator.setSourceContent(sourceMapPath, mapSingleContents); } //Add the file to the final contents From 19f5e485d49d585d8c3790a5d658fcc35e35c0dd Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 11 Oct 2013 14:29:43 -0700 Subject: [PATCH 065/382] Fixes #486, make sure bundled map is kept around in closure case --- build/jslib/rhino/optimize.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/build/jslib/rhino/optimize.js b/build/jslib/rhino/optimize.js index 11c3dbb3..bf20b285 100644 --- a/build/jslib/rhino/optimize.js +++ b/build/jslib/rhino/optimize.js @@ -77,6 +77,7 @@ define(['logger', 'env!env/file'], function (logger, file) { config = config || {}; var result, mappings, optimized, compressed, baseName, writer, outBaseName, outFileNameMap, outFileNameMapContent, + srcOutFileName, concatNameMap, jscomp = Packages.com.google.javascript.jscomp, flags = Packages.com.google.common.flags, //Set up source input @@ -107,7 +108,7 @@ define(['logger', 'env!env/file'], function (logger, file) { if (config.generateSourceMaps) { mappings = new java.util.ArrayList(); - mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src")); + mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src.js")); options.setSourceMapLocationMappings(mappings); options.setSourceMapOutputPath(fileName + ".map"); } @@ -115,8 +116,8 @@ define(['logger', 'env!env/file'], function (logger, file) { //Trigger the compiler Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']); compiler = new Compiler(); - - //fill the sourceArrrayList; we need the ArrayList because the only overload of compile + + //fill the sourceArrrayList; we need the ArrayList because the only overload of compile //accepting the getDefaultExterns return value (a List) also wants the sources as a List sourceListArray.add(jsSourceFile); @@ -127,9 +128,22 @@ define(['logger', 'env!env/file'], function (logger, file) { if (config.generateSourceMaps && result.sourceMap && outFileName) { outBaseName = (new java.io.File(outFileName)).getName(); - file.saveUtf8File(outFileName + ".src", fileContents); - + srcOutFileName = outFileName + ".src.js"; outFileNameMap = outFileName + ".map"; + + //If previous .map file exists, move it to the ".src.js" + //location. Need to update the sourceMappingURL part in the + //src.js file too. + if (file.exists(outFileNameMap)) { + concatNameMap = outFileNameMap.replace(/\.map$/, '.src.js.map'); + file.saveFile(concatNameMap, file.readFile(outFileNameMap)); + file.saveFile(srcOutFileName, + fileContents.replace(/\/\# sourceMappingURL=(.+).map/, + '/# sourceMappingURL=$1.src.js.map')); + } else { + file.saveUtf8File(srcOutFileName, fileContents); + } + writer = getFileWriter(outFileNameMap, "utf-8"); result.sourceMap.appendTo(writer, outFileName); writer.close(); From ce345e688ad221dd10d99a6e9fa08dede3be28d2 Mon Sep 17 00:00:00 2001 From: jrburke Date: Fri, 11 Oct 2013 14:30:41 -0700 Subject: [PATCH 066/382] snapshot --- dist/r.js | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/dist/r.js b/dist/r.js index e167d7ed..c5356ca5 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 11 Oct 2013 18:37:42 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Fri, 11 Oct 2013 21:29:46 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 11 Oct 2013 18:37:42 GMT', + version = '2.1.8+ Fri, 11 Oct 2013 21:29:46 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22834,6 +22834,7 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { config = config || {}; var result, mappings, optimized, compressed, baseName, writer, outBaseName, outFileNameMap, outFileNameMapContent, + srcOutFileName, concatNameMap, jscomp = Packages.com.google.javascript.jscomp, flags = Packages.com.google.common.flags, //Set up source input @@ -22864,7 +22865,7 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { if (config.generateSourceMaps) { mappings = new java.util.ArrayList(); - mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src")); + mappings.add(new com.google.javascript.jscomp.SourceMap.LocationMapping(fileName, baseName + ".src.js")); options.setSourceMapLocationMappings(mappings); options.setSourceMapOutputPath(fileName + ".map"); } @@ -22872,8 +22873,8 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { //Trigger the compiler Compiler.setLoggingLevel(Packages.java.util.logging.Level[config.loggingLevel || 'WARNING']); compiler = new Compiler(); - - //fill the sourceArrrayList; we need the ArrayList because the only overload of compile + + //fill the sourceArrrayList; we need the ArrayList because the only overload of compile //accepting the getDefaultExterns return value (a List) also wants the sources as a List sourceListArray.add(jsSourceFile); @@ -22884,9 +22885,22 @@ define('rhino/optimize', ['logger', 'env!env/file'], function (logger, file) { if (config.generateSourceMaps && result.sourceMap && outFileName) { outBaseName = (new java.io.File(outFileName)).getName(); - file.saveUtf8File(outFileName + ".src", fileContents); - + srcOutFileName = outFileName + ".src.js"; outFileNameMap = outFileName + ".map"; + + //If previous .map file exists, move it to the ".src.js" + //location. Need to update the sourceMappingURL part in the + //src.js file too. + if (file.exists(outFileNameMap)) { + concatNameMap = outFileNameMap.replace(/\.map$/, '.src.js.map'); + file.saveFile(concatNameMap, file.readFile(outFileNameMap)); + file.saveFile(srcOutFileName, + fileContents.replace(/\/\# sourceMappingURL=(.+).map/, + '/# sourceMappingURL=$1.src.js.map')); + } else { + file.saveUtf8File(srcOutFileName, fileContents); + } + writer = getFileWriter(outFileNameMap, "utf-8"); result.sourceMap.appendTo(writer, outFileName); writer.close(); From 51b7e6cdf7640c573e1ce5da8709b65a089345cc Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 12 Oct 2013 17:52:18 -0700 Subject: [PATCH 067/382] Fixes #482, apply cssPrefix to top cssIn file --- build/jslib/optimize.js | 81 +++++++++++-------- build/tests/lib/cssPrefix/input/main.css | 4 + build/tests/lib/cssPrefix/output/expected.css | 3 + .../tests/lib/cssPrefix/output/main-built.css | 3 + 4 files changed, 56 insertions(+), 35 deletions(-) diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index 594ed983..08b97b07 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -41,6 +41,41 @@ function (lang, logger, envOptimize, file, parse, return url; } + function fixCssUrlPaths(fileName, path, contents, cssPrefix) { + return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { + var colonIndex, parts, i, + fixedUrlMatch = cleanCssUrlQuotes(urlMatch); + + fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); + + //Only do the work for relative URLs. Skip things that start with / or have + //a protocol. + colonIndex = fixedUrlMatch.indexOf(":"); + if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + //It is a relative URL, tack on the cssPrefix and path prefix + urlMatch = cssPrefix + path + fixedUrlMatch; + + } else { + logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); + } + + //Collapse .. and . + parts = urlMatch.split("/"); + for (i = parts.length - 1; i > 0; i--) { + if (parts[i] === ".") { + parts.splice(i, 1); + } else if (parts[i] === "..") { + if (i !== 0 && parts[i - 1] !== "..") { + parts.splice(i - 1, 2); + i -= 1; + } + } + } + + return "url(" + parts.join("/") + ")"; + }); + } + /** * Inlines nested stylesheets that have @import calls in them. * @param {String} fileName the file name @@ -49,7 +84,7 @@ function (lang, logger, envOptimize, file, parse, * @param {String} cssPrefix string to be prefixed before relative URLs * @param {Object} included an object used to track the files already imported */ - function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included) { + function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included, topLevel) { //Find the last slash in the name. fileName = fileName.replace(lang.backSlashRegExp, "/"); var endIndex = fileName.lastIndexOf("/"), @@ -60,7 +95,7 @@ function (lang, logger, envOptimize, file, parse, importList = [], skippedList = []; - //First make a pass by removing an commented out @import calls. + //First make a pass by removing any commented out @import calls. fileContents = fileContents.replace(cssCommentImportRegExp, ''); //Make sure we have a delimited ignore list to make matching faster @@ -90,8 +125,8 @@ function (lang, logger, envOptimize, file, parse, //If it is not a relative path, then the readFile below will fail, //and we will just skip that import. var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName, - importContents = file.readFile(fullImportFileName), i, - importEndIndex, importPath, fixedUrlMatch, colonIndex, parts, flat; + importContents = file.readFile(fullImportFileName), + importEndIndex, importPath, flat; //Skip the file if it has already been included. if (included[fullImportFileName]) { @@ -121,36 +156,7 @@ function (lang, logger, envOptimize, file, parse, 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, "/"); - - //Only do the work for relative URLs. Skip things that start with / or have - //a protocol. - colonIndex = fixedUrlMatch.indexOf(":"); - if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { - //It is a relative URL, tack on the cssPrefix and path prefix - urlMatch = cssPrefix + importPath + fixedUrlMatch; - - } else { - logger.trace(importFileName + "\n URL not a relative URL, skipping: " + urlMatch); - } - - //Collapse .. and . - parts = urlMatch.split("/"); - for (i = parts.length - 1; i > 0; i--) { - if (parts[i] === ".") { - parts.splice(i, 1); - } else if (parts[i] === "..") { - if (i !== 0 && parts[i - 1] !== "..") { - parts.splice(i - 1, 2); - i -= 1; - } - } - } - - return "url(" + parts.join("/") + ")"; - }); + importContents = fixCssUrlPaths(importFileName, importPath, importContents, cssPrefix); importList.push(fullImportFileName); return importContents; @@ -160,6 +166,11 @@ function (lang, logger, envOptimize, file, parse, } }); + if (cssPrefix && topLevel) { + //Modify URL paths to match the path represented by this file. + fileContents = fixCssUrlPaths(fileName, '', fileContents, cssPrefix); + } + return { importList : importList, skippedList: skippedList, @@ -269,7 +280,7 @@ function (lang, logger, envOptimize, file, parse, //Read in the file. Make sure we have a JS string. var originalFileContents = file.readFile(fileName), - flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}), + flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}, true), //Do not use the flattened CSS if there was one that was skipped. fileContents = flat.skippedList.length ? originalFileContents : flat.fileContents, startIndex, endIndex, buildText, comment; diff --git a/build/tests/lib/cssPrefix/input/main.css b/build/tests/lib/cssPrefix/input/main.css index 73222244..ff060cad 100644 --- a/build/tests/lib/cssPrefix/input/main.css +++ b/build/tests/lib/cssPrefix/input/main.css @@ -1 +1,5 @@ @import url(subfolder/sub.css); + +body { + background: url(img/bg.png); +} diff --git a/build/tests/lib/cssPrefix/output/expected.css b/build/tests/lib/cssPrefix/output/expected.css index c39cfcd3..434549d8 100644 --- a/build/tests/lib/cssPrefix/output/expected.css +++ b/build/tests/lib/cssPrefix/output/expected.css @@ -1,3 +1,6 @@ .test { background: url(/test/subfolder/test.png); } +body { + background: url(/test/img/bg.png); +} diff --git a/build/tests/lib/cssPrefix/output/main-built.css b/build/tests/lib/cssPrefix/output/main-built.css index c39cfcd3..434549d8 100644 --- a/build/tests/lib/cssPrefix/output/main-built.css +++ b/build/tests/lib/cssPrefix/output/main-built.css @@ -1,3 +1,6 @@ .test { background: url(/test/subfolder/test.png); } +body { + background: url(/test/img/bg.png); +} From 97f348ca00af084978bb3f5c3a4a93ab5fd6dbc4 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 12 Oct 2013 17:52:31 -0700 Subject: [PATCH 068/382] snapshot --- dist/r.js | 85 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/dist/r.js b/dist/r.js index c5356ca5..1888fc4a 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Fri, 11 Oct 2013 21:29:46 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Sun, 13 Oct 2013 00:52:22 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Fri, 11 Oct 2013 21:29:46 GMT', + version = '2.1.8+ Sun, 13 Oct 2013 00:52:22 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22974,6 +22974,41 @@ function (lang, logger, envOptimize, file, parse, return url; } + function fixCssUrlPaths(fileName, path, contents, cssPrefix) { + return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { + var colonIndex, parts, i, + fixedUrlMatch = cleanCssUrlQuotes(urlMatch); + + fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); + + //Only do the work for relative URLs. Skip things that start with / or have + //a protocol. + colonIndex = fixedUrlMatch.indexOf(":"); + if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + //It is a relative URL, tack on the cssPrefix and path prefix + urlMatch = cssPrefix + path + fixedUrlMatch; + + } else { + logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); + } + + //Collapse .. and . + parts = urlMatch.split("/"); + for (i = parts.length - 1; i > 0; i--) { + if (parts[i] === ".") { + parts.splice(i, 1); + } else if (parts[i] === "..") { + if (i !== 0 && parts[i - 1] !== "..") { + parts.splice(i - 1, 2); + i -= 1; + } + } + } + + return "url(" + parts.join("/") + ")"; + }); + } + /** * Inlines nested stylesheets that have @import calls in them. * @param {String} fileName the file name @@ -22982,7 +23017,7 @@ function (lang, logger, envOptimize, file, parse, * @param {String} cssPrefix string to be prefixed before relative URLs * @param {Object} included an object used to track the files already imported */ - function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included) { + function flattenCss(fileName, fileContents, cssImportIgnore, cssPrefix, included, topLevel) { //Find the last slash in the name. fileName = fileName.replace(lang.backSlashRegExp, "/"); var endIndex = fileName.lastIndexOf("/"), @@ -22993,7 +23028,7 @@ function (lang, logger, envOptimize, file, parse, importList = [], skippedList = []; - //First make a pass by removing an commented out @import calls. + //First make a pass by removing any commented out @import calls. fileContents = fileContents.replace(cssCommentImportRegExp, ''); //Make sure we have a delimited ignore list to make matching faster @@ -23023,8 +23058,8 @@ function (lang, logger, envOptimize, file, parse, //If it is not a relative path, then the readFile below will fail, //and we will just skip that import. var fullImportFileName = importFileName.charAt(0) === "/" ? importFileName : filePath + importFileName, - importContents = file.readFile(fullImportFileName), i, - importEndIndex, importPath, fixedUrlMatch, colonIndex, parts, flat; + importContents = file.readFile(fullImportFileName), + importEndIndex, importPath, flat; //Skip the file if it has already been included. if (included[fullImportFileName]) { @@ -23054,36 +23089,7 @@ function (lang, logger, envOptimize, file, parse, 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, "/"); - - //Only do the work for relative URLs. Skip things that start with / or have - //a protocol. - colonIndex = fixedUrlMatch.indexOf(":"); - if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { - //It is a relative URL, tack on the cssPrefix and path prefix - urlMatch = cssPrefix + importPath + fixedUrlMatch; - - } else { - logger.trace(importFileName + "\n URL not a relative URL, skipping: " + urlMatch); - } - - //Collapse .. and . - parts = urlMatch.split("/"); - for (i = parts.length - 1; i > 0; i--) { - if (parts[i] === ".") { - parts.splice(i, 1); - } else if (parts[i] === "..") { - if (i !== 0 && parts[i - 1] !== "..") { - parts.splice(i - 1, 2); - i -= 1; - } - } - } - - return "url(" + parts.join("/") + ")"; - }); + importContents = fixCssUrlPaths(importFileName, importPath, importContents, cssPrefix); importList.push(fullImportFileName); return importContents; @@ -23093,6 +23099,11 @@ function (lang, logger, envOptimize, file, parse, } }); + if (cssPrefix && topLevel) { + //Modify URL paths to match the path represented by this file. + fileContents = fixCssUrlPaths(fileName, '', fileContents, cssPrefix); + } + return { importList : importList, skippedList: skippedList, @@ -23202,7 +23213,7 @@ function (lang, logger, envOptimize, file, parse, //Read in the file. Make sure we have a JS string. var originalFileContents = file.readFile(fileName), - flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}), + flat = flattenCss(fileName, originalFileContents, config.cssImportIgnore, config.cssPrefix, {}, true), //Do not use the flattened CSS if there was one that was skipped. fileContents = flat.skippedList.length ? originalFileContents : flat.fileContents, startIndex, endIndex, buildText, comment; From 56df88e93243e982d254344e0568f5bba5004b82 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 12 Oct 2013 19:52:15 -0700 Subject: [PATCH 069/382] Fixes #526, call errbacks in node usage --- build/jslib/node.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/build/jslib/node.js b/build/jslib/node.js index b1c5fb32..16c259d8 100644 --- a/build/jslib/node.js +++ b/build/jslib/node.js @@ -35,10 +35,16 @@ fn(); } + function makeError(message, moduleName) { + var err = new Error(message); + err.requireModules = [moduleName]; + return err; + } + //Supply an implementation that allows synchronous get of a module. req.get = function (context, moduleName, relModuleMap, localRequire) { if (moduleName === "require" || moduleName === "exports" || moduleName === "module") { - req.onError(new Error("Explicit require of " + moduleName + " is not allowed.")); + context.onError(makeError("Explicit require of " + moduleName + " is not allowed.", moduleName)); } var ret, oldTick, @@ -121,8 +127,9 @@ moduleName + '" failed with error: ' + e); err.originalError = e; err.moduleName = moduleName; + err.requireModules = [moduleName]; err.fileName = url; - return req.onError(err); + return context.onError(err); } } else { def(moduleName, function () { @@ -151,7 +158,8 @@ 'with error: ' + e); err.originalError = e; err.moduleName = originalName; - return req.onError(err); + err.requireModules = [moduleName]; + return context.onError(err); } }); } From 4ce60ac17610e9085685dc69a760efac2e3cc9ce Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 12 Oct 2013 19:52:29 -0700 Subject: [PATCH 070/382] snapshot --- dist/r.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/dist/r.js b/dist/r.js index 1888fc4a..f0e266e2 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Sun, 13 Oct 2013 00:52:22 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Sun, 13 Oct 2013 02:52:19 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Sun, 13 Oct 2013 00:52:22 GMT', + version = '2.1.8+ Sun, 13 Oct 2013 02:52:19 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -2391,10 +2391,16 @@ var requirejs, require, define, xpcUtil; fn(); } + function makeError(message, moduleName) { + var err = new Error(message); + err.requireModules = [moduleName]; + return err; + } + //Supply an implementation that allows synchronous get of a module. req.get = function (context, moduleName, relModuleMap, localRequire) { if (moduleName === "require" || moduleName === "exports" || moduleName === "module") { - req.onError(new Error("Explicit require of " + moduleName + " is not allowed.")); + context.onError(makeError("Explicit require of " + moduleName + " is not allowed.", moduleName)); } var ret, oldTick, @@ -2477,8 +2483,9 @@ var requirejs, require, define, xpcUtil; moduleName + '" failed with error: ' + e); err.originalError = e; err.moduleName = moduleName; + err.requireModules = [moduleName]; err.fileName = url; - return req.onError(err); + return context.onError(err); } } else { def(moduleName, function () { @@ -2507,7 +2514,8 @@ var requirejs, require, define, xpcUtil; 'with error: ' + e); err.originalError = e; err.moduleName = originalName; - return req.onError(err); + err.requireModules = [moduleName]; + return context.onError(err); } }); } From cd1979b8be9a48acedd848cfaa5fc78ac6f4698f Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 12 Oct 2013 20:04:47 -0700 Subject: [PATCH 071/382] Fixes #533, add doc about create: true --- build/example.build.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build/example.build.js b/build/example.build.js index 6e7659c8..0b435efb 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -339,6 +339,12 @@ { name: "foo/bar/bop", + //create: true can be used to create the modul layer at the given + //name, if it does not already exist in the source location. If + //there is a module at the source location with this name, then + //create: true is superfluous. + create: true, + //For build profiles that contain more than one modules entry, //allow overrides for the properties that set for the whole build, //for example a different set of pragmas for this module. From 56faf871c62519cb9921565bca0ce679fd9322e4 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 13 Oct 2013 23:33:07 -0700 Subject: [PATCH 072/382] Related to #523, forgot to update lineCount to discard inserted line. Found via backbone-boilerplate run --- build/jslib/build.js | 4 ++-- build/tests/lib/sourcemap/onejs/expected.map | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 7a365ef9..86a7c80a 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1765,7 +1765,7 @@ define(function (require) { //remove the line break for things to line up. sourceMapLineNumber = fileContents.split('\n').length - 1 + 1; mapSingleContents = singleContents.substring(1); - lineCount = singleContents.split('\n').length; + lineCount = mapSingleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { sourceMapGenerator.addMapping({ generated: { @@ -1783,7 +1783,7 @@ define(function (require) { //Store the content of the original in the source //map since other transforms later like minification //can mess up translating back to the original - //source + //source. sourceMapGenerator.setSourceContent(sourceMapPath, mapSingleContents); } diff --git a/build/tests/lib/sourcemap/onejs/expected.map b/build/tests/lib/sourcemap/onejs/expected.map index 6cac3f3e..149215e3 100644 --- a/build/tests/lib/sourcemap/onejs/expected.map +++ b/build/tests/lib/sourcemap/onejs/expected.map @@ -1 +1 @@ -{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAUA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,ODmYA,yBAAA,WAAA,MAAA,eEhYA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QDYA,QCXA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","define('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","define('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","require.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAUA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","define('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","define('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","require.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file From 093b137e8c1bfaa0fb5e61c5597f6ceae8be625b Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 13 Oct 2013 23:33:28 -0700 Subject: [PATCH 073/382] snapshot --- dist/r.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index f0e266e2..5dd4b526 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Sun, 13 Oct 2013 02:52:19 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Mon, 14 Oct 2013 06:33:12 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Sun, 13 Oct 2013 02:52:19 GMT', + version = '2.1.8+ Mon, 14 Oct 2013 06:33:12 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25754,7 +25754,7 @@ define('build', function (require) { //remove the line break for things to line up. sourceMapLineNumber = fileContents.split('\n').length - 1 + 1; mapSingleContents = singleContents.substring(1); - lineCount = singleContents.split('\n').length; + lineCount = mapSingleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { sourceMapGenerator.addMapping({ generated: { @@ -25772,7 +25772,7 @@ define('build', function (require) { //Store the content of the original in the source //map since other transforms later like minification //can mess up translating back to the original - //source + //source. sourceMapGenerator.setSourceContent(sourceMapPath, mapSingleContents); } From 00d171157b2899bbb64e998955d46e1034816578 Mon Sep 17 00:00:00 2001 From: dsine-de Date: Mon, 14 Oct 2013 15:52:35 +0200 Subject: [PATCH 074/382] Fixed typo --- build/example.build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/example.build.js b/build/example.build.js index 0b435efb..1e1d6e87 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -196,7 +196,7 @@ //returns. (r.js 1.0.8+) optimizeCss: "standard.keepLines", - //If optimizeCss is in use, a list of of files to ignore for the @import + //If optimizeCss is in use, a list of files to ignore for the @import //inlining. The value of this option should be a string of comma separated //CSS file names to ignore (like 'a.css,b.css'. The file names should match //whatever strings are used in the @import calls. From 5cb869b36ad5746a13932613569bd4b7e0a55008 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 14 Oct 2013 13:28:22 -0700 Subject: [PATCH 075/382] Reverts changes for #523, some cases with uglifyjs2 result in warnings --- build/jslib/build.js | 15 ++++----------- build/tests/lib/sourcemap/expected-main.js.map | 2 +- build/tests/lib/sourcemap/onejs/expected.map | 2 +- .../sourcemapSingle/expected-main-built.js.map | 2 +- build/tests/lib/sourcemapSingle/main-built.js.map | 2 +- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 86a7c80a..558f772b 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1711,7 +1711,7 @@ define(function (require) { }); } }).then(function () { - var refPath, pluginId, resourcePath, mapSingleContents, + var refPath, pluginId, resourcePath, sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); @@ -1757,15 +1757,8 @@ define(function (require) { } } - //singleContents always has a line break added from - //the above code. However, that line break is not in - //the original code. So the sourceMapLineNumber - //needs to start + 1 to skip over that line, and the - //singleContents put into the map also needs to - //remove the line break for things to line up. - sourceMapLineNumber = fileContents.split('\n').length - 1 + 1; - mapSingleContents = singleContents.substring(1); - lineCount = mapSingleContents.split('\n').length; + sourceMapLineNumber = fileContents.split('\n').length - 1; + lineCount = singleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { sourceMapGenerator.addMapping({ generated: { @@ -1784,7 +1777,7 @@ define(function (require) { //map since other transforms later like minification //can mess up translating back to the original //source. - sourceMapGenerator.setSourceContent(sourceMapPath, mapSingleContents); + sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); } //Add the file to the final contents diff --git a/build/tests/lib/sourcemap/expected-main.js.map b/build/tests/lib/sourcemap/expected-main.js.map index 99fe1f2f..ec727c47 100644 --- a/build/tests/lib/sourcemap/expected-main.js.map +++ b/build/tests/lib/sourcemap/expected-main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"main.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAIA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["\n/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\n/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemap/onejs/expected.map b/build/tests/lib/sourcemap/onejs/expected.map index 149215e3..4a67b0d6 100644 --- a/build/tests/lib/sourcemap/onejs/expected.map +++ b/build/tests/lib/sourcemap/onejs/expected.map @@ -1 +1 @@ -{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAUA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","define('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","define('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","require.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAWA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,MADA,KACA,MAGA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,WACA,IACA,UAIA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,KAfA,SAoBA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IChYA,OAAA,yBAAA,WAAA,MAAA,eCGA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCTA,OAAA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QAAA,QACA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,aAGA,OAAA,MAAA","sourcesContent":["\n/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n","\n/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\ndefine('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n","\nrequire.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main']);\n\n\ndefine(\"app\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/expected-main-built.js.map b/build/tests/lib/sourcemapSingle/expected-main-built.js.map index 777bc73e..4d2baf6d 100644 --- a/build/tests/lib/sourcemapSingle/expected-main-built.js.map +++ b/build/tests/lib/sourcemapSingle/expected-main-built.js.map @@ -1 +1 @@ -{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAIA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["\n/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\n/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/main-built.js.map b/build/tests/lib/sourcemapSingle/main-built.js.map index 777bc73e..4d2baf6d 100644 --- a/build/tests/lib/sourcemapSingle/main-built.js.map +++ b/build/tests/lib/sourcemapSingle/main-built.js.map @@ -1 +1 @@ -{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file +{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAIA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["\n/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n","\n/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n","\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n"]} \ No newline at end of file From 6f83b691b26f16993d06777e70987068ac549f5a Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 14 Oct 2013 13:28:47 -0700 Subject: [PATCH 076/382] snapshot --- dist/r.js | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/dist/r.js b/dist/r.js index 5dd4b526..9c040edc 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Mon, 14 Oct 2013 06:33:12 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.8+ Mon, 14 Oct 2013 20:28:39 GMT 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Mon, 14 Oct 2013 06:33:12 GMT', + version = '2.1.8+ Mon, 14 Oct 2013 20:28:39 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25700,7 +25700,7 @@ define('build', function (require) { }); } }).then(function () { - var refPath, pluginId, resourcePath, mapSingleContents, + var refPath, pluginId, resourcePath, sourceMapPath, sourceMapLineNumber, shortPath = path.replace(config.dir, ""); @@ -25746,15 +25746,8 @@ define('build', function (require) { } } - //singleContents always has a line break added from - //the above code. However, that line break is not in - //the original code. So the sourceMapLineNumber - //needs to start + 1 to skip over that line, and the - //singleContents put into the map also needs to - //remove the line break for things to line up. - sourceMapLineNumber = fileContents.split('\n').length - 1 + 1; - mapSingleContents = singleContents.substring(1); - lineCount = mapSingleContents.split('\n').length; + sourceMapLineNumber = fileContents.split('\n').length - 1; + lineCount = singleContents.split('\n').length; for (var i = 1; i <= lineCount; i += 1) { sourceMapGenerator.addMapping({ generated: { @@ -25773,7 +25766,7 @@ define('build', function (require) { //map since other transforms later like minification //can mess up translating back to the original //source. - sourceMapGenerator.setSourceContent(sourceMapPath, mapSingleContents); + sourceMapGenerator.setSourceContent(sourceMapPath, singleContents); } //Add the file to the final contents From 93f5334e82602c4735ba3efbca9f0769bc7db7f8 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 14 Oct 2013 14:05:33 -0700 Subject: [PATCH 077/382] rev for 2.1.9 --- build/jslib/x.js | 4 ++-- dist/r.js | 8 ++++---- require.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 7d32a492..06e0662d 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+', + version = '2.1.9', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index 9c040edc..309ceaf3 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.8+ Mon, 14 Oct 2013 20:28:39 GMT Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9 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 */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.8+ Mon, 14 Oct 2013 20:28:39 GMT', + version = '2.1.9', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.8+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.9 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 */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.8+', + version = '2.1.9', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, diff --git a/require.js b/require.js index c7c3150e..2ce09b5e 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.8+ Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.9 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 */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.8+', + version = '2.1.9', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, From 32247b1be7238e553a40e8186629d5d9287d812a Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 23 Oct 2013 15:30:34 -0700 Subject: [PATCH 078/382] update copyright years --- build/build.js | 2 +- build/jslib/browser.js | 2 +- build/jslib/browser/args.js | 2 +- build/jslib/browser/assert.js | 2 +- build/jslib/browser/file.js | 2 +- build/jslib/browser/load.js | 2 +- build/jslib/browser/optimize.js | 2 +- build/jslib/browser/print.js | 2 +- build/jslib/build.js | 2 +- build/jslib/commandLine.js | 2 +- build/jslib/commonJs.js | 2 +- build/jslib/env.js | 2 +- build/jslib/esprimaAdapter.js | 2 +- build/jslib/lang.js | 2 +- build/jslib/logger.js | 2 +- build/jslib/node.js | 2 +- build/jslib/node/args.js | 2 +- build/jslib/node/assert.js | 2 +- build/jslib/node/file.js | 2 +- build/jslib/node/load.js | 2 +- build/jslib/node/optimize.js | 2 +- build/jslib/node/print.js | 2 +- build/jslib/optimize.js | 2 +- build/jslib/parse.js | 2 +- build/jslib/pragma.js | 2 +- build/jslib/requirePatch.js | 2 +- build/jslib/rhino.js | 2 +- build/jslib/rhino/args.js | 2 +- build/jslib/rhino/assert.js | 2 +- build/jslib/rhino/file.js | 2 +- build/jslib/rhino/load.js | 2 +- build/jslib/rhino/optimize.js | 2 +- build/jslib/rhino/print.js | 2 +- build/jslib/transform.js | 2 +- build/jslib/x.js | 2 +- dist.js | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/build/build.js b/build/build.js index 1ff114ff..42381e3e 100644 --- a/build/build.js +++ b/build/build.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser.js b/build/jslib/browser.js index 5dc16ceb..ebba05a5 100644 --- a/build/jslib/browser.js +++ b/build/jslib/browser.js @@ -1,5 +1,5 @@ /** - * @license RequireJS rhino Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS rhino Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser/args.js b/build/jslib/browser/args.js index 9e50f059..007c1697 100644 --- a/build/jslib/browser/args.js +++ b/build/jslib/browser/args.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser/assert.js b/build/jslib/browser/assert.js index 62cef8cc..66b0bf04 100644 --- a/build/jslib/browser/assert.js +++ b/build/jslib/browser/assert.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser/file.js b/build/jslib/browser/file.js index c8ed8e34..0089f045 100644 --- a/build/jslib/browser/file.js +++ b/build/jslib/browser/file.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser/load.js b/build/jslib/browser/load.js index 71246450..e62871d0 100644 --- a/build/jslib/browser/load.js +++ b/build/jslib/browser/load.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser/optimize.js b/build/jslib/browser/optimize.js index 8731b69d..0c98e4b7 100644 --- a/build/jslib/browser/optimize.js +++ b/build/jslib/browser/optimize.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/browser/print.js b/build/jslib/browser/print.js index 2835926a..374fd422 100644 --- a/build/jslib/browser/print.js +++ b/build/jslib/browser/print.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/build.js b/build/jslib/build.js index 558f772b..575d73c7 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/commandLine.js b/build/jslib/commandLine.js index 31ddeecd..df482c76 100644 --- a/build/jslib/commandLine.js +++ b/build/jslib/commandLine.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/commonJs.js b/build/jslib/commonJs.js index dccebf25..ed666b05 100644 --- a/build/jslib/commonJs.js +++ b/build/jslib/commonJs.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/env.js b/build/jslib/env.js index c1603dba..448e02ee 100644 --- a/build/jslib/env.js +++ b/build/jslib/env.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/esprimaAdapter.js b/build/jslib/esprimaAdapter.js index 6e78f015..0bdbd667 100644 --- a/build/jslib/esprimaAdapter.js +++ b/build/jslib/esprimaAdapter.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/lang.js b/build/jslib/lang.js index bedd8fbb..ca165b9b 100644 --- a/build/jslib/lang.js +++ b/build/jslib/lang.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/logger.js b/build/jslib/logger.js index 57dea64b..87b3da96 100644 --- a/build/jslib/logger.js +++ b/build/jslib/logger.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node.js b/build/jslib/node.js index 16c259d8..798f66ca 100644 --- a/build/jslib/node.js +++ b/build/jslib/node.js @@ -1,5 +1,5 @@ /** - * @license RequireJS node Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS node Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node/args.js b/build/jslib/node/args.js index 54abbd34..fca2c34e 100644 --- a/build/jslib/node/args.js +++ b/build/jslib/node/args.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node/assert.js b/build/jslib/node/assert.js index ac213c7c..828da0e1 100644 --- a/build/jslib/node/assert.js +++ b/build/jslib/node/assert.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node/file.js b/build/jslib/node/file.js index 440e2b9c..b9fb1729 100644 --- a/build/jslib/node/file.js +++ b/build/jslib/node/file.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node/load.js b/build/jslib/node/load.js index 194ea9e5..02df3860 100644 --- a/build/jslib/node/load.js +++ b/build/jslib/node/load.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node/optimize.js b/build/jslib/node/optimize.js index 8731b69d..0c98e4b7 100644 --- a/build/jslib/node/optimize.js +++ b/build/jslib/node/optimize.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/node/print.js b/build/jslib/node/print.js index 2835926a..374fd422 100644 --- a/build/jslib/node/print.js +++ b/build/jslib/node/print.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index 08b97b07..a7714d38 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/parse.js b/build/jslib/parse.js index 3f941ec1..44f5bf82 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/pragma.js b/build/jslib/pragma.js index 8214e3b2..7afe6a7a 100644 --- a/build/jslib/pragma.js +++ b/build/jslib/pragma.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/requirePatch.js b/build/jslib/requirePatch.js index 2acc313a..e0c3b67a 100644 --- a/build/jslib/requirePatch.js +++ b/build/jslib/requirePatch.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino.js b/build/jslib/rhino.js index 935be7b7..f1ce31c4 100644 --- a/build/jslib/rhino.js +++ b/build/jslib/rhino.js @@ -1,5 +1,5 @@ /** - * @license RequireJS rhino Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS rhino Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino/args.js b/build/jslib/rhino/args.js index 331d8146..d8846a73 100644 --- a/build/jslib/rhino/args.js +++ b/build/jslib/rhino/args.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino/assert.js b/build/jslib/rhino/assert.js index 62cef8cc..1d761fe3 100644 --- a/build/jslib/rhino/assert.js +++ b/build/jslib/rhino/assert.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino/file.js b/build/jslib/rhino/file.js index e064e6a8..70e8dba3 100644 --- a/build/jslib/rhino/file.js +++ b/build/jslib/rhino/file.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino/load.js b/build/jslib/rhino/load.js index 84a23198..4ff51725 100644 --- a/build/jslib/rhino/load.js +++ b/build/jslib/rhino/load.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino/optimize.js b/build/jslib/rhino/optimize.js index bf20b285..e062f68c 100644 --- a/build/jslib/rhino/optimize.js +++ b/build/jslib/rhino/optimize.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/rhino/print.js b/build/jslib/rhino/print.js index 4ba92382..f8192215 100644 --- a/build/jslib/rhino/print.js +++ b/build/jslib/rhino/print.js @@ -1,5 +1,5 @@ /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/transform.js b/build/jslib/transform.js index 0540c51b..6e250152 100644 --- a/build/jslib/transform.js +++ b/build/jslib/transform.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/build/jslib/x.js b/build/jslib/x.js index 06e0662d..43bcb618 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9 Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ diff --git a/dist.js b/dist.js index 6380aab7..bc638621 100644 --- a/dist.js +++ b/dist.js @@ -1,5 +1,5 @@ /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ From 9aaa9f6648b216a90517367cbfe58a7496279e56 Mon Sep 17 00:00:00 2001 From: Magnus Dahlstrand Date: Wed, 6 Nov 2013 10:59:55 +0000 Subject: [PATCH 079/382] Add test case for whitespace stripping and update example build file. --- .gitignore | 1 + build/example.build.js | 2 +- build/tests/builds.js | 17 +++++++++++++++++ build/tests/lib/cssKeepComments/expected.css | 11 ++--------- build/tests/lib/cssKeepWhitespace/a.css | 8 ++++++++ build/tests/lib/cssKeepWhitespace/build.js | 5 +++++ build/tests/lib/cssKeepWhitespace/expected.css | 6 ++++++ build/tests/lib/cssKeepWhitespace/main.css | 8 ++++++++ 8 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 build/tests/lib/cssKeepWhitespace/a.css create mode 100644 build/tests/lib/cssKeepWhitespace/build.js create mode 100644 build/tests/lib/cssKeepWhitespace/expected.css create mode 100644 build/tests/lib/cssKeepWhitespace/main.css diff --git a/.gitignore b/.gitignore index 612b8118..082edafa 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ build/tests/lib/configPackageShim/built build/tests/lib/cssComment138/main-built.css build/tests/lib/cssDuplicates/main-built.css build/tests/lib/cssKeepComments/main-built.css +build/tests/lib/cssKeepWhitespace/main-built.css build/tests/lib/cssKeepLicense/main-license-built.css build/tests/lib/cssKeepLicense/main-built.css build/tests/lib/cssMediaQuery/main-built.css diff --git a/build/example.build.js b/build/example.build.js index 971ee2de..4b83869c 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -196,7 +196,7 @@ //- "standard.keepComments.keepLines": keeps the file comments and line //returns. (r.js 1.0.8+) //- "standard.keepWhitespace": like "standard" but keeps unnecessary whitespace. - optimizeCss: "standard.keepLines", + optimizeCss: "standard.keepLines.keepWhitespace", //If optimizeCss is in use, a list of of files to ignore for the @import //inlining. The value of this option should be a string of comma separated diff --git a/build/tests/builds.js b/build/tests/builds.js index 08c8fb5d..8b038a1e 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -989,6 +989,23 @@ define(['build', 'env!env/file', 'env'], function (build, file, env) { ); doh.run(); + doh.register("cssKeepWhitespace", + [ + function cssKeepComments(t) { + file.deleteFile("lib/cssKeepWhitespace/main-built.css"); + + build(["lib/cssKeepWhitespace/build.js"]); + + t.is(nol(c("lib/cssKeepWhitespace/expected.css")), + nol(c("lib/cssKeepWhitespace/main-built.css"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + doh.register("cssKeepLicense", [ function cssKeepLicense(t) { diff --git a/build/tests/lib/cssKeepComments/expected.css b/build/tests/lib/cssKeepComments/expected.css index bbfc10d0..a3da4b2f 100644 --- a/build/tests/lib/cssKeepComments/expected.css +++ b/build/tests/lib/cssKeepComments/expected.css @@ -1,12 +1,5 @@ /* This is an a.css comment. -*/ -.acss { - width: 1px; -} -/* +*/.acss{width:1px;}/* This is a main.css comment -*/ -.maincss { - width: 1; -} +*/.maincss{width:1;} diff --git a/build/tests/lib/cssKeepWhitespace/a.css b/build/tests/lib/cssKeepWhitespace/a.css new file mode 100644 index 00000000..1e3eddd3 --- /dev/null +++ b/build/tests/lib/cssKeepWhitespace/a.css @@ -0,0 +1,8 @@ +/* +This is an a.css comment. +*/ + +.acss { + width: 1px; +} + diff --git a/build/tests/lib/cssKeepWhitespace/build.js b/build/tests/lib/cssKeepWhitespace/build.js new file mode 100644 index 00000000..75e560d2 --- /dev/null +++ b/build/tests/lib/cssKeepWhitespace/build.js @@ -0,0 +1,5 @@ +{ + cssIn: 'main.css', + out: 'main-built.css', + optimizeCss: 'standard.keepLines.keepWhitespace' +} diff --git a/build/tests/lib/cssKeepWhitespace/expected.css b/build/tests/lib/cssKeepWhitespace/expected.css new file mode 100644 index 00000000..ea2af694 --- /dev/null +++ b/build/tests/lib/cssKeepWhitespace/expected.css @@ -0,0 +1,6 @@ +.acss { + width: 1px; +} +.maincss { + width: 1; +} diff --git a/build/tests/lib/cssKeepWhitespace/main.css b/build/tests/lib/cssKeepWhitespace/main.css new file mode 100644 index 00000000..93f741f0 --- /dev/null +++ b/build/tests/lib/cssKeepWhitespace/main.css @@ -0,0 +1,8 @@ +@import url(a.css); +/* +This is a main.css comment +*/ + +.maincss { + width: 1; +} From 9a35b98325671a3b9c1b6491c8996b38c6001924 Mon Sep 17 00:00:00 2001 From: Lukasz Kryger Date: Tue, 12 Nov 2013 14:44:36 +0000 Subject: [PATCH 080/382] modul -> module --- build/example.build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/example.build.js b/build/example.build.js index 1e1d6e87..c8269b31 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -339,7 +339,7 @@ { name: "foo/bar/bop", - //create: true can be used to create the modul layer at the given + //create: true can be used to create the module layer at the given //name, if it does not already exist in the source location. If //there is a module at the source location with this name, then //create: true is superfluous. From 49e2f0b6495e439f707f408278288843a3f243ab Mon Sep 17 00:00:00 2001 From: Eudis Duran Date: Wed, 13 Nov 2013 12:06:15 -0500 Subject: [PATCH 081/382] Small comment fixes --- build/example.build.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/example.build.js b/build/example.build.js index 1e1d6e87..00cd5579 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -101,9 +101,9 @@ //Introduced in 2.1.2 and considered experimental. //If the minifier specified in the "optimize" option supports generating - //source maps for the minfied code, then generate them. The source maps + //source maps for the minified code, then generate them. The source maps //generated only translate minified JS to non-minified JS, it does not do - //anything magical for translating minfied JS to transpiled source code. + //anything magical for translating minified JS to transpiled source code. //Currently only optimize: "uglify2" is supported when running in node or //rhino, and if running in rhino, "closure" with a closure compiler jar //build after r1592 (20111114 release). @@ -339,7 +339,7 @@ { name: "foo/bar/bop", - //create: true can be used to create the modul layer at the given + //create: true can be used to create the module layer at the given //name, if it does not already exist in the source location. If //there is a module at the source location with this name, then //create: true is superfluous. @@ -538,7 +538,7 @@ data.path: the bundle path relative to the output directory. data.included: an array of items included in the build bundle. If a file path, it is relative to the output directory. Loader - plugin IDs are also included in this array, but dependending + plugin IDs are also included in this array, but depending on the plugin, may or may not have something inlined in the module bundle. */ From 42d8a033c6edb1219b70a6505dfa84054e09b899 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 17 Nov 2013 20:40:36 -0800 Subject: [PATCH 082/382] Fixes jrburke/requirejs#942, error out if build layer sourcePath and buildPath are the same. --- build/jslib/build.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/build/jslib/build.js b/build/jslib/build.js index 575d73c7..4047d039 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -344,6 +344,18 @@ define(function (require) { modules.forEach(function (module) { if (module.name) { module._buildPath = buildContext.nameToUrl(module.name, null); + + //If buildPath and sourcePath are the same, throw since this + //would result in modifying source. This condition can happen + //with some more tricky paths: config and appDir/baseUrl + //setting, which is a sign of incorrect config. + if (module._buildPath === module._sourcePath) { + throw new Error('Module ID \'' + module.name + + '\' has a source path that is same as output path: ' + + module._sourcePath + + '. Stopping, config is malformed.'); + } + if (!module.create) { file.copyFile(module._sourcePath, module._buildPath); } From 014dd9daa7e05efc09e35c705ccbaa4032166e2c Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 17 Nov 2013 20:42:11 -0800 Subject: [PATCH 083/382] add + for after release, update snapshot --- build/jslib/x.js | 4 +-- dist/r.js | 82 +++++++++++++++++++++++++++--------------------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 43bcb618..7145f0b3 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9 Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9', + version = '2.1.9+', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index 309ceaf3..a4342554 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Mon, 18 Nov 2013 04:41:40 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9', + version = '2.1.9+ Mon, 18 Nov 2013 04:41:40 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -2302,7 +2302,7 @@ var requirejs, require, define, xpcUtil; if (env === 'browser') { /** - * @license RequireJS rhino Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS rhino Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -2331,7 +2331,7 @@ var requirejs, require, define, xpcUtil; }()); } else if (env === 'rhino') { /** - * @license RequireJS rhino Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS rhino Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -2355,7 +2355,7 @@ var requirejs, require, define, xpcUtil; require.nodeRequire = nodeRequire; /** - * @license RequireJS node Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS node Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -2569,7 +2569,7 @@ var requirejs, require, define, xpcUtil; */ function loadLib() { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -2622,7 +2622,7 @@ var requirejs, require, define, xpcUtil; } }); }());/** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -2999,7 +2999,7 @@ var prim; }()); if(env === 'browser') { /** - * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3016,7 +3016,7 @@ define('browser/assert', function () { if(env === 'node') { /** - * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3033,7 +3033,7 @@ define('node/assert', ['assert'], function (assert) { if(env === 'rhino') { /** - * @license RequireJS Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3067,7 +3067,7 @@ define('xpconnect/assert', function () { if(env === 'browser') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3084,7 +3084,7 @@ define('browser/args', function () { if(env === 'node') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3108,7 +3108,7 @@ define('node/args', function () { if(env === 'rhino') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3158,7 +3158,7 @@ define('xpconnect/args', function () { if(env === 'browser') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3178,7 +3178,7 @@ define('browser/load', ['./file'], function (file) { if(env === 'node') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3199,7 +3199,7 @@ define('node/load', ['fs'], function (fs) { if(env === 'rhino') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3231,7 +3231,7 @@ define('xpconnect/load', function () { if(env === 'browser') { /** - * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3409,7 +3409,7 @@ define('browser/file', ['prim'], function (prim) { if(env === 'node') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -3719,7 +3719,7 @@ define('node/file', ['fs', 'path', 'prim'], function (fs, path, prim) { if(env === 'rhino') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -4333,7 +4333,7 @@ define('xpconnect/quit', function () { if(env === 'browser') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -4353,7 +4353,7 @@ define('browser/print', function () { if(env === 'node') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -4373,7 +4373,7 @@ define('node/print', function () { if(env === 'rhino') { /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -4403,7 +4403,7 @@ define('xpconnect/print', function () { } /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -8373,7 +8373,7 @@ parseStatement: true, parseSourceElement: true */ })); /* vim: set sw=4 ts=4 et tw=80 : */ /** - * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -21127,7 +21127,7 @@ exports.describe_ast = function() { }); /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -22053,7 +22053,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { return parse; }); /** - * @license Copyright (c) 2012, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2012-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -22471,7 +22471,7 @@ function (esprima, parse, logger, lang) { return transform; }); /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -22736,7 +22736,7 @@ define('pragma', ['parse', 'logger'], function (parse, logger) { }); if(env === 'browser') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -22750,7 +22750,7 @@ define('browser/optimize', {}); if(env === 'node') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -22764,7 +22764,7 @@ define('node/optimize', {}); if(env === 'rhino') { /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -22940,7 +22940,7 @@ if(env === 'xpconnect') { define('xpconnect/optimize', {}); } /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -23412,7 +23412,7 @@ function (lang, logger, envOptimize, file, parse, return optimize; }); /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -23884,7 +23884,7 @@ define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'c }; }); /** - * @license RequireJS Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license RequireJS Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -23988,7 +23988,7 @@ define('commonJs', ['env!env/file', 'parse'], function (file, parse) { return commonJs; }); /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -24333,6 +24333,18 @@ define('build', function (require) { modules.forEach(function (module) { if (module.name) { module._buildPath = buildContext.nameToUrl(module.name, null); + + //If buildPath and sourcePath are the same, throw since this + //would result in modifying source. This condition can happen + //with some more tricky paths: config and appDir/baseUrl + //setting, which is a sign of incorrect config. + if (module._buildPath === module._sourcePath) { + throw new Error('Module ID \'' + module.name + + '\' has a source path that is same as output path: ' + + module._sourcePath + + '. Stopping, config is malformed.'); + } + if (!module.create) { file.copyFile(module._sourcePath, module._buildPath); } @@ -25983,7 +25995,7 @@ define('build', function (require) { loadLib(); /** - * @license Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved. + * @license Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ From 1a2208cd64327179c0ba40e5ca0a4c1b6a2811e5 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 18 Nov 2013 12:29:14 -0800 Subject: [PATCH 084/382] require.js update for jrburke/requirejs#925 --- dist/r.js | 25 +++++++++++++++++-------- require.js | 21 +++++++++++++++------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/dist/r.js b/dist/r.js index a4342554..c4aa2b43 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9+ Mon, 18 Nov 2013 04:41:40 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Mon, 18 Nov 2013 20:28:43 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9+ Mon, 18 Nov 2013 04:41:40 GMT', + version = '2.1.9+ Mon, 18 Nov 2013 20:28:43 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.9+ 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 */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.9', + version = '2.1.9+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -787,7 +787,7 @@ var requirejs, require, define, xpcUtil; //local var ref to defQueue, so cannot just reassign the one //on context. apsp.apply(defQueue, - [defQueue.length - 1, 0].concat(globalDefQueue)); + [defQueue.length, 0].concat(globalDefQueue)); globalDefQueue = []; } } @@ -867,7 +867,7 @@ var requirejs, require, define, xpcUtil; } function checkLoaded() { - var map, modId, err, usingPathFallback, + var err, usingPathFallback, waitInterval = config.waitSeconds * 1000, //It is possible to disable the wait interval by using waitSeconds of 0. expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), @@ -885,8 +885,8 @@ var requirejs, require, define, xpcUtil; //Figure out the state of all the modules. eachProp(enabledRegistry, function (mod) { - map = mod.map; - modId = map.id; + var map = mod.map, + modId = map.id; //Skip things that are not enabled or in error state. if (!mod.enabled) { @@ -1708,6 +1708,15 @@ var requirejs, require, define, xpcUtil; delete urlFetched[map.url]; delete undefEvents[id]; + //Clean queued defines too. Go backwards + //in array so that the splices do not + //mess up the iteration. + eachReverse(defQueue, function(args, i) { + if(args[0] === id) { + defQueue.splice(i, 1); + } + }); + if (mod) { //Hold on to listeners in case the //module will be attempted to be reloaded diff --git a/require.js b/require.js index 2ce09b5e..267b7690 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.9 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.9+ 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 */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.9', + version = '2.1.9+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -548,7 +548,7 @@ var requirejs, require, define; //local var ref to defQueue, so cannot just reassign the one //on context. apsp.apply(defQueue, - [defQueue.length - 1, 0].concat(globalDefQueue)); + [defQueue.length, 0].concat(globalDefQueue)); globalDefQueue = []; } } @@ -628,7 +628,7 @@ var requirejs, require, define; } function checkLoaded() { - var map, modId, err, usingPathFallback, + var err, usingPathFallback, waitInterval = config.waitSeconds * 1000, //It is possible to disable the wait interval by using waitSeconds of 0. expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), @@ -646,8 +646,8 @@ var requirejs, require, define; //Figure out the state of all the modules. eachProp(enabledRegistry, function (mod) { - map = mod.map; - modId = map.id; + var map = mod.map, + modId = map.id; //Skip things that are not enabled or in error state. if (!mod.enabled) { @@ -1469,6 +1469,15 @@ var requirejs, require, define; delete urlFetched[map.url]; delete undefEvents[id]; + //Clean queued defines too. Go backwards + //in array so that the splices do not + //mess up the iteration. + eachReverse(defQueue, function(args, i) { + if(args[0] === id) { + defQueue.splice(i, 1); + } + }); + if (mod) { //Hold on to listeners in case the //module will be attempted to be reloaded From 0e263d42e6b67bc084988c9f513ad14379b87050 Mon Sep 17 00:00:00 2001 From: Aleksandr Gornostal Date: Mon, 2 Dec 2013 13:02:21 +0200 Subject: [PATCH 085/382] Fixed bug in makeRelativeFilePath() - targetPath wasn't normalized --- build/jslib/build.js | 2 +- build/tests/buildUtils.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 4047d039..1fe4b21f 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -864,7 +864,7 @@ define(function (require) { build.makeRelativeFilePath = function (refPath, targetPath) { var i, dotLength, finalParts, length, refParts = refPath.split('/'), - targetParts = targetPath.split('/'), + targetParts = file.normalize(targetPath).split('/'), //Pull off file name targetName = targetParts.pop(), dotParts = []; diff --git a/build/tests/buildUtils.js b/build/tests/buildUtils.js index e6a163ba..99bd0ada 100644 --- a/build/tests/buildUtils.js +++ b/build/tests/buildUtils.js @@ -139,6 +139,10 @@ define(['build'], function (build) { t.is('../../../Applications/foo/', build.makeRelativeFilePath('/Users/some/thing/', '/Applications/foo/')); + + t.is('modules/player.js', + build.makeRelativeFilePath('/some/other/www-built/js/app/main.js', + '/some/other/www-built/js/main/lib/../../app/modules/player.js')); } ]); doh.run(); From a2cf7c4168cf271ce5189fca658571cae201cf74 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 16 Dec 2013 17:04:50 -0800 Subject: [PATCH 086/382] Fixes #587, reset _buildPathToModuleIndex between runs --- build/jslib/build.js | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 4047d039..2749c226 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -11,7 +11,7 @@ define(function (require) { 'use strict'; - var build, buildBaseConfig, + var build, lang = require('lang'), prim = require('prim'), logger = require('logger'), @@ -57,22 +57,24 @@ define(function (require) { } }; - buildBaseConfig = { - appDir: "", - pragmas: {}, - paths: {}, - optimize: "uglify", - optimizeCss: "standard.keepLines", - inlineText: true, - isBuild: true, - optimizeAllPluginResources: false, - findNestedDependencies: false, - preserveLicenseComments: true, - //By default, all files/directories are copied, unless - //they match this regexp, by default just excludes .folders - dirExclusionRegExp: file.dirExclusionRegExp, - _buildPathToModuleIndex: {} - }; + function makeBuildBaseConfig() { + return { + appDir: "", + pragmas: {}, + paths: {}, + optimize: "uglify", + optimizeCss: "standard.keepLines", + inlineText: true, + isBuild: true, + optimizeAllPluginResources: false, + findNestedDependencies: false, + preserveLicenseComments: true, + //By default, all files/directories are copied, unless + //they match this regexp, by default just excludes .folders + dirExclusionRegExp: file.dirExclusionRegExp, + _buildPathToModuleIndex: {} + }; + } /** * Some JS may not be valid if concatenated with other JS, in particular @@ -988,8 +990,10 @@ define(function (require) { */ build.createConfig = function (cfg) { /*jslint evil: true */ - var config = {}, buildFileContents, buildFileConfig, mainConfig, - mainConfigFile, mainConfigPath, buildFile, absFilePath; + var buildFileContents, buildFileConfig, mainConfig, + mainConfigFile, mainConfigPath, buildFile, absFilePath, + config = {}, + buildBaseConfig = makeBuildBaseConfig(); //Make sure all paths are relative to current directory. absFilePath = file.absPath('.'); From 3f46b1f2df9e6287737c48c9ce9b5773f0887681 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 16 Dec 2013 17:05:03 -0800 Subject: [PATCH 087/382] snapshot --- dist/r.js | 46 +++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/dist/r.js b/dist/r.js index c4aa2b43..c7c90afc 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9+ Mon, 18 Nov 2013 20:28:43 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Tue, 17 Dec 2013 01:04:57 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9+ Mon, 18 Nov 2013 20:28:43 GMT', + version = '2.1.9+ Tue, 17 Dec 2013 01:04:57 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24009,7 +24009,7 @@ define('commonJs', ['env!env/file', 'parse'], function (file, parse) { define('build', function (require) { 'use strict'; - var build, buildBaseConfig, + var build, lang = require('lang'), prim = require('prim'), logger = require('logger'), @@ -24055,22 +24055,24 @@ define('build', function (require) { } }; - buildBaseConfig = { - appDir: "", - pragmas: {}, - paths: {}, - optimize: "uglify", - optimizeCss: "standard.keepLines", - inlineText: true, - isBuild: true, - optimizeAllPluginResources: false, - findNestedDependencies: false, - preserveLicenseComments: true, - //By default, all files/directories are copied, unless - //they match this regexp, by default just excludes .folders - dirExclusionRegExp: file.dirExclusionRegExp, - _buildPathToModuleIndex: {} - }; + function makeBuildBaseConfig() { + return { + appDir: "", + pragmas: {}, + paths: {}, + optimize: "uglify", + optimizeCss: "standard.keepLines", + inlineText: true, + isBuild: true, + optimizeAllPluginResources: false, + findNestedDependencies: false, + preserveLicenseComments: true, + //By default, all files/directories are copied, unless + //they match this regexp, by default just excludes .folders + dirExclusionRegExp: file.dirExclusionRegExp, + _buildPathToModuleIndex: {} + }; + } /** * Some JS may not be valid if concatenated with other JS, in particular @@ -24986,8 +24988,10 @@ define('build', function (require) { */ build.createConfig = function (cfg) { /*jslint evil: true */ - var config = {}, buildFileContents, buildFileConfig, mainConfig, - mainConfigFile, mainConfigPath, buildFile, absFilePath; + var buildFileContents, buildFileConfig, mainConfig, + mainConfigFile, mainConfigPath, buildFile, absFilePath, + config = {}, + buildBaseConfig = makeBuildBaseConfig(); //Make sure all paths are relative to current directory. absFilePath = file.absPath('.'); From 4120052392d0ee0749ca6855579aa46097562d0e Mon Sep 17 00:00:00 2001 From: "S. Andrew Sheppard" Date: Mon, 16 Dec 2013 20:49:01 -0600 Subject: [PATCH 088/382] don't add cssPrefix to URLs starting with '#' --- build/jslib/optimize.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index a7714d38..2ca5dcfd 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -43,15 +43,16 @@ function (lang, logger, envOptimize, file, parse, function fixCssUrlPaths(fileName, path, contents, cssPrefix) { return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { - var colonIndex, parts, i, + var colonIndex, firstChar, parts, i, fixedUrlMatch = cleanCssUrlQuotes(urlMatch); fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); - //Only do the work for relative URLs. Skip things that start with / or have + //Only do the work for relative URLs. Skip things that start with / or #, or have //a protocol. + firstChar = fixedUrlMatch.charAt(0); colonIndex = fixedUrlMatch.indexOf(":"); - if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + if (firstChar !== "/" && firstChar !== "#" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { //It is a relative URL, tack on the cssPrefix and path prefix urlMatch = cssPrefix + path + fixedUrlMatch; From 4d353c9d326e73de7693612bcfcfd3c5ce196fbc Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 30 Dec 2013 19:35:38 -0800 Subject: [PATCH 089/382] snapshot --- dist/r.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index c7c90afc..1ead44f9 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9+ Tue, 17 Dec 2013 01:04:57 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Tue, 31 Dec 2013 03:35:30 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9+ Tue, 17 Dec 2013 01:04:57 GMT', + version = '2.1.9+ Tue, 31 Dec 2013 03:35:30 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -23276,6 +23276,20 @@ function (lang, logger, envOptimize, file, parse, fileContents = fileContents.replace(/(\r\n)+/g, "\r\n"); fileContents = fileContents.replace(/(\n)+/g, "\n"); } + //Remove unnecessary whitespace + if (config.optimizeCss.indexOf(".keepWhitespace") === -1) { + //Remove leading and trailing whitespace from lines + fileContents = fileContents.replace(/^[ \t]+/gm, ""); + fileContents = fileContents.replace(/[ \t]+$/gm, ""); + //Remove whitespace after semicolon, colon, curly brackets and commas + fileContents = fileContents.replace(/(;|:|\{|}|,)[ \t]+/g, "$1"); + //Remove whitespace before opening curly brackets + fileContents = fileContents.replace(/[ \t]+(\{)/g, "$1"); + //Truncate double whitespace + fileContents = fileContents.replace(/([ \t])+/g, "$1"); + //Remove empty lines + fileContents = fileContents.replace(/^[ \t]*[\r\n]/gm,''); + } } catch (e) { fileContents = originalFileContents; logger.error("Could not optimized CSS file: " + fileName + ", error: " + e); @@ -24061,7 +24075,7 @@ define('build', function (require) { pragmas: {}, paths: {}, optimize: "uglify", - optimizeCss: "standard.keepLines", + optimizeCss: "standard.keepLines.keepWhitespace", inlineText: true, isBuild: true, optimizeAllPluginResources: false, From 87ba6daa4bb72aabb13621424aa22e3a5bb20a88 Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 31 Dec 2013 00:09:19 -0800 Subject: [PATCH 090/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 1ead44f9..25913f9d 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9+ Tue, 31 Dec 2013 03:35:30 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Tue, 31 Dec 2013 08:07:36 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9+ Tue, 31 Dec 2013 03:35:30 GMT', + version = '2.1.9+ Tue, 31 Dec 2013 08:07:36 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24878,7 +24878,7 @@ define('build', function (require) { build.makeRelativeFilePath = function (refPath, targetPath) { var i, dotLength, finalParts, length, refParts = refPath.split('/'), - targetParts = targetPath.split('/'), + targetParts = file.normalize(targetPath).split('/'), //Pull off file name targetName = targetParts.pop(), dotParts = []; From d395438a5d703d278d3ece1f10bfd31b0e7c1c3b Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 31 Dec 2013 15:08:10 -0800 Subject: [PATCH 091/382] requirejs update --- require.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/require.js b/require.js index 267b7690..4925f805 100644 --- a/require.js +++ b/require.js @@ -108,7 +108,10 @@ var requirejs, require, define; if (source) { eachProp(source, function (value, prop) { if (force || !hasProp(target, prop)) { - if (deepStringMixin && typeof value !== 'string') { + if (deepStringMixin && typeof value === 'object' && value && + !isArray(value) && !isFunction(value) && + !(value instanceof RegExp)) { + if (!target[prop]) { target[prop] = {}; } @@ -1261,14 +1264,10 @@ var requirejs, require, define; eachProp(cfg, function (value, prop) { if (objs[prop]) { - if (prop === 'map') { - if (!config.map) { - config.map = {}; - } - mixin(config[prop], value, true, true); - } else { - mixin(config[prop], value, true); + if (!config[prop]) { + config[prop] = {}; } + mixin(config[prop], value, true, true); } else { config[prop] = value; } From 5ce1eb98239f0af828633f57604f7aa9164dc91a Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 4 Jan 2014 15:02:04 -0800 Subject: [PATCH 092/382] Related to #981: better error message for missing plugin resources. --- build/jslib/build.js | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 94287ca1..dec9f175 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1451,7 +1451,7 @@ define(function (require) { build.checkForErrors = function (context) { //Check to see if it all loaded. If not, then throw, and give //a message on what is left. - var id, prop, mod, idParts, pluginId, + var id, prop, mod, idParts, pluginId, pluginResources, errMessage = '', failedPluginMap = {}, failedPluginIds = [], @@ -1464,6 +1464,11 @@ define(function (require) { registry = context.registry; function populateErrUrlMap(id, errUrl, skipNew) { + // Loader plugins do not have an errUrl, so skip them. + if (!errUrl) { + return; + } + if (!skipNew) { errIds.push(id); } @@ -1487,17 +1492,24 @@ define(function (require) { if (hasProp(registry, id) && id.indexOf('_@r') !== 0) { hasUndefined = true; mod = getOwn(registry, id); + idParts = id.split('!'); + pluginId = idParts[0]; if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) { populateErrUrlMap(id, mod.map.url); } //Look for plugins that did not call load() - idParts = id.split('!'); - pluginId = idParts[0]; - if (idParts.length > 1 && falseProp(failedPluginMap, pluginId)) { - failedPluginIds.push(pluginId); - failedPluginMap[pluginId] = true; + + if (idParts.length > 1) { + if (falseProp(failedPluginMap, pluginId)) { + failedPluginIds.push(pluginId); + } + pluginResources = failedPluginMap[pluginId]; + if (!pluginResources) { + pluginResources = failedPluginMap[pluginId] = []; + } + pluginResources.push(id + (mod.error ? ': ' + mod.error : '')); } } } @@ -1517,8 +1529,11 @@ define(function (require) { errMessage += 'Loader plugin' + (failedPluginIds.length === 1 ? '' : 's') + ' did not call ' + - 'the load callback in the build: ' + - failedPluginIds.join(', ') + '\n'; + 'the load callback in the build:\n' + + failedPluginIds.map(function (pluginId) { + var pluginResources = failedPluginMap[pluginId]; + return pluginId + ':\n ' + pluginResources.join('\n '); + }).join('\n') + '\n'; } errMessage += 'Module loading did not complete for: ' + errIds.join(', '); From 77237e59726ace5da76efb1a1e2eb16c9eec8fb0 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 4 Jan 2014 15:02:17 -0800 Subject: [PATCH 093/382] snapshot --- dist/r.js | 74 +++++++++++++++++++++++++++++++----------------------- require.js | 17 ++++++------- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/dist/r.js b/dist/r.js index 25913f9d..ae2ae8d4 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9+ Tue, 31 Dec 2013 08:07:36 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Sat, 04 Jan 2014 23:02:08 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9+ Tue, 31 Dec 2013 08:07:36 GMT', + version = '2.1.9+ Sat, 04 Jan 2014 23:02:08 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -347,7 +347,10 @@ var requirejs, require, define, xpcUtil; if (source) { eachProp(source, function (value, prop) { if (force || !hasProp(target, prop)) { - if (deepStringMixin && typeof value !== 'string') { + if (deepStringMixin && typeof value === 'object' && value && + !isArray(value) && !isFunction(value) && + !(value instanceof RegExp)) { + if (!target[prop]) { target[prop] = {}; } @@ -826,7 +829,7 @@ var requirejs, require, define, xpcUtil; getOwn(config.config, mod.map.id); return c || {}; }, - exports: defined[mod.map.id] + exports: handlers.exports(mod) }); } } @@ -1109,17 +1112,14 @@ var requirejs, require, define, xpcUtil; exports = context.execCb(id, factory, depExports, exports); } - if (this.map.isDefine) { - //If setting exports via 'module' is in play, - //favor that over return value and exports. After that, - //favor a non-undefined return value over exports use. + // Favor return value over exports. If node/cjs in play, + // then will not have a return value anyway. Favor + // module.exports assignment over exports object. + if (this.map.isDefine && exports === undefined) { cjsModule = this.module; - if (cjsModule && - cjsModule.exports !== undefined && - //Make sure it is not already the exports value - cjsModule.exports !== this.exports) { + if (cjsModule) { exports = cjsModule.exports; - } else if (exports === undefined && this.usingExports) { + } else if (this.usingExports) { //exports already set the defined value. exports = this.exports; } @@ -1500,14 +1500,10 @@ var requirejs, require, define, xpcUtil; eachProp(cfg, function (value, prop) { if (objs[prop]) { - if (prop === 'map') { - if (!config.map) { - config.map = {}; - } - mixin(config[prop], value, true, true); - } else { - mixin(config[prop], value, true); + if (!config[prop]) { + config[prop] = {}; } + mixin(config[prop], value, true, true); } else { config[prop] = value; } @@ -22993,15 +22989,16 @@ function (lang, logger, envOptimize, file, parse, function fixCssUrlPaths(fileName, path, contents, cssPrefix) { return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { - var colonIndex, parts, i, + var colonIndex, firstChar, parts, i, fixedUrlMatch = cleanCssUrlQuotes(urlMatch); fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); - //Only do the work for relative URLs. Skip things that start with / or have + //Only do the work for relative URLs. Skip things that start with / or #, or have //a protocol. + firstChar = fixedUrlMatch.charAt(0); colonIndex = fixedUrlMatch.indexOf(":"); - if (fixedUrlMatch.charAt(0) !== "/" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + if (firstChar !== "/" && firstChar !== "#" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { //It is a relative URL, tack on the cssPrefix and path prefix urlMatch = cssPrefix + path + fixedUrlMatch; @@ -25463,7 +25460,7 @@ define('build', function (require) { build.checkForErrors = function (context) { //Check to see if it all loaded. If not, then throw, and give //a message on what is left. - var id, prop, mod, idParts, pluginId, + var id, prop, mod, idParts, pluginId, pluginResources, errMessage = '', failedPluginMap = {}, failedPluginIds = [], @@ -25476,6 +25473,11 @@ define('build', function (require) { registry = context.registry; function populateErrUrlMap(id, errUrl, skipNew) { + // Loader plugins do not have an errUrl, so skip them. + if (!errUrl) { + return; + } + if (!skipNew) { errIds.push(id); } @@ -25499,17 +25501,24 @@ define('build', function (require) { if (hasProp(registry, id) && id.indexOf('_@r') !== 0) { hasUndefined = true; mod = getOwn(registry, id); + idParts = id.split('!'); + pluginId = idParts[0]; if (id.indexOf('_unnormalized') === -1 && mod && mod.enabled) { populateErrUrlMap(id, mod.map.url); } //Look for plugins that did not call load() - idParts = id.split('!'); - pluginId = idParts[0]; - if (idParts.length > 1 && falseProp(failedPluginMap, pluginId)) { - failedPluginIds.push(pluginId); - failedPluginMap[pluginId] = true; + + if (idParts.length > 1) { + if (falseProp(failedPluginMap, pluginId)) { + failedPluginIds.push(pluginId); + } + pluginResources = failedPluginMap[pluginId]; + if (!pluginResources) { + pluginResources = failedPluginMap[pluginId] = []; + } + pluginResources.push(id + (mod.error ? ': ' + mod.error : '')); } } } @@ -25529,8 +25538,11 @@ define('build', function (require) { errMessage += 'Loader plugin' + (failedPluginIds.length === 1 ? '' : 's') + ' did not call ' + - 'the load callback in the build: ' + - failedPluginIds.join(', ') + '\n'; + 'the load callback in the build:\n' + + failedPluginIds.map(function (pluginId) { + var pluginResources = failedPluginMap[pluginId]; + return pluginId + ':\n ' + pluginResources.join('\n '); + }).join('\n') + '\n'; } errMessage += 'Module loading did not complete for: ' + errIds.join(', '); diff --git a/require.js b/require.js index 4925f805..026fd489 100644 --- a/require.js +++ b/require.js @@ -590,7 +590,7 @@ var requirejs, require, define; getOwn(config.config, mod.map.id); return c || {}; }, - exports: defined[mod.map.id] + exports: handlers.exports(mod) }); } } @@ -873,17 +873,14 @@ var requirejs, require, define; exports = context.execCb(id, factory, depExports, exports); } - if (this.map.isDefine) { - //If setting exports via 'module' is in play, - //favor that over return value and exports. After that, - //favor a non-undefined return value over exports use. + // Favor return value over exports. If node/cjs in play, + // then will not have a return value anyway. Favor + // module.exports assignment over exports object. + if (this.map.isDefine && exports === undefined) { cjsModule = this.module; - if (cjsModule && - cjsModule.exports !== undefined && - //Make sure it is not already the exports value - cjsModule.exports !== this.exports) { + if (cjsModule) { exports = cjsModule.exports; - } else if (exports === undefined && this.usingExports) { + } else if (this.usingExports) { //exports already set the defined value. exports = this.exports; } From 6f6a9d3ca1fc8f1523d85744cd833d04ba35ed9d Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 4 Jan 2014 15:28:14 -0800 Subject: [PATCH 094/382] Fixes #594, use lstat instead of stat for deletes --- build/jslib/node/file.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jslib/node/file.js b/build/jslib/node/file.js index b9fb1729..83090d2f 100644 --- a/build/jslib/node/file.js +++ b/build/jslib/node/file.js @@ -262,7 +262,7 @@ define(['fs', 'path', 'prim'], function (fs, path, prim) { //summary: deletes a file or directory if it exists. var files, i, stat; if (file.exists(fileName)) { - stat = fs.statSync(fileName); + stat = fs.lstatSync(fileName); if (stat.isDirectory()) { files = fs.readdirSync(fileName); for (i = 0; i < files.length; i++) { @@ -287,7 +287,7 @@ define(['fs', 'path', 'prim'], function (fs, path, prim) { for (i = 0; i < dirFileArray.length; i++) { fileName = dirFileArray[i]; filePath = path.join(startDir, fileName); - stat = fs.statSync(filePath); + stat = fs.lstatSync(filePath); if (stat.isDirectory()) { file.deleteEmptyDirs(filePath); } From 6c6044ba9f049f5a9412fa13fdff6eddd5600439 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 4 Jan 2014 15:28:39 -0800 Subject: [PATCH 095/382] snapshot --- dist/r.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index ae2ae8d4..89c6ed2a 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.9+ Sat, 04 Jan 2014 23:02:08 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.9+ Sat, 04 Jan 2014 23:28:31 GMT Copyright (c) 2010-2013, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.9+ Sat, 04 Jan 2014 23:02:08 GMT', + version = '2.1.9+ Sat, 04 Jan 2014 23:28:31 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -3677,7 +3677,7 @@ define('node/file', ['fs', 'path', 'prim'], function (fs, path, prim) { //summary: deletes a file or directory if it exists. var files, i, stat; if (file.exists(fileName)) { - stat = fs.statSync(fileName); + stat = fs.lstatSync(fileName); if (stat.isDirectory()) { files = fs.readdirSync(fileName); for (i = 0; i < files.length; i++) { @@ -3702,7 +3702,7 @@ define('node/file', ['fs', 'path', 'prim'], function (fs, path, prim) { for (i = 0; i < dirFileArray.length; i++) { fileName = dirFileArray[i]; filePath = path.join(startDir, fileName); - stat = fs.statSync(filePath); + stat = fs.lstatSync(filePath); if (stat.isDirectory()) { file.deleteEmptyDirs(filePath); } From 94598e7af2acd7a19eb27d818fedc2b5e5411e46 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 4 Jan 2014 21:24:42 -0800 Subject: [PATCH 096/382] Fixes #595, updates uglify to latest version, uses new method to embed uglifyjs to preserve files better --- build/jslib/source-map/source-map-consumer.js | 106 +- build/jslib/uglifyjs2.js | 12438 +++++++++------- build/jslib/uglifyjs2/README.md | 10 +- build/jslib/uglifyjs2/combine.js | 41 +- build/jslib/uglifyjs2/generate.sh | 9 +- build/jslib/uglifyjs2/post.txt | 126 - build/jslib/x.js | 2 +- 7 files changed, 7020 insertions(+), 5712 deletions(-) diff --git a/build/jslib/source-map/source-map-consumer.js b/build/jslib/source-map/source-map-consumer.js index a5bc2c49..0ac6d931 100644 --- a/build/jslib/source-map/source-map-consumer.js +++ b/build/jslib/source-map/source-map-consumer.js @@ -50,13 +50,17 @@ define(function (require, exports, module) { var version = util.getArg(sourceMap, 'version'); var sources = util.getArg(sourceMap, 'sources'); - var names = util.getArg(sourceMap, 'names'); + // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which + // requires the array) to play nice here. + 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', null); - if (version !== this._version) { + // Once again, Sass deviates from the spec and supplies the version as a + // string rather than a number, so we use loose equality checking here. + if (version != this._version) { throw new Error('Unsupported version: ' + version); } @@ -66,36 +70,11 @@ define(function (require, exports, module) { // #72 and bugzil.la/889492. this._names = ArraySet.fromArray(names, true); this._sources = ArraySet.fromArray(sources, true); + this.sourceRoot = sourceRoot; this.sourcesContent = sourcesContent; + this._mappings = mappings; this.file = file; - - // `this._generatedMappings` and `this._originalMappings` hold the parsed - // mapping coordinates from the source map's "mappings" attribute. Each - // object in the array is of the form - // - // { - // generatedLine: The line number in the generated code, - // generatedColumn: The column number in the generated code, - // source: The path to the original source file that generated this - // chunk of code, - // originalLine: The line number in the original source that - // corresponds to this chunk of generated code, - // originalColumn: The column number in the original source that - // corresponds to this chunk of generated code, - // name: The name of the original symbol which generated this chunk of - // code. - // } - // - // All properties except for `generatedLine` and `generatedColumn` can be - // `null`. - // - // `this._generatedMappings` is ordered by the generated positions. - // - // `this._originalMappings` is ordered by the original positions. - this._generatedMappings = []; - this._originalMappings = []; - this._parseMappings(mappings, sourceRoot); } /** @@ -116,9 +95,9 @@ define(function (require, exports, module) { smc.sourceRoot); smc.file = aSourceMap._file; - smc._generatedMappings = aSourceMap._mappings.slice() + smc.__generatedMappings = aSourceMap._mappings.slice() .sort(util.compareByGeneratedPositions); - smc._originalMappings = aSourceMap._mappings.slice() + smc.__originalMappings = aSourceMap._mappings.slice() .sort(util.compareByOriginalPositions); return smc; @@ -140,9 +119,66 @@ define(function (require, exports, module) { } }); + // `__generatedMappings` and `__originalMappings` are arrays that hold the + // parsed mapping coordinates from the source map's "mappings" attribute. They + // are lazily instantiated, accessed via the `_generatedMappings` and + // `_originalMappings` getters respectively, and we only parse the mappings + // and create these arrays once queried for a source location. We jump through + // these hoops because there can be many thousands of mappings, and parsing + // them is expensive, so we only want to do it if we must. + // + // Each object in the arrays 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`. + // + // `_generatedMappings` is ordered by the generated positions. + // + // `_originalMappings` is ordered by the original positions. + + SourceMapConsumer.prototype.__generatedMappings = null; + Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { + get: function () { + if (!this.__generatedMappings) { + this.__generatedMappings = []; + this.__originalMappings = []; + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__generatedMappings; + } + }); + + SourceMapConsumer.prototype.__originalMappings = null; + Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { + get: function () { + if (!this.__originalMappings) { + this.__generatedMappings = []; + this.__originalMappings = []; + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__originalMappings; + } + }); + /** * Parse the mappings in a string in to a data structure which we can easily - * query (an ordered list in this._generatedMappings). + * query (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). */ SourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { @@ -212,14 +248,14 @@ define(function (require, exports, module) { } } - this._generatedMappings.push(mapping); + this.__generatedMappings.push(mapping); if (typeof mapping.originalLine === 'number') { - this._originalMappings.push(mapping); + this.__originalMappings.push(mapping); } } } - this._originalMappings.sort(util.compareByOriginalPositions); + this.__originalMappings.sort(util.compareByOriginalPositions); }; /** diff --git a/build/jslib/uglifyjs2.js b/build/jslib/uglifyjs2.js index ce535068..acd33e3c 100644 --- a/build/jslib/uglifyjs2.js +++ b/build/jslib/uglifyjs2.js @@ -1,4713 +1,5826 @@ //Distributed under the BSD license: //Copyright 2012 (c) Mihai Bazon define(['exports', 'source-map', 'logger', 'env!env/file'], function (exports, MOZ_SourceMap, logger, rjsFile) { -(function(exports, global) { - global["UglifyJS"] = exports; - "use strict"; - function array_to_hash(a) { - var ret = Object.create(null); - for (var i = 0; i < a.length; ++i) ret[a[i]] = true; - return ret; - } - function slice(a, start) { - return Array.prototype.slice.call(a, start || 0); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +"use strict"; + +function array_to_hash(a) { + var ret = Object.create(null); + for (var i = 0; i < a.length; ++i) + ret[a[i]] = true; + return ret; +}; + +function slice(a, start) { + return Array.prototype.slice.call(a, start || 0); +}; + +function characters(str) { + return str.split(""); +}; + +function member(name, array) { + for (var i = array.length; --i >= 0;) + if (array[i] == name) + return true; + return false; +}; + +function find_if(func, array) { + for (var i = 0, n = array.length; i < n; ++i) { + if (func(array[i])) + return array[i]; } - function characters(str) { - return str.split(""); +}; + +function repeat_string(str, i) { + if (i <= 0) return ""; + if (i == 1) return str; + var d = repeat_string(str, i >> 1); + d += d; + if (i & 1) d += str; + return d; +}; + +function DefaultsError(msg, defs) { + Error.call(this, msg); + this.msg = msg; + this.defs = defs; +}; +DefaultsError.prototype = Object.create(Error.prototype); +DefaultsError.prototype.constructor = DefaultsError; + +DefaultsError.croak = function(msg, defs) { + throw new DefaultsError(msg, defs); +}; + +function defaults(args, defs, croak) { + if (args === true) + args = {}; + var ret = args || {}; + if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i)) + DefaultsError.croak("`" + i + "` is not a supported option", defs); + for (var i in defs) if (defs.hasOwnProperty(i)) { + ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i]; } - function member(name, array) { - for (var i = array.length; --i >= 0; ) if (array[i] == name) return true; - return false; + return ret; +}; + +function merge(obj, ext) { + for (var i in ext) if (ext.hasOwnProperty(i)) { + obj[i] = ext[i]; } - function find_if(func, array) { - for (var i = 0, n = array.length; i < n; ++i) { - if (func(array[i])) return array[i]; + return obj; +}; + +function noop() {}; + +var MAP = (function(){ + function MAP(a, f, backwards) { + var ret = [], top = [], i; + function doit() { + var val = f(a[i], i); + var is_last = val instanceof Last; + if (is_last) val = val.v; + if (val instanceof AtTop) { + val = val.v; + if (val instanceof Splice) { + top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); + } else { + top.push(val); + } + } + else if (val !== skip) { + if (val instanceof Splice) { + ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); + } else { + ret.push(val); + } + } + return is_last; + }; + if (a instanceof Array) { + if (backwards) { + for (i = a.length; --i >= 0;) if (doit()) break; + ret.reverse(); + top.reverse(); + } else { + for (i = 0; i < a.length; ++i) if (doit()) break; + } } + else { + for (i in a) if (a.hasOwnProperty(i)) if (doit()) break; + } + return top.concat(ret); + }; + MAP.at_top = function(val) { return new AtTop(val) }; + MAP.splice = function(val) { return new Splice(val) }; + MAP.last = function(val) { return new Last(val) }; + var skip = MAP.skip = {}; + function AtTop(val) { this.v = val }; + function Splice(val) { this.v = val }; + function Last(val) { this.v = val }; + return MAP; +})(); + +function push_uniq(array, el) { + if (array.indexOf(el) < 0) + array.push(el); +}; + +function string_template(text, props) { + return text.replace(/\{(.+?)\}/g, function(str, p){ + return props[p]; + }); +}; + +function remove(array, el) { + for (var i = array.length; --i >= 0;) { + if (array[i] === el) array.splice(i, 1); + } +}; + +function mergeSort(array, cmp) { + if (array.length < 2) return array.slice(); + function merge(a, b) { + var r = [], ai = 0, bi = 0, i = 0; + while (ai < a.length && bi < b.length) { + cmp(a[ai], b[bi]) <= 0 + ? r[i++] = a[ai++] + : r[i++] = b[bi++]; + } + if (ai < a.length) r.push.apply(r, a.slice(ai)); + if (bi < b.length) r.push.apply(r, b.slice(bi)); + return r; + }; + function _ms(a) { + if (a.length <= 1) + return a; + var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); + left = _ms(left); + right = _ms(right); + return merge(left, right); + }; + return _ms(array); +}; + +function set_difference(a, b) { + return a.filter(function(el){ + return b.indexOf(el) < 0; + }); +}; + +function set_intersection(a, b) { + return a.filter(function(el){ + return b.indexOf(el) >= 0; + }); +}; + +// this function is taken from Acorn [1], written by Marijn Haverbeke +// [1] https://github.com/marijnh/acorn +function makePredicate(words) { + if (!(words instanceof Array)) words = words.split(" "); + var f = "", cats = []; + out: for (var i = 0; i < words.length; ++i) { + for (var j = 0; j < cats.length; ++j) + if (cats[j][0].length == words[i].length) { + cats[j].push(words[i]); + continue out; + } + cats.push([words[i]]); } - function repeat_string(str, i) { - if (i <= 0) return ""; - if (i == 1) return str; - var d = repeat_string(str, i >> 1); - d += d; - if (i & 1) d += str; - return d; + function compareTo(arr) { + if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; + f += "switch(str){"; + for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; + f += "return true}return false;"; } - function DefaultsError(msg, defs) { - this.msg = msg; - this.defs = defs; + // When there are more than three length categories, an outer + // switch first dispatches on the lengths, to save on comparisons. + if (cats.length > 3) { + cats.sort(function(a, b) {return b.length - a.length;}); + f += "switch(str.length){"; + for (var i = 0; i < cats.length; ++i) { + var cat = cats[i]; + f += "case " + cat[0].length + ":"; + compareTo(cat); + } + f += "}"; + // Otherwise, simply generate a flat `switch` statement. + } else { + compareTo(words); } - function defaults(args, defs, croak) { - if (args === true) args = {}; - var ret = args || {}; - if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i)) throw new DefaultsError("`" + i + "` is not a supported option", defs); - for (var i in defs) if (defs.hasOwnProperty(i)) { - ret[i] = args && args.hasOwnProperty(i) ? args[i] : defs[i]; - } + return new Function("str", f); +}; + +function all(array, predicate) { + for (var i = array.length; --i >= 0;) + if (!predicate(array[i])) + return false; + return true; +}; + +function Dictionary() { + this._values = Object.create(null); + this._size = 0; +}; +Dictionary.prototype = { + set: function(key, val) { + if (!this.has(key)) ++this._size; + this._values["$" + key] = val; + return this; + }, + add: function(key, val) { + if (this.has(key)) { + this.get(key).push(val); + } else { + this.set(key, [ val ]); + } + return this; + }, + get: function(key) { return this._values["$" + key] }, + del: function(key) { + if (this.has(key)) { + --this._size; + delete this._values["$" + key]; + } + return this; + }, + has: function(key) { return ("$" + key) in this._values }, + each: function(f) { + for (var i in this._values) + f(this._values[i], i.substr(1)); + }, + size: function() { + return this._size; + }, + map: function(f) { + var ret = []; + for (var i in this._values) + ret.push(f(this._values[i], i.substr(1))); return ret; } - function merge(obj, ext) { - for (var i in ext) if (ext.hasOwnProperty(i)) { - obj[i] = ext[i]; +}; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +"use strict"; + +function DEFNODE(type, props, methods, base) { + if (arguments.length < 4) base = AST_Node; + if (!props) props = []; + else props = props.split(/\s+/); + var self_props = props; + if (base && base.PROPS) + props = props.concat(base.PROPS); + var code = "return function AST_" + type + "(props){ if (props) { "; + for (var i = props.length; --i >= 0;) { + code += "this." + props[i] + " = props." + props[i] + ";"; + } + var proto = base && new base; + if (proto && proto.initialize || (methods && methods.initialize)) + code += "this.initialize();"; + code += "}}"; + var ctor = new Function(code)(); + if (proto) { + ctor.prototype = proto; + ctor.BASE = base; + } + if (base) base.SUBCLASSES.push(ctor); + ctor.prototype.CTOR = ctor; + ctor.PROPS = props || null; + ctor.SELF_PROPS = self_props; + ctor.SUBCLASSES = []; + if (type) { + ctor.prototype.TYPE = ctor.TYPE = type; + } + if (methods) for (i in methods) if (methods.hasOwnProperty(i)) { + if (/^\$/.test(i)) { + ctor[i.substr(1)] = methods[i]; + } else { + ctor.prototype[i] = methods[i]; } - return obj; } - function noop() {} - var MAP = function() { - function MAP(a, f, backwards) { - var ret = [], top = [], i; - function doit() { - var val = f(a[i], i); - var is_last = val instanceof Last; - if (is_last) val = val.v; - if (val instanceof AtTop) { - val = val.v; - if (val instanceof Splice) { - top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); - } else { - top.push(val); - } - } else if (val !== skip) { - if (val instanceof Splice) { - ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); - } else { - ret.push(val); - } + ctor.DEFMETHOD = function(name, method) { + this.prototype[name] = method; + }; + return ctor; +}; + +var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", { +}, null); + +var AST_Node = DEFNODE("Node", "start end", { + clone: function() { + return new this.CTOR(this); + }, + $documentation: "Base class of all AST nodes", + $propdoc: { + start: "[AST_Token] The first token of this node", + end: "[AST_Token] The last token of this node" + }, + _walk: function(visitor) { + return visitor._visit(this); + }, + walk: function(visitor) { + return this._walk(visitor); // not sure the indirection will be any help + } +}, null); + +AST_Node.warn_function = null; +AST_Node.warn = function(txt, props) { + if (AST_Node.warn_function) + AST_Node.warn_function(string_template(txt, props)); +}; + +/* -----[ statements ]----- */ + +var AST_Statement = DEFNODE("Statement", null, { + $documentation: "Base class of all statements", +}); + +var AST_Debugger = DEFNODE("Debugger", null, { + $documentation: "Represents a debugger statement", +}, AST_Statement); + +var AST_Directive = DEFNODE("Directive", "value scope", { + $documentation: "Represents a directive, like \"use strict\";", + $propdoc: { + value: "[string] The value of this directive as a plain string (it's not an AST_String!)", + scope: "[AST_Scope/S] The scope that this directive affects" + }, +}, AST_Statement); + +var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { + $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", + $propdoc: { + body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.body._walk(visitor); + }); + } +}, AST_Statement); + +function walk_body(node, visitor) { + if (node.body instanceof AST_Statement) { + node.body._walk(visitor); + } + else node.body.forEach(function(stat){ + stat._walk(visitor); + }); +}; + +var AST_Block = DEFNODE("Block", "body", { + $documentation: "A body of statements (usually bracketed)", + $propdoc: { + body: "[AST_Statement*] an array of statements" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + walk_body(this, visitor); + }); + } +}, AST_Statement); + +var AST_BlockStatement = DEFNODE("BlockStatement", null, { + $documentation: "A block statement", +}, AST_Block); + +var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { + $documentation: "The empty statement (empty block or simply a semicolon)", + _walk: function(visitor) { + return visitor._visit(this); + } +}, AST_Statement); + +var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { + $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", + $propdoc: { + body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.body._walk(visitor); + }); + } +}, AST_Statement); + +var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { + $documentation: "Statement with a label", + $propdoc: { + label: "[AST_Label] a label definition" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.label._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_StatementWithBody); + +var AST_IterationStatement = DEFNODE("IterationStatement", null, { + $documentation: "Internal class. All loops inherit from it." +}, AST_StatementWithBody); + +var AST_DWLoop = DEFNODE("DWLoop", "condition", { + $documentation: "Base class for do/while statements", + $propdoc: { + condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.condition._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_IterationStatement); + +var AST_Do = DEFNODE("Do", null, { + $documentation: "A `do` statement", +}, AST_DWLoop); + +var AST_While = DEFNODE("While", null, { + $documentation: "A `while` statement", +}, AST_DWLoop); + +var AST_For = DEFNODE("For", "init condition step", { + $documentation: "A `for` statement", + $propdoc: { + init: "[AST_Node?] the `for` initialization code, or null if empty", + condition: "[AST_Node?] the `for` termination clause, or null if empty", + step: "[AST_Node?] the `for` update clause, or null if empty" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + if (this.init) this.init._walk(visitor); + if (this.condition) this.condition._walk(visitor); + if (this.step) this.step._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_IterationStatement); + +var AST_ForIn = DEFNODE("ForIn", "init name object", { + $documentation: "A `for ... in` statement", + $propdoc: { + init: "[AST_Node] the `for/in` initialization code", + name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var", + object: "[AST_Node] the object that we're looping through" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.init._walk(visitor); + this.object._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_IterationStatement); + +var AST_With = DEFNODE("With", "expression", { + $documentation: "A `with` statement", + $propdoc: { + expression: "[AST_Node] the `with` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + this.body._walk(visitor); + }); + } +}, AST_StatementWithBody); + +/* -----[ scope and functions ]----- */ + +var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { + $documentation: "Base class for all statements introducing a lexical scope", + $propdoc: { + directives: "[string*/S] an array of directives declared in this scope", + variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", + functions: "[Object/S] like `variables`, but only lists function declarations", + uses_with: "[boolean/S] tells whether this scope uses the `with` statement", + uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", + parent_scope: "[AST_Scope?/S] link to the parent scope", + enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", + cname: "[integer/S] current index for mangling variables (used internally by the mangler)", + }, +}, AST_Block); + +var AST_Toplevel = DEFNODE("Toplevel", "globals", { + $documentation: "The toplevel scope", + $propdoc: { + globals: "[Object/S] a map of name -> SymbolDef for all undeclared names", + }, + wrap_enclose: function(arg_parameter_pairs) { + var self = this; + var args = []; + var parameters = []; + + arg_parameter_pairs.forEach(function(pair) { + var split = pair.split(":"); + + args.push(split[0]); + parameters.push(split[1]); + }); + + var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ + if (node instanceof AST_Directive && node.value == "$ORIG") { + return MAP.splice(self.body); + } + })); + return wrapped_tl; + }, + wrap_commonjs: function(name, export_all) { + var self = this; + var to_export = []; + if (export_all) { + self.figure_out_scope(); + self.walk(new TreeWalker(function(node){ + if (node instanceof AST_SymbolDeclaration && node.definition().global) { + if (!find_if(function(n){ return n.name == node.name }, to_export)) + to_export.push(node); } - return is_last; - } - if (a instanceof Array) { - if (backwards) { - for (i = a.length; --i >= 0; ) if (doit()) break; - ret.reverse(); - top.reverse(); - } else { - for (i = 0; i < a.length; ++i) if (doit()) break; + })); + } + var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){ + if (node instanceof AST_SimpleStatement) { + node = node.body; + if (node instanceof AST_String) switch (node.getValue()) { + case "$ORIG": + return MAP.splice(self.body); + case "$EXPORTS": + var body = []; + to_export.forEach(function(sym){ + body.push(new AST_SimpleStatement({ + body: new AST_Assign({ + left: new AST_Sub({ + expression: new AST_SymbolRef({ name: "exports" }), + property: new AST_String({ value: sym.name }), + }), + operator: "=", + right: new AST_SymbolRef(sym), + }), + })); + }); + return MAP.splice(body); } - } else { - for (i in a) if (a.hasOwnProperty(i)) if (doit()) break; } - return top.concat(ret); - } - MAP.at_top = function(val) { - return new AtTop(val); - }; - MAP.splice = function(val) { - return new Splice(val); - }; - MAP.last = function(val) { - return new Last(val); - }; - var skip = MAP.skip = {}; - function AtTop(val) { - this.v = val; - } - function Splice(val) { - this.v = val; - } - function Last(val) { - this.v = val; - } - return MAP; - }(); - function push_uniq(array, el) { - if (array.indexOf(el) < 0) array.push(el); + })); + return wrapped_tl; } - function string_template(text, props) { - return text.replace(/\{(.+?)\}/g, function(str, p) { - return props[p]; +}, AST_Scope); + +var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", { + $documentation: "Base class for functions", + $propdoc: { + name: "[AST_SymbolDeclaration?] the name of this function", + argnames: "[AST_SymbolFunarg*] array of function arguments", + uses_arguments: "[boolean/S] tells whether this function accesses the arguments array" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + if (this.name) this.name._walk(visitor); + this.argnames.forEach(function(arg){ + arg._walk(visitor); + }); + walk_body(this, visitor); }); } - function remove(array, el) { - for (var i = array.length; --i >= 0; ) { - if (array[i] === el) array.splice(i, 1); - } +}, AST_Scope); + +var AST_Accessor = DEFNODE("Accessor", null, { + $documentation: "A setter/getter function. The `name` property is always null." +}, AST_Lambda); + +var AST_Function = DEFNODE("Function", null, { + $documentation: "A function expression" +}, AST_Lambda); + +var AST_Defun = DEFNODE("Defun", null, { + $documentation: "A function definition" +}, AST_Lambda); + +/* -----[ JUMPS ]----- */ + +var AST_Jump = DEFNODE("Jump", null, { + $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" +}, AST_Statement); + +var AST_Exit = DEFNODE("Exit", "value", { + $documentation: "Base class for “exits” (`return` and `throw`)", + $propdoc: { + value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" + }, + _walk: function(visitor) { + return visitor._visit(this, this.value && function(){ + this.value._walk(visitor); + }); } - function mergeSort(array, cmp) { - if (array.length < 2) return array.slice(); - function merge(a, b) { - var r = [], ai = 0, bi = 0, i = 0; - while (ai < a.length && bi < b.length) { - cmp(a[ai], b[bi]) <= 0 ? r[i++] = a[ai++] : r[i++] = b[bi++]; - } - if (ai < a.length) r.push.apply(r, a.slice(ai)); - if (bi < b.length) r.push.apply(r, b.slice(bi)); - return r; - } - function _ms(a) { - if (a.length <= 1) return a; - var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); - left = _ms(left); - right = _ms(right); - return merge(left, right); - } - return _ms(array); +}, AST_Jump); + +var AST_Return = DEFNODE("Return", null, { + $documentation: "A `return` statement" +}, AST_Exit); + +var AST_Throw = DEFNODE("Throw", null, { + $documentation: "A `throw` statement" +}, AST_Exit); + +var AST_LoopControl = DEFNODE("LoopControl", "label", { + $documentation: "Base class for loop control statements (`break` and `continue`)", + $propdoc: { + label: "[AST_LabelRef?] the label, or null if none", + }, + _walk: function(visitor) { + return visitor._visit(this, this.label && function(){ + this.label._walk(visitor); + }); } - function set_difference(a, b) { - return a.filter(function(el) { - return b.indexOf(el) < 0; +}, AST_Jump); + +var AST_Break = DEFNODE("Break", null, { + $documentation: "A `break` statement" +}, AST_LoopControl); + +var AST_Continue = DEFNODE("Continue", null, { + $documentation: "A `continue` statement" +}, AST_LoopControl); + +/* -----[ IF ]----- */ + +var AST_If = DEFNODE("If", "condition alternative", { + $documentation: "A `if` statement", + $propdoc: { + condition: "[AST_Node] the `if` condition", + alternative: "[AST_Statement?] the `else` part, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.condition._walk(visitor); + this.body._walk(visitor); + if (this.alternative) this.alternative._walk(visitor); }); } - function set_intersection(a, b) { - return a.filter(function(el) { - return b.indexOf(el) >= 0; +}, AST_StatementWithBody); + +/* -----[ SWITCH ]----- */ + +var AST_Switch = DEFNODE("Switch", "expression", { + $documentation: "A `switch` statement", + $propdoc: { + expression: "[AST_Node] the `switch` “discriminant”" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + walk_body(this, visitor); }); } - function makePredicate(words) { - if (!(words instanceof Array)) words = words.split(" "); - var f = "", cats = []; - out: for (var i = 0; i < words.length; ++i) { - for (var j = 0; j < cats.length; ++j) if (cats[j][0].length == words[i].length) { - cats[j].push(words[i]); - continue out; - } - cats.push([ words[i] ]); - } - function compareTo(arr) { - if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";"; - f += "switch(str){"; - for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":"; - f += "return true}return false;"; - } - if (cats.length > 3) { - cats.sort(function(a, b) { - return b.length - a.length; +}, AST_Block); + +var AST_SwitchBranch = DEFNODE("SwitchBranch", null, { + $documentation: "Base class for `switch` branches", +}, AST_Block); + +var AST_Default = DEFNODE("Default", null, { + $documentation: "A `default` switch branch", +}, AST_SwitchBranch); + +var AST_Case = DEFNODE("Case", "expression", { + $documentation: "A `case` switch branch", + $propdoc: { + expression: "[AST_Node] the `case` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + walk_body(this, visitor); + }); + } +}, AST_SwitchBranch); + +/* -----[ EXCEPTIONS ]----- */ + +var AST_Try = DEFNODE("Try", "bcatch bfinally", { + $documentation: "A `try` statement", + $propdoc: { + bcatch: "[AST_Catch?] the catch block, or null if not present", + bfinally: "[AST_Finally?] the finally block, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + walk_body(this, visitor); + if (this.bcatch) this.bcatch._walk(visitor); + if (this.bfinally) this.bfinally._walk(visitor); + }); + } +}, AST_Block); + +var AST_Catch = DEFNODE("Catch", "argname", { + $documentation: "A `catch` node; only makes sense as part of a `try` statement", + $propdoc: { + argname: "[AST_SymbolCatch] symbol for the exception" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.argname._walk(visitor); + walk_body(this, visitor); + }); + } +}, AST_Block); + +var AST_Finally = DEFNODE("Finally", null, { + $documentation: "A `finally` node; only makes sense as part of a `try` statement" +}, AST_Block); + +/* -----[ VAR/CONST ]----- */ + +var AST_Definitions = DEFNODE("Definitions", "definitions", { + $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", + $propdoc: { + definitions: "[AST_VarDef*] array of variable definitions" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.definitions.forEach(function(def){ + def._walk(visitor); }); - f += "switch(str.length){"; - for (var i = 0; i < cats.length; ++i) { - var cat = cats[i]; - f += "case " + cat[0].length + ":"; - compareTo(cat); - } - f += "}"; - } else { - compareTo(words); - } - return new Function("str", f); + }); } - function all(array, predicate) { - for (var i = array.length; --i >= 0; ) if (!predicate(array[i])) return false; - return true; +}, AST_Statement); + +var AST_Var = DEFNODE("Var", null, { + $documentation: "A `var` statement" +}, AST_Definitions); + +var AST_Const = DEFNODE("Const", null, { + $documentation: "A `const` statement" +}, AST_Definitions); + +var AST_VarDef = DEFNODE("VarDef", "name value", { + $documentation: "A variable declaration; only appears in a AST_Definitions node", + $propdoc: { + name: "[AST_SymbolVar|AST_SymbolConst] name of the variable", + value: "[AST_Node?] initializer, or null of there's no initializer" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.name._walk(visitor); + if (this.value) this.value._walk(visitor); + }); } - function Dictionary() { - this._values = Object.create(null); - this._size = 0; +}); + +/* -----[ OTHER ]----- */ + +var AST_Call = DEFNODE("Call", "expression args", { + $documentation: "A function call expression", + $propdoc: { + expression: "[AST_Node] expression to invoke as function", + args: "[AST_Node*] array of arguments" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + this.args.forEach(function(arg){ + arg._walk(visitor); + }); + }); } - Dictionary.prototype = { - set: function(key, val) { - if (!this.has(key)) ++this._size; - this._values["$" + key] = val; - return this; - }, - add: function(key, val) { - if (this.has(key)) { - this.get(key).push(val); - } else { - this.set(key, [ val ]); +}); + +var AST_New = DEFNODE("New", null, { + $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" +}, AST_Call); + +var AST_Seq = DEFNODE("Seq", "car cdr", { + $documentation: "A sequence expression (two comma-separated expressions)", + $propdoc: { + car: "[AST_Node] first element in sequence", + cdr: "[AST_Node] second element in sequence" + }, + $cons: function(x, y) { + var seq = new AST_Seq(x); + seq.car = x; + seq.cdr = y; + return seq; + }, + $from_array: function(array) { + if (array.length == 0) return null; + if (array.length == 1) return array[0].clone(); + var list = null; + for (var i = array.length; --i >= 0;) { + list = AST_Seq.cons(array[i], list); + } + var p = list; + while (p) { + if (p.cdr && !p.cdr.cdr) { + p.cdr = p.cdr.car; + break; } - return this; - }, - get: function(key) { - return this._values["$" + key]; - }, - del: function(key) { - if (this.has(key)) { - --this._size; - delete this._values["$" + key]; + p = p.cdr; + } + return list; + }, + to_array: function() { + var p = this, a = []; + while (p) { + a.push(p.car); + if (p.cdr && !(p.cdr instanceof AST_Seq)) { + a.push(p.cdr); + break; } - return this; - }, - has: function(key) { - return "$" + key in this._values; - }, - each: function(f) { - for (var i in this._values) f(this._values[i], i.substr(1)); - }, - size: function() { - return this._size; - }, - map: function(f) { - var ret = []; - for (var i in this._values) ret.push(f(this._values[i], i.substr(1))); - return ret; + p = p.cdr; } - }; - "use strict"; - function DEFNODE(type, props, methods, base) { - if (arguments.length < 4) base = AST_Node; - if (!props) props = []; else props = props.split(/\s+/); - var self_props = props; - if (base && base.PROPS) props = props.concat(base.PROPS); - var code = "return function AST_" + type + "(props){ if (props) { "; - for (var i = props.length; --i >= 0; ) { - code += "this." + props[i] + " = props." + props[i] + ";"; - } - var proto = base && new base(); - if (proto && proto.initialize || methods && methods.initialize) code += "this.initialize();"; - code += "}}"; - var ctor = new Function(code)(); - if (proto) { - ctor.prototype = proto; - ctor.BASE = base; - } - if (base) base.SUBCLASSES.push(ctor); - ctor.prototype.CTOR = ctor; - ctor.PROPS = props || null; - ctor.SELF_PROPS = self_props; - ctor.SUBCLASSES = []; - if (type) { - ctor.prototype.TYPE = ctor.TYPE = type; - } - if (methods) for (i in methods) if (methods.hasOwnProperty(i)) { - if (/^\$/.test(i)) { - ctor[i.substr(1)] = methods[i]; - } else { - ctor.prototype[i] = methods[i]; + return a; + }, + add: function(node) { + var p = this; + while (p) { + if (!(p.cdr instanceof AST_Seq)) { + var cell = AST_Seq.cons(p.cdr, node); + return p.cdr = cell; } + p = p.cdr; } - ctor.DEFMETHOD = function(name, method) { - this.prototype[name] = method; - }; - return ctor; + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.car._walk(visitor); + if (this.cdr) this.cdr._walk(visitor); + }); } - var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {}, null); - var AST_Node = DEFNODE("Node", "start end", { - clone: function() { - return new this.CTOR(this); - }, - $documentation: "Base class of all AST nodes", - $propdoc: { - start: "[AST_Token] The first token of this node", - end: "[AST_Token] The last token of this node" - }, - _walk: function(visitor) { - return visitor._visit(this); - }, - walk: function(visitor) { - return this._walk(visitor); - } - }, null); - AST_Node.warn_function = null; - AST_Node.warn = function(txt, props) { - if (AST_Node.warn_function) AST_Node.warn_function(string_template(txt, props)); - }; - var AST_Statement = DEFNODE("Statement", null, { - $documentation: "Base class of all statements" - }); - var AST_Debugger = DEFNODE("Debugger", null, { - $documentation: "Represents a debugger statement" - }, AST_Statement); - var AST_Directive = DEFNODE("Directive", "value scope", { - $documentation: 'Represents a directive, like "use strict";', - $propdoc: { - value: "[string] The value of this directive as a plain string (it's not an AST_String!)", - scope: "[AST_Scope/S] The scope that this directive affects" - } - }, AST_Statement); - var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { - $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", - $propdoc: { - body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - }); - } - }, AST_Statement); - function walk_body(node, visitor) { - if (node.body instanceof AST_Statement) { - node.body._walk(visitor); - } else node.body.forEach(function(stat) { - stat._walk(visitor); +}); + +var AST_PropAccess = DEFNODE("PropAccess", "expression property", { + $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", + $propdoc: { + expression: "[AST_Node] the “container” expression", + property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" + } +}); + +var AST_Dot = DEFNODE("Dot", null, { + $documentation: "A dotted property access expression", + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); }); } - var AST_Block = DEFNODE("Block", "body", { - $documentation: "A body of statements (usually bracketed)", - $propdoc: { - body: "[AST_Statement*] an array of statements" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - walk_body(this, visitor); - }); - } - }, AST_Statement); - var AST_BlockStatement = DEFNODE("BlockStatement", null, { - $documentation: "A block statement" - }, AST_Block); - var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { - $documentation: "The empty statement (empty block or simply a semicolon)", - _walk: function(visitor) { - return visitor._visit(this); - } - }, AST_Statement); - var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { - $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", - $propdoc: { - body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - }); - } - }, AST_Statement); - var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { - $documentation: "Statement with a label", - $propdoc: { - label: "[AST_Label] a label definition" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.label._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_StatementWithBody); - var AST_DWLoop = DEFNODE("DWLoop", "condition", { - $documentation: "Base class for do/while statements", - $propdoc: { - condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_StatementWithBody); - var AST_Do = DEFNODE("Do", null, { - $documentation: "A `do` statement" - }, AST_DWLoop); - var AST_While = DEFNODE("While", null, { - $documentation: "A `while` statement" - }, AST_DWLoop); - var AST_For = DEFNODE("For", "init condition step", { - $documentation: "A `for` statement", - $propdoc: { - init: "[AST_Node?] the `for` initialization code, or null if empty", - condition: "[AST_Node?] the `for` termination clause, or null if empty", - step: "[AST_Node?] the `for` update clause, or null if empty" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.init) this.init._walk(visitor); - if (this.condition) this.condition._walk(visitor); - if (this.step) this.step._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_StatementWithBody); - var AST_ForIn = DEFNODE("ForIn", "init name object", { - $documentation: "A `for ... in` statement", - $propdoc: { - init: "[AST_Node] the `for/in` initialization code", - name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var", - object: "[AST_Node] the object that we're looping through" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.init._walk(visitor); - this.object._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_StatementWithBody); - var AST_With = DEFNODE("With", "expression", { - $documentation: "A `with` statement", - $propdoc: { - expression: "[AST_Node] the `with` expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_StatementWithBody); - var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", { - $documentation: "Base class for all statements introducing a lexical scope", - $propdoc: { - directives: "[string*/S] an array of directives declared in this scope", - variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope", - functions: "[Object/S] like `variables`, but only lists function declarations", - uses_with: "[boolean/S] tells whether this scope uses the `with` statement", - uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", - parent_scope: "[AST_Scope?/S] link to the parent scope", - enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", - cname: "[integer/S] current index for mangling variables (used internally by the mangler)" - } - }, AST_Block); - var AST_Toplevel = DEFNODE("Toplevel", "globals", { - $documentation: "The toplevel scope", - $propdoc: { - globals: "[Object/S] a map of name -> SymbolDef for all undeclared names" - }, - wrap_enclose: function(arg_parameter_pairs) { - var self = this; - var args = []; - var parameters = []; - arg_parameter_pairs.forEach(function(pair) { - var split = pair.split(":"); - args.push(split[0]); - parameters.push(split[1]); - }); - var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; - wrapped_tl = parse(wrapped_tl); - wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) { - if (node instanceof AST_Directive && node.value == "$ORIG") { - return MAP.splice(self.body); - } - })); - return wrapped_tl; - }, - wrap_commonjs: function(name, export_all) { - var self = this; - var to_export = []; - if (export_all) { - self.figure_out_scope(); - self.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolDeclaration && node.definition().global) { - if (!find_if(function(n) { - return n.name == node.name; - }, to_export)) to_export.push(node); - } - })); - } - var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))"; - wrapped_tl = parse(wrapped_tl); - wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node) { - if (node instanceof AST_SimpleStatement) { - node = node.body; - if (node instanceof AST_String) switch (node.getValue()) { - case "$ORIG": - return MAP.splice(self.body); - - case "$EXPORTS": - var body = []; - to_export.forEach(function(sym) { - body.push(new AST_SimpleStatement({ - body: new AST_Assign({ - left: new AST_Sub({ - expression: new AST_SymbolRef({ - name: "exports" - }), - property: new AST_String({ - value: sym.name - }) - }), - operator: "=", - right: new AST_SymbolRef(sym) - }) - })); - }); - return MAP.splice(body); - } - } - })); - return wrapped_tl; - } - }, AST_Scope); - var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", { - $documentation: "Base class for functions", - $propdoc: { - name: "[AST_SymbolDeclaration?] the name of this function", - argnames: "[AST_SymbolFunarg*] array of function arguments", - uses_arguments: "[boolean/S] tells whether this function accesses the arguments array" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.name) this.name._walk(visitor); - this.argnames.forEach(function(arg) { - arg._walk(visitor); - }); - walk_body(this, visitor); - }); - } - }, AST_Scope); - var AST_Accessor = DEFNODE("Accessor", null, { - $documentation: "A setter/getter function" - }, AST_Lambda); - var AST_Function = DEFNODE("Function", null, { - $documentation: "A function expression" - }, AST_Lambda); - var AST_Defun = DEFNODE("Defun", null, { - $documentation: "A function definition" - }, AST_Lambda); - var AST_Jump = DEFNODE("Jump", null, { - $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" - }, AST_Statement); - var AST_Exit = DEFNODE("Exit", "value", { - $documentation: "Base class for “exits” (`return` and `throw`)", - $propdoc: { - value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" - }, - _walk: function(visitor) { - return visitor._visit(this, this.value && function() { - this.value._walk(visitor); - }); - } - }, AST_Jump); - var AST_Return = DEFNODE("Return", null, { - $documentation: "A `return` statement" - }, AST_Exit); - var AST_Throw = DEFNODE("Throw", null, { - $documentation: "A `throw` statement" - }, AST_Exit); - var AST_LoopControl = DEFNODE("LoopControl", "label", { - $documentation: "Base class for loop control statements (`break` and `continue`)", - $propdoc: { - label: "[AST_LabelRef?] the label, or null if none" - }, - _walk: function(visitor) { - return visitor._visit(this, this.label && function() { - this.label._walk(visitor); - }); - } - }, AST_Jump); - var AST_Break = DEFNODE("Break", null, { - $documentation: "A `break` statement" - }, AST_LoopControl); - var AST_Continue = DEFNODE("Continue", null, { - $documentation: "A `continue` statement" - }, AST_LoopControl); - var AST_If = DEFNODE("If", "condition alternative", { - $documentation: "A `if` statement", - $propdoc: { - condition: "[AST_Node] the `if` condition", - alternative: "[AST_Statement?] the `else` part, or null if not present" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.body._walk(visitor); - if (this.alternative) this.alternative._walk(visitor); - }); - } - }, AST_StatementWithBody); - var AST_Switch = DEFNODE("Switch", "expression", { - $documentation: "A `switch` statement", - $propdoc: { - expression: "[AST_Node] the `switch` “discriminant”" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - walk_body(this, visitor); - }); - } - }, AST_Block); - var AST_SwitchBranch = DEFNODE("SwitchBranch", null, { - $documentation: "Base class for `switch` branches" - }, AST_Block); - var AST_Default = DEFNODE("Default", null, { - $documentation: "A `default` switch branch" - }, AST_SwitchBranch); - var AST_Case = DEFNODE("Case", "expression", { - $documentation: "A `case` switch branch", - $propdoc: { - expression: "[AST_Node] the `case` expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - walk_body(this, visitor); - }); - } - }, AST_SwitchBranch); - var AST_Try = DEFNODE("Try", "bcatch bfinally", { - $documentation: "A `try` statement", - $propdoc: { - bcatch: "[AST_Catch?] the catch block, or null if not present", - bfinally: "[AST_Finally?] the finally block, or null if not present" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - walk_body(this, visitor); - if (this.bcatch) this.bcatch._walk(visitor); - if (this.bfinally) this.bfinally._walk(visitor); - }); - } - }, AST_Block); - var AST_Catch = DEFNODE("Catch", "argname", { - $documentation: "A `catch` node; only makes sense as part of a `try` statement", - $propdoc: { - argname: "[AST_SymbolCatch] symbol for the exception" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.argname._walk(visitor); - walk_body(this, visitor); - }); - } - }, AST_Block); - var AST_Finally = DEFNODE("Finally", null, { - $documentation: "A `finally` node; only makes sense as part of a `try` statement" - }, AST_Block); - var AST_Definitions = DEFNODE("Definitions", "definitions", { - $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", - $propdoc: { - definitions: "[AST_VarDef*] array of variable definitions" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.definitions.forEach(function(def) { - def._walk(visitor); - }); - }); - } - }, AST_Statement); - var AST_Var = DEFNODE("Var", null, { - $documentation: "A `var` statement" - }, AST_Definitions); - var AST_Const = DEFNODE("Const", null, { - $documentation: "A `const` statement" - }, AST_Definitions); - var AST_VarDef = DEFNODE("VarDef", "name value", { - $documentation: "A variable declaration; only appears in a AST_Definitions node", - $propdoc: { - name: "[AST_SymbolVar|AST_SymbolConst] name of the variable", - value: "[AST_Node?] initializer, or null of there's no initializer" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.name._walk(visitor); - if (this.value) this.value._walk(visitor); - }); - } - }); - var AST_Call = DEFNODE("Call", "expression args", { - $documentation: "A function call expression", - $propdoc: { - expression: "[AST_Node] expression to invoke as function", - args: "[AST_Node*] array of arguments" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.args.forEach(function(arg) { - arg._walk(visitor); - }); - }); - } - }); - var AST_New = DEFNODE("New", null, { - $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" - }, AST_Call); - var AST_Seq = DEFNODE("Seq", "car cdr", { - $documentation: "A sequence expression (two comma-separated expressions)", - $propdoc: { - car: "[AST_Node] first element in sequence", - cdr: "[AST_Node] second element in sequence" - }, - $cons: function(x, y) { - var seq = new AST_Seq(x); - seq.car = x; - seq.cdr = y; - return seq; - }, - $from_array: function(array) { - if (array.length == 0) return null; - if (array.length == 1) return array[0].clone(); - var list = null; - for (var i = array.length; --i >= 0; ) { - list = AST_Seq.cons(array[i], list); - } - var p = list; - while (p) { - if (p.cdr && !p.cdr.cdr) { - p.cdr = p.cdr.car; - break; - } - p = p.cdr; - } - return list; - }, - to_array: function() { - var p = this, a = []; - while (p) { - a.push(p.car); - if (p.cdr && !(p.cdr instanceof AST_Seq)) { - a.push(p.cdr); - break; - } - p = p.cdr; - } - return a; - }, - add: function(node) { - var p = this; - while (p) { - if (!(p.cdr instanceof AST_Seq)) { - var cell = AST_Seq.cons(p.cdr, node); - return p.cdr = cell; - } - p = p.cdr; - } - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.car._walk(visitor); - if (this.cdr) this.cdr._walk(visitor); - }); - } - }); - var AST_PropAccess = DEFNODE("PropAccess", "expression property", { - $documentation: 'Base class for property access expressions, i.e. `a.foo` or `a["foo"]`', - $propdoc: { - expression: "[AST_Node] the “container” expression", - property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" - } - }); - var AST_Dot = DEFNODE("Dot", null, { - $documentation: "A dotted property access expression", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - } - }, AST_PropAccess); - var AST_Sub = DEFNODE("Sub", null, { - $documentation: 'Index-style property access, i.e. `a["foo"]`', - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.property._walk(visitor); - }); - } - }, AST_PropAccess); - var AST_Unary = DEFNODE("Unary", "operator expression", { - $documentation: "Base class for unary expressions", - $propdoc: { - operator: "[string] the operator", - expression: "[AST_Node] expression that this unary operator applies to" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - } - }); - var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { - $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" - }, AST_Unary); - var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { - $documentation: "Unary postfix expression, i.e. `i++`" - }, AST_Unary); - var AST_Binary = DEFNODE("Binary", "left operator right", { - $documentation: "Binary expression, i.e. `a + b`", - $propdoc: { - left: "[AST_Node] left-hand side expression", - operator: "[string] the operator", - right: "[AST_Node] right-hand side expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.left._walk(visitor); - this.right._walk(visitor); - }); - } - }); - var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { - $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", - $propdoc: { - condition: "[AST_Node]", - consequent: "[AST_Node]", - alternative: "[AST_Node]" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.consequent._walk(visitor); - this.alternative._walk(visitor); - }); - } - }); - var AST_Assign = DEFNODE("Assign", null, { - $documentation: "An assignment expression — `a = b + 5`" - }, AST_Binary); - var AST_Array = DEFNODE("Array", "elements", { - $documentation: "An array literal", - $propdoc: { - elements: "[AST_Node*] array of elements" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.elements.forEach(function(el) { - el._walk(visitor); - }); - }); - } - }); - var AST_Object = DEFNODE("Object", "properties", { - $documentation: "An object literal", - $propdoc: { - properties: "[AST_ObjectProperty*] array of properties" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.properties.forEach(function(prop) { - prop._walk(visitor); - }); - }); - } - }); - var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { - $documentation: "Base class for literal object properties", - $propdoc: { - key: "[string] the property name; it's always a plain string in our AST, no matter if it was a string, number or identifier in original code", - value: "[AST_Node] property value. For setters and getters this is an AST_Function." - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.value._walk(visitor); - }); - } - }); - var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, { - $documentation: "A key: value object property" - }, AST_ObjectProperty); - var AST_ObjectSetter = DEFNODE("ObjectSetter", null, { - $documentation: "An object setter property" - }, AST_ObjectProperty); - var AST_ObjectGetter = DEFNODE("ObjectGetter", null, { - $documentation: "An object getter property" - }, AST_ObjectProperty); - var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { - $propdoc: { - name: "[string] name of this symbol", - scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", - thedef: "[SymbolDef/S] the definition of this symbol" - }, - $documentation: "Base class for all symbols" - }); - var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, { - $documentation: "The name of a property accessor (setter/getter function)" - }, AST_Symbol); - var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { - $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", - $propdoc: { - init: "[AST_Node*/S] array of initializers for this declaration." - } - }, AST_Symbol); - var AST_SymbolVar = DEFNODE("SymbolVar", null, { - $documentation: "Symbol defining a variable" - }, AST_SymbolDeclaration); - var AST_SymbolConst = DEFNODE("SymbolConst", null, { - $documentation: "A constant declaration" - }, AST_SymbolDeclaration); - var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { - $documentation: "Symbol naming a function argument" - }, AST_SymbolVar); - var AST_SymbolDefun = DEFNODE("SymbolDefun", null, { - $documentation: "Symbol defining a function" - }, AST_SymbolDeclaration); - var AST_SymbolLambda = DEFNODE("SymbolLambda", null, { - $documentation: "Symbol naming a function expression" - }, AST_SymbolDeclaration); - var AST_SymbolCatch = DEFNODE("SymbolCatch", null, { - $documentation: "Symbol naming the exception in catch" - }, AST_SymbolDeclaration); - var AST_Label = DEFNODE("Label", "references", { - $documentation: "Symbol naming a label (declaration)", - $propdoc: { - references: "[AST_LabelRef*] a list of nodes referring to this label" - } - }, AST_Symbol); - var AST_SymbolRef = DEFNODE("SymbolRef", null, { - $documentation: "Reference to some symbol (not definition/declaration)" - }, AST_Symbol); - var AST_LabelRef = DEFNODE("LabelRef", null, { - $documentation: "Reference to a label symbol" - }, AST_Symbol); - var AST_This = DEFNODE("This", null, { - $documentation: "The `this` symbol" - }, AST_Symbol); - var AST_Constant = DEFNODE("Constant", null, { - $documentation: "Base class for all constants", - getValue: function() { - return this.value; - } - }); - var AST_String = DEFNODE("String", "value", { - $documentation: "A string literal", - $propdoc: { - value: "[string] the contents of this string" - } - }, AST_Constant); - var AST_Number = DEFNODE("Number", "value", { - $documentation: "A number literal", - $propdoc: { - value: "[number] the numeric value" - } - }, AST_Constant); - var AST_RegExp = DEFNODE("RegExp", "value", { - $documentation: "A regexp literal", - $propdoc: { - value: "[RegExp] the actual regexp" - } - }, AST_Constant); - var AST_Atom = DEFNODE("Atom", null, { - $documentation: "Base class for atoms" - }, AST_Constant); - var AST_Null = DEFNODE("Null", null, { - $documentation: "The `null` atom", - value: null - }, AST_Atom); - var AST_NaN = DEFNODE("NaN", null, { - $documentation: "The impossible value", - value: 0 / 0 - }, AST_Atom); - var AST_Undefined = DEFNODE("Undefined", null, { - $documentation: "The `undefined` value", - value: function() {}() - }, AST_Atom); - var AST_Hole = DEFNODE("Hole", null, { - $documentation: "A hole in an array", - value: function() {}() - }, AST_Atom); - var AST_Infinity = DEFNODE("Infinity", null, { - $documentation: "The `Infinity` value", - value: 1 / 0 - }, AST_Atom); - var AST_Boolean = DEFNODE("Boolean", null, { - $documentation: "Base class for booleans" - }, AST_Atom); - var AST_False = DEFNODE("False", null, { - $documentation: "The `false` atom", - value: false - }, AST_Boolean); - var AST_True = DEFNODE("True", null, { - $documentation: "The `true` atom", - value: true - }, AST_Boolean); - function TreeWalker(callback) { - this.visit = callback; - this.stack = []; - } - TreeWalker.prototype = { - _visit: function(node, descend) { - this.stack.push(node); - var ret = this.visit(node, descend ? function() { - descend.call(node); - } : noop); - if (!ret && descend) { - descend.call(node); - } - this.stack.pop(); - return ret; - }, - parent: function(n) { - return this.stack[this.stack.length - 2 - (n || 0)]; - }, - push: function(node) { - this.stack.push(node); - }, - pop: function() { - return this.stack.pop(); - }, - self: function() { - return this.stack[this.stack.length - 1]; - }, - find_parent: function(type) { - var stack = this.stack; - for (var i = stack.length; --i >= 0; ) { - var x = stack[i]; - if (x instanceof type) return x; - } - }, - has_directive: function(type) { - return this.find_parent(AST_Scope).has_directive(type); - }, - in_boolean_context: function() { - var stack = this.stack; - var i = stack.length, self = stack[--i]; - while (i > 0) { - var p = stack[--i]; - if (p instanceof AST_If && p.condition === self || p instanceof AST_Conditional && p.condition === self || p instanceof AST_DWLoop && p.condition === self || p instanceof AST_For && p.condition === self || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) { - return true; - } - if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) return false; - self = p; - } - }, - loopcontrol_target: function(label) { - var stack = this.stack; - if (label) { - for (var i = stack.length; --i >= 0; ) { - var x = stack[i]; - if (x instanceof AST_LabeledStatement && x.label.name == label.name) { - return x.body; - } - } - } else { - for (var i = stack.length; --i >= 0; ) { - var x = stack[i]; - if (x instanceof AST_Switch || x instanceof AST_For || x instanceof AST_ForIn || x instanceof AST_DWLoop) return x; - } - } - } - }; - "use strict"; - var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with"; - var KEYWORDS_ATOM = "false null true"; - var RESERVED_WORDS = "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile" + " " + KEYWORDS_ATOM + " " + KEYWORDS; - var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case"; - KEYWORDS = makePredicate(KEYWORDS); - RESERVED_WORDS = makePredicate(RESERVED_WORDS); - KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION); - KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM); - var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^")); - var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; - var RE_OCT_NUMBER = /^0[0-7]+$/; - var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; - var OPERATORS = makePredicate([ "in", "instanceof", "typeof", "new", "void", "delete", "++", "--", "+", "-", "!", "~", "&", "|", "^", "*", "/", "%", ">>", "<<", ">>>", "<", ">", "<=", ">=", "==", "===", "!=", "!==", "?", "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=", "&&", "||" ]); - var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); - var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); - var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); - var REGEXP_MODIFIERS = makePredicate(characters("gmsiy")); - var UNICODE = { - letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), - non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), - space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), - connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") - }; - function is_letter(code) { - return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 170 && UNICODE.letter.test(String.fromCharCode(code)); +}, AST_PropAccess); + +var AST_Sub = DEFNODE("Sub", null, { + $documentation: "Index-style property access, i.e. `a[\"foo\"]`", + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + this.property._walk(visitor); + }); } - function is_digit(code) { - return code >= 48 && code <= 57; +}, AST_PropAccess); + +var AST_Unary = DEFNODE("Unary", "operator expression", { + $documentation: "Base class for unary expressions", + $propdoc: { + operator: "[string] the operator", + expression: "[AST_Node] expression that this unary operator applies to" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.expression._walk(visitor); + }); } - function is_alphanumeric_char(code) { - return is_digit(code) || is_letter(code); +}); + +var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { + $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" +}, AST_Unary); + +var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { + $documentation: "Unary postfix expression, i.e. `i++`" +}, AST_Unary); + +var AST_Binary = DEFNODE("Binary", "left operator right", { + $documentation: "Binary expression, i.e. `a + b`", + $propdoc: { + left: "[AST_Node] left-hand side expression", + operator: "[string] the operator", + right: "[AST_Node] right-hand side expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.left._walk(visitor); + this.right._walk(visitor); + }); } - function is_unicode_combining_mark(ch) { - return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); +}); + +var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { + $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", + $propdoc: { + condition: "[AST_Node]", + consequent: "[AST_Node]", + alternative: "[AST_Node]" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.condition._walk(visitor); + this.consequent._walk(visitor); + this.alternative._walk(visitor); + }); } - function is_unicode_connector_punctuation(ch) { - return UNICODE.connector_punctuation.test(ch); +}); + +var AST_Assign = DEFNODE("Assign", null, { + $documentation: "An assignment expression — `a = b + 5`", +}, AST_Binary); + +/* -----[ LITERALS ]----- */ + +var AST_Array = DEFNODE("Array", "elements", { + $documentation: "An array literal", + $propdoc: { + elements: "[AST_Node*] array of elements" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.elements.forEach(function(el){ + el._walk(visitor); + }); + }); } - function is_identifier(name) { - return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name); +}); + +var AST_Object = DEFNODE("Object", "properties", { + $documentation: "An object literal", + $propdoc: { + properties: "[AST_ObjectProperty*] array of properties" + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.properties.forEach(function(prop){ + prop._walk(visitor); + }); + }); } - function is_identifier_start(code) { - return code == 36 || code == 95 || is_letter(code); +}); + +var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { + $documentation: "Base class for literal object properties", + $propdoc: { + key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.", + value: "[AST_Node] property value. For setters and getters this is an AST_Function." + }, + _walk: function(visitor) { + return visitor._visit(this, function(){ + this.value._walk(visitor); + }); } - function is_identifier_char(ch) { - var code = ch.charCodeAt(0); - return is_identifier_start(code) || is_digit(code) || code == 8204 || code == 8205 || is_unicode_combining_mark(ch) || is_unicode_connector_punctuation(ch); +}); + +var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, { + $documentation: "A key: value object property", +}, AST_ObjectProperty); + +var AST_ObjectSetter = DEFNODE("ObjectSetter", null, { + $documentation: "An object setter property", +}, AST_ObjectProperty); + +var AST_ObjectGetter = DEFNODE("ObjectGetter", null, { + $documentation: "An object getter property", +}, AST_ObjectProperty); + +var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { + $propdoc: { + name: "[string] name of this symbol", + scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", + thedef: "[SymbolDef/S] the definition of this symbol" + }, + $documentation: "Base class for all symbols", +}); + +var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, { + $documentation: "The name of a property accessor (setter/getter function)" +}, AST_Symbol); + +var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { + $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", + $propdoc: { + init: "[AST_Node*/S] array of initializers for this declaration." } - function is_identifier_string(str) { - var i = str.length; - if (i == 0) return false; - if (is_digit(str.charCodeAt(0))) return false; - while (--i >= 0) { - if (!is_identifier_char(str.charAt(i))) return false; - } - return true; +}, AST_Symbol); + +var AST_SymbolVar = DEFNODE("SymbolVar", null, { + $documentation: "Symbol defining a variable", +}, AST_SymbolDeclaration); + +var AST_SymbolConst = DEFNODE("SymbolConst", null, { + $documentation: "A constant declaration" +}, AST_SymbolDeclaration); + +var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { + $documentation: "Symbol naming a function argument", +}, AST_SymbolVar); + +var AST_SymbolDefun = DEFNODE("SymbolDefun", null, { + $documentation: "Symbol defining a function", +}, AST_SymbolDeclaration); + +var AST_SymbolLambda = DEFNODE("SymbolLambda", null, { + $documentation: "Symbol naming a function expression", +}, AST_SymbolDeclaration); + +var AST_SymbolCatch = DEFNODE("SymbolCatch", null, { + $documentation: "Symbol naming the exception in catch", +}, AST_SymbolDeclaration); + +var AST_Label = DEFNODE("Label", "references", { + $documentation: "Symbol naming a label (declaration)", + $propdoc: { + references: "[AST_LoopControl*] a list of nodes referring to this label" + }, + initialize: function() { + this.references = []; + this.thedef = this; } - function parse_js_number(num) { - if (RE_HEX_NUMBER.test(num)) { - return parseInt(num.substr(2), 16); - } else if (RE_OCT_NUMBER.test(num)) { - return parseInt(num.substr(1), 8); - } else if (RE_DEC_NUMBER.test(num)) { - return parseFloat(num); - } +}, AST_Symbol); + +var AST_SymbolRef = DEFNODE("SymbolRef", null, { + $documentation: "Reference to some symbol (not definition/declaration)", +}, AST_Symbol); + +var AST_LabelRef = DEFNODE("LabelRef", null, { + $documentation: "Reference to a label symbol", +}, AST_Symbol); + +var AST_This = DEFNODE("This", null, { + $documentation: "The `this` symbol", +}, AST_Symbol); + +var AST_Constant = DEFNODE("Constant", null, { + $documentation: "Base class for all constants", + getValue: function() { + return this.value; } - function JS_Parse_Error(message, line, col, pos) { - this.message = message; - this.line = line; - this.col = col; - this.pos = pos; - this.stack = new Error().stack; +}); + +var AST_String = DEFNODE("String", "value", { + $documentation: "A string literal", + $propdoc: { + value: "[string] the contents of this string" } - JS_Parse_Error.prototype.toString = function() { - return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; - }; - function js_error(message, filename, line, col, pos) { - throw new JS_Parse_Error(message, line, col, pos); +}, AST_Constant); + +var AST_Number = DEFNODE("Number", "value", { + $documentation: "A number literal", + $propdoc: { + value: "[number] the numeric value" } - function is_token(token, type, val) { - return token.type == type && (val == null || token.value == val); +}, AST_Constant); + +var AST_RegExp = DEFNODE("RegExp", "value", { + $documentation: "A regexp literal", + $propdoc: { + value: "[RegExp] the actual regexp" } - var EX_EOF = {}; - function tokenizer($TEXT, filename) { - var S = { - text: $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ""), - filename: filename, - pos: 0, - tokpos: 0, - line: 1, - tokline: 0, - col: 0, - tokcol: 0, - newline_before: false, - regex_allowed: false, - comments_before: [] - }; - function peek() { - return S.text.charAt(S.pos); - } - function next(signal_eof, in_string) { - var ch = S.text.charAt(S.pos++); - if (signal_eof && !ch) throw EX_EOF; - if (ch == "\n") { - S.newline_before = S.newline_before || !in_string; - ++S.line; - S.col = 0; - } else { - ++S.col; - } - return ch; - } - function find(what, signal_eof) { - var pos = S.text.indexOf(what, S.pos); - if (signal_eof && pos == -1) throw EX_EOF; - return pos; - } - function start_token() { - S.tokline = S.line; - S.tokcol = S.col; - S.tokpos = S.pos; - } - function token(type, value, is_comment) { - S.regex_allowed = type == "operator" && !UNARY_POSTFIX(value) || type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value) || type == "punc" && PUNC_BEFORE_EXPRESSION(value); - var ret = { - type: type, - value: value, - line: S.tokline, - col: S.tokcol, - pos: S.tokpos, - endpos: S.pos, - nlb: S.newline_before, - file: filename - }; - if (!is_comment) { - ret.comments_before = S.comments_before; - S.comments_before = []; - for (var i = 0, len = ret.comments_before.length; i < len; i++) { - ret.nlb = ret.nlb || ret.comments_before[i].nlb; - } - } - S.newline_before = false; - return new AST_Token(ret); - } - function skip_whitespace() { - while (WHITESPACE_CHARS(peek())) next(); - } - function read_while(pred) { - var ret = "", ch, i = 0; - while ((ch = peek()) && pred(ch, i++)) ret += next(); - return ret; - } - function parse_error(err) { - js_error(err, filename, S.tokline, S.tokcol, S.tokpos); - } - function read_num(prefix) { - var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; - var num = read_while(function(ch, i) { - var code = ch.charCodeAt(0); - switch (code) { - case 120: - case 88: - return has_x ? false : has_x = true; +}, AST_Constant); - case 101: - case 69: - return has_x ? true : has_e ? false : has_e = after_e = true; +var AST_Atom = DEFNODE("Atom", null, { + $documentation: "Base class for atoms", +}, AST_Constant); - case 45: - return after_e || i == 0 && !prefix; +var AST_Null = DEFNODE("Null", null, { + $documentation: "The `null` atom", + value: null +}, AST_Atom); - case 43: - return after_e; +var AST_NaN = DEFNODE("NaN", null, { + $documentation: "The impossible value", + value: 0/0 +}, AST_Atom); - case after_e = false, 46: - return !has_dot && !has_x && !has_e ? has_dot = true : false; - } - return is_alphanumeric_char(code); - }); - if (prefix) num = prefix + num; - var valid = parse_js_number(num); - if (!isNaN(valid)) { - return token("num", valid); - } else { - parse_error("Invalid syntax: " + num); +var AST_Undefined = DEFNODE("Undefined", null, { + $documentation: "The `undefined` value", + value: (function(){}()) +}, AST_Atom); + +var AST_Hole = DEFNODE("Hole", null, { + $documentation: "A hole in an array", + value: (function(){}()) +}, AST_Atom); + +var AST_Infinity = DEFNODE("Infinity", null, { + $documentation: "The `Infinity` value", + value: 1/0 +}, AST_Atom); + +var AST_Boolean = DEFNODE("Boolean", null, { + $documentation: "Base class for booleans", +}, AST_Atom); + +var AST_False = DEFNODE("False", null, { + $documentation: "The `false` atom", + value: false +}, AST_Boolean); + +var AST_True = DEFNODE("True", null, { + $documentation: "The `true` atom", + value: true +}, AST_Boolean); + +/* -----[ TreeWalker ]----- */ + +function TreeWalker(callback) { + this.visit = callback; + this.stack = []; +}; +TreeWalker.prototype = { + _visit: function(node, descend) { + this.stack.push(node); + var ret = this.visit(node, descend ? function(){ + descend.call(node); + } : noop); + if (!ret && descend) { + descend.call(node); + } + this.stack.pop(); + return ret; + }, + parent: function(n) { + return this.stack[this.stack.length - 2 - (n || 0)]; + }, + push: function (node) { + this.stack.push(node); + }, + pop: function() { + return this.stack.pop(); + }, + self: function() { + return this.stack[this.stack.length - 1]; + }, + find_parent: function(type) { + var stack = this.stack; + for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof type) return x; + } + }, + has_directive: function(type) { + return this.find_parent(AST_Scope).has_directive(type); + }, + in_boolean_context: function() { + var stack = this.stack; + var i = stack.length, self = stack[--i]; + while (i > 0) { + var p = stack[--i]; + if ((p instanceof AST_If && p.condition === self) || + (p instanceof AST_Conditional && p.condition === self) || + (p instanceof AST_DWLoop && p.condition === self) || + (p instanceof AST_For && p.condition === self) || + (p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self)) + { + return true; } + if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator == "||"))) + return false; + self = p; + } + }, + loopcontrol_target: function(label) { + var stack = this.stack; + if (label) for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof AST_LabeledStatement && x.label.name == label.name) { + return x.body; + } + } else for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof AST_Switch || x instanceof AST_IterationStatement) + return x; } - function read_escaped_char(in_string) { - var ch = next(true, in_string); - switch (ch.charCodeAt(0)) { - case 110: - return "\n"; + } +}; - case 114: - return "\r"; +/*********************************************************************** - case 116: - return " "; + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 - case 98: - return "\b"; + -------------------------------- (C) --------------------------------- - case 118: - return " "; + Author: Mihai Bazon + + http://mihai.bazon.net/blog - case 102: - return "\f"; + Distributed under the BSD license: - case 48: - return "\x00"; + Copyright 2012 (c) Mihai Bazon + Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/). - case 120: - return String.fromCharCode(hex_bytes(2)); + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: - case 117: - return String.fromCharCode(hex_bytes(4)); + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. - case 10: - return ""; + * 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. - default: - return ch; - } - } - function hex_bytes(n) { - var num = 0; - for (;n > 0; --n) { - var digit = parseInt(next(true), 16); - if (isNaN(digit)) parse_error("Invalid hex-character pattern in string"); - num = num << 4 | digit; - } - return num; - } - var read_string = with_eof_error("Unterminated string constant", function() { - var quote = next(), ret = ""; - for (;;) { - var ch = next(true); - if (ch == "\\") { - var octal_len = 0, first = null; - ch = read_while(function(ch) { - if (ch >= "0" && ch <= "7") { - if (!first) { - first = ch; - return ++octal_len; - } else if (first <= "3" && octal_len <= 2) return ++octal_len; else if (first >= "4" && octal_len <= 1) return ++octal_len; - } - return false; - }); - if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); else ch = read_escaped_char(true); - } else if (ch == quote) break; - ret += ch; - } - return token("string", ret); - }); - function read_line_comment() { - next(); - var i = find("\n"), ret; - if (i == -1) { - ret = S.text.substr(S.pos); - S.pos = S.text.length; - } else { - ret = S.text.substring(S.pos, i); - S.pos = i; - } - return token("comment1", ret, true); - } - var read_multiline_comment = with_eof_error("Unterminated multiline comment", function() { - next(); - var i = find("*/", true); - var text = S.text.substring(S.pos, i); - var a = text.split("\n"), n = a.length; - S.pos = i + 2; - S.line += n - 1; - if (n > 1) S.col = a[n - 1].length; else S.col += a[n - 1].length; - S.col += 2; - S.newline_before = S.newline_before || text.indexOf("\n") >= 0; - return token("comment2", text, true); - }); - function read_name() { - var backslash = false, name = "", ch, escaped = false, hex; - while ((ch = peek()) != null) { - if (!backslash) { - if (ch == "\\") escaped = backslash = true, next(); else if (is_identifier_char(ch)) name += next(); else break; - } else { - if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); - ch = read_escaped_char(); - if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); - name += ch; - backslash = false; - } - } - if (KEYWORDS(name) && escaped) { - hex = name.charCodeAt(0).toString(16).toUpperCase(); - name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); - } - return name; - } - var read_regexp = with_eof_error("Unterminated regular expression", function(regexp) { - var prev_backslash = false, ch, in_class = false; - while (ch = next(true)) if (prev_backslash) { - regexp += "\\" + ch; - prev_backslash = false; - } else if (ch == "[") { - in_class = true; - regexp += ch; - } else if (ch == "]" && in_class) { - in_class = false; - regexp += ch; - } else if (ch == "/" && !in_class) { - break; - } else if (ch == "\\") { - prev_backslash = true; - } else { - regexp += ch; - } - var mods = read_name(); - return token("regexp", new RegExp(regexp, mods)); - }); - function read_operator(prefix) { - function grow(op) { - if (!peek()) return op; - var bigger = op + peek(); - if (OPERATORS(bigger)) { - next(); - return grow(bigger); - } else { - return op; - } - } - return token("operator", grow(prefix || next())); - } - function handle_slash() { - next(); - var regex_allowed = S.regex_allowed; - switch (peek()) { - case "/": - S.comments_before.push(read_line_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - - case "*": - S.comments_before.push(read_multiline_comment()); - S.regex_allowed = regex_allowed; - return next_token(); - } - return S.regex_allowed ? read_regexp("") : read_operator("/"); - } - function handle_dot() { - next(); - return is_digit(peek().charCodeAt(0)) ? read_num(".") : token("punc", "."); - } - function read_word() { - var word = read_name(); - return KEYWORDS_ATOM(word) ? token("atom", word) : !KEYWORDS(word) ? token("name", word) : OPERATORS(word) ? token("operator", word) : token("keyword", word); - } - function with_eof_error(eof_error, cont) { - return function(x) { - try { - return cont(x); - } catch (ex) { - if (ex === EX_EOF) parse_error(eof_error); else throw ex; - } - }; - } - function next_token(force_regexp) { - if (force_regexp != null) return read_regexp(force_regexp); - skip_whitespace(); - start_token(); - var ch = peek(); - if (!ch) return token("eof"); - var code = ch.charCodeAt(0); - switch (code) { - case 34: - case 39: - return read_string(); + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. - case 46: - return handle_dot(); + ***********************************************************************/ - case 47: - return handle_slash(); - } - if (is_digit(code)) return read_num(); - if (PUNC_CHARS(ch)) return token("punc", next()); - if (OPERATOR_CHARS(ch)) return read_operator(); - if (code == 92 || is_identifier_start(code)) return read_word(); - parse_error("Unexpected character '" + ch + "'"); - } - next_token.context = function(nc) { - if (nc) S = nc; - return S; - }; - return next_token; - } - var UNARY_PREFIX = makePredicate([ "typeof", "void", "delete", "--", "++", "!", "~", "-", "+" ]); - var UNARY_POSTFIX = makePredicate([ "--", "++" ]); - var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); - var PRECEDENCE = function(a, ret) { - for (var i = 0, n = 1; i < a.length; ++i, ++n) { - var b = a[i]; - for (var j = 0; j < b.length; ++j) { - ret[b[j]] = n; - } - } - return ret; - }([ [ "||" ], [ "&&" ], [ "|" ], [ "^" ], [ "&" ], [ "==", "===", "!=", "!==" ], [ "<", ">", "<=", ">=", "in", "instanceof" ], [ ">>", "<<", ">>>" ], [ "+", "-" ], [ "*", "/", "%" ] ], {}); - var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); - var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); - function parse($TEXT, options) { - options = defaults(options, { - strict: false, - filename: null, - toplevel: null, - expression: false - }); - var S = { - input: typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT, - token: null, - prev: null, - peeked: null, - in_function: 0, - in_directives: true, - in_loop: 0, - labels: [] - }; - S.token = next(); - function is(type, value) { - return is_token(S.token, type, value); - } - function peek() { - return S.peeked || (S.peeked = S.input()); - } - function next() { - S.prev = S.token; - if (S.peeked) { - S.token = S.peeked; - S.peeked = null; - } else { - S.token = S.input(); - } - S.in_directives = S.in_directives && (S.token.type == "string" || is("punc", ";")); - return S.token; - } - function prev() { - return S.prev; - } - function croak(msg, line, col, pos) { - var ctx = S.input.context(); - js_error(msg, ctx.filename, line != null ? line : ctx.tokline, col != null ? col : ctx.tokcol, pos != null ? pos : ctx.tokpos); - } - function token_error(token, msg) { - croak(msg, token.line, token.col); - } - function unexpected(token) { - if (token == null) token = S.token; - token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); - } - function expect_token(type, val) { - if (is(type, val)) { - return next(); - } - token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); - } - function expect(punc) { - return expect_token("punc", punc); - } - function can_insert_semicolon() { - return !options.strict && (S.token.nlb || is("eof") || is("punc", "}")); - } - function semicolon() { - if (is("punc", ";")) next(); else if (!can_insert_semicolon()) unexpected(); - } - function parenthesised() { - expect("("); - var exp = expression(true); - expect(")"); - return exp; - } - function embed_tokens(parser) { - return function() { - var start = S.token; - var expr = parser(); - var end = prev(); - expr.start = start; - expr.end = end; - return expr; - }; - } - var statement = embed_tokens(function() { - var tmp; - if (is("operator", "/") || is("operator", "/=")) { - S.peeked = null; - S.token = S.input(S.token.value.substr(1)); - } - switch (S.token.type) { - case "string": - var dir = S.in_directives, stat = simple_statement(); - if (dir && stat.body instanceof AST_String && !is("punc", ",")) return new AST_Directive({ - value: stat.body.value - }); - return stat; +"use strict"; - case "num": - case "regexp": - case "operator": - case "atom": - return simple_statement(); +var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with'; +var KEYWORDS_ATOM = 'false null true'; +var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile' + + " " + KEYWORDS_ATOM + " " + KEYWORDS; +var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case'; - case "name": - return is_token(peek(), "punc", ":") ? labeled_statement() : simple_statement(); +KEYWORDS = makePredicate(KEYWORDS); +RESERVED_WORDS = makePredicate(RESERVED_WORDS); +KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION); +KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM); - case "punc": - switch (S.token.value) { - case "{": - return new AST_BlockStatement({ - start: S.token, - body: block_(), - end: prev() - }); +var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^")); - case "[": - case "(": - return simple_statement(); +var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; +var RE_OCT_NUMBER = /^0[0-7]+$/; +var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; - case ";": - next(); - return new AST_EmptyStatement(); +var OPERATORS = makePredicate([ + "in", + "instanceof", + "typeof", + "new", + "void", + "delete", + "++", + "--", + "+", + "-", + "!", + "~", + "&", + "|", + "^", + "*", + "/", + "%", + ">>", + "<<", + ">>>", + "<", + ">", + "<=", + ">=", + "==", + "===", + "!=", + "!==", + "?", + "=", + "+=", + "-=", + "/=", + "*=", + "%=", + ">>=", + "<<=", + ">>>=", + "|=", + "^=", + "&=", + "&&", + "||" +]); - default: - unexpected(); - } +var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000")); - case "keyword": - switch (tmp = S.token.value, next(), tmp) { - case "break": - return break_cont(AST_Break); +var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:")); - case "continue": - return break_cont(AST_Continue); +var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); - case "debugger": - semicolon(); - return new AST_Debugger(); +var REGEXP_MODIFIERS = makePredicate(characters("gmsiy")); - case "do": - return new AST_Do({ - body: in_loop(statement), - condition: (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), - tmp) - }); +/* -----[ Tokenizer ]----- */ - case "while": - return new AST_While({ - condition: parenthesised(), - body: in_loop(statement) - }); +// regexps adapted from http://xregexp.com/plugins/#unicode +var UNICODE = { + letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"), + non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"), + space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"), + connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]") +}; - case "for": - return for_(); +function is_letter(code) { + return (code >= 97 && code <= 122) + || (code >= 65 && code <= 90) + || (code >= 0xaa && UNICODE.letter.test(String.fromCharCode(code))); +}; - case "function": - return function_(true); +function is_digit(code) { + return code >= 48 && code <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9 +}; - case "if": - return if_(); +function is_alphanumeric_char(code) { + return is_digit(code) || is_letter(code); +}; - case "return": - if (S.in_function == 0) croak("'return' outside of function"); - return new AST_Return({ - value: is("punc", ";") ? (next(), null) : can_insert_semicolon() ? null : (tmp = expression(true), - semicolon(), tmp) - }); +function is_unicode_combining_mark(ch) { + return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch); +}; - case "switch": - return new AST_Switch({ - expression: parenthesised(), - body: in_loop(switch_body_) - }); +function is_unicode_connector_punctuation(ch) { + return UNICODE.connector_punctuation.test(ch); +}; - case "throw": - if (S.token.nlb) croak("Illegal newline after 'throw'"); - return new AST_Throw({ - value: (tmp = expression(true), semicolon(), tmp) - }); +function is_identifier(name) { + return !RESERVED_WORDS(name) && /^[a-z_$][a-z0-9_$]*$/i.test(name); +}; - case "try": - return try_(); +function is_identifier_start(code) { + return code == 36 || code == 95 || is_letter(code); +}; - case "var": - return tmp = var_(), semicolon(), tmp; +function is_identifier_char(ch) { + var code = ch.charCodeAt(0); + return is_identifier_start(code) + || is_digit(code) + || code == 8204 // \u200c: zero-width non-joiner + || code == 8205 // \u200d: zero-width joiner (in my ECMA-262 PDF, this is also 200c) + || is_unicode_combining_mark(ch) + || is_unicode_connector_punctuation(ch) + ; +}; - case "const": - return tmp = const_(), semicolon(), tmp; +function is_identifier_string(str){ + var i = str.length; + if (i == 0) return false; + if (!is_identifier_start(str.charCodeAt(0))) return false; + while (--i >= 0) { + if (!is_identifier_char(str.charAt(i))) + return false; + } + return true; +}; - case "with": - return new AST_With({ - expression: parenthesised(), - body: statement() - }); +function parse_js_number(num) { + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } +}; - default: - unexpected(); - } - } - }); - function labeled_statement() { - var label = as_symbol(AST_Label); - if (find_if(function(l) { - return l.name == label.name; - }, S.labels)) { - croak("Label " + label.name + " defined twice"); - } - expect(":"); - S.labels.push(label); - var stat = statement(); - S.labels.pop(); - return new AST_LabeledStatement({ - body: stat, - label: label - }); - } - function simple_statement(tmp) { - return new AST_SimpleStatement({ - body: (tmp = expression(true), semicolon(), tmp) - }); - } - function break_cont(type) { - var label = null; - if (!can_insert_semicolon()) { - label = as_symbol(AST_LabelRef, true); - } - if (label != null) { - if (!find_if(function(l) { - return l.name == label.name; - }, S.labels)) croak("Undefined label " + label.name); - } else if (S.in_loop == 0) croak(type.TYPE + " not inside a loop or switch"); - semicolon(); - return new type({ - label: label - }); - } - function for_() { - expect("("); - var init = null; - if (!is("punc", ";")) { - init = is("keyword", "var") ? (next(), var_(true)) : expression(true, true); - if (is("operator", "in")) { - if (init instanceof AST_Var && init.definitions.length > 1) croak("Only one variable declaration allowed in for..in loop"); - next(); - return for_in(init); - } - } - return regular_for(init); - } - function regular_for(init) { - expect(";"); - var test = is("punc", ";") ? null : expression(true); - expect(";"); - var step = is("punc", ")") ? null : expression(true); - expect(")"); - return new AST_For({ - init: init, - condition: test, - step: step, - body: in_loop(statement) - }); - } - function for_in(init) { - var lhs = init instanceof AST_Var ? init.definitions[0].name : null; - var obj = expression(true); - expect(")"); - return new AST_ForIn({ - init: init, - name: lhs, - object: obj, - body: in_loop(statement) - }); +function JS_Parse_Error(message, line, col, pos) { + this.message = message; + this.line = line; + this.col = col; + this.pos = pos; + this.stack = new Error().stack; +}; + +JS_Parse_Error.prototype.toString = function() { + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; +}; + +function js_error(message, filename, line, col, pos) { + throw new JS_Parse_Error(message, line, col, pos); +}; + +function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); +}; + +var EX_EOF = {}; + +function tokenizer($TEXT, filename, html5_comments) { + + var S = { + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ''), + filename : filename, + pos : 0, + tokpos : 0, + line : 1, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + comments_before : [] + }; + + function peek() { return S.text.charAt(S.pos); }; + + function next(signal_eof, in_string) { + var ch = S.text.charAt(S.pos++); + if (signal_eof && !ch) + throw EX_EOF; + if (ch == "\n") { + S.newline_before = S.newline_before || !in_string; + ++S.line; + S.col = 0; + } else { + ++S.col; } - var function_ = function(in_statement, ctor) { - var is_accessor = ctor === AST_Accessor; - var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : is_accessor ? AST_SymbolAccessor : AST_SymbolLambda) : is_accessor && (is("string") || is("num")) ? as_atom_node() : null; - if (in_statement && !name) unexpected(); - expect("("); - if (!ctor) ctor = in_statement ? AST_Defun : AST_Function; - return new ctor({ - name: name, - argnames: function(first, a) { - while (!is("punc", ")")) { - if (first) first = false; else expect(","); - a.push(as_symbol(AST_SymbolFunarg)); - } - next(); - return a; - }(true, []), - body: function(loop, labels) { - ++S.in_function; - S.in_directives = true; - S.in_loop = 0; - S.labels = []; - var a = block_(); - --S.in_function; - S.in_loop = loop; - S.labels = labels; - return a; - }(S.in_loop, S.labels) - }); + return ch; + }; + + function forward(i) { + while (i-- > 0) next(); + }; + + function looking_at(str) { + return S.text.substr(S.pos, str.length) == str; + }; + + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + }; + + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + }; + + var prev_was_dot = false; + function token(type, value, is_comment) { + S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) || + (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) || + (type == "punc" && PUNC_BEFORE_EXPRESSION(value))); + prev_was_dot = (type == "punc" && value == "."); + var ret = { + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + endpos : S.pos, + nlb : S.newline_before, + file : filename }; - function if_() { - var cond = parenthesised(), body = statement(), belse = null; - if (is("keyword", "else")) { - next(); - belse = statement(); + if (!is_comment) { + ret.comments_before = S.comments_before; + S.comments_before = []; + // make note of any newlines in the comments that came before + for (var i = 0, len = ret.comments_before.length; i < len; i++) { + ret.nlb = ret.nlb || ret.comments_before[i].nlb; } - return new AST_If({ - condition: cond, - body: body, - alternative: belse - }); } - function block_() { - expect("{"); - var a = []; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - a.push(statement()); - } + S.newline_before = false; + return new AST_Token(ret); + }; + + function skip_whitespace() { + while (WHITESPACE_CHARS(peek())) next(); - return a; + }; + + function read_while(pred) { + var ret = "", ch, i = 0; + while ((ch = peek()) && pred(ch, i++)) + ret += next(); + return ret; + }; + + function parse_error(err) { + js_error(err, filename, S.tokline, S.tokcol, S.tokpos); + }; + + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false, has_dot = prefix == "."; + var num = read_while(function(ch, i){ + var code = ch.charCodeAt(0); + switch (code) { + case 120: case 88: // xX + return has_x ? false : (has_x = true); + case 101: case 69: // eE + return has_x ? true : has_e ? false : (has_e = after_e = true); + case 45: // - + return after_e || (i == 0 && !prefix); + case 43: // + + return after_e; + case (after_e = false, 46): // . + return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false; + } + return is_alphanumeric_char(code); + }); + if (prefix) num = prefix + num; + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); } - function switch_body_() { - expect("{"); - var a = [], cur = null, branch = null, tmp; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - if (is("keyword", "case")) { - if (branch) branch.end = prev(); - cur = []; - branch = new AST_Case({ - start: (tmp = S.token, next(), tmp), - expression: expression(true), - body: cur - }); - a.push(branch); - expect(":"); - } else if (is("keyword", "default")) { - if (branch) branch.end = prev(); - cur = []; - branch = new AST_Default({ - start: (tmp = S.token, next(), expect(":"), tmp), - body: cur - }); - a.push(branch); - } else { - if (!cur) unexpected(); - cur.push(statement()); - } - } - if (branch) branch.end = prev(); - next(); - return a; + }; + + function read_escaped_char(in_string) { + var ch = next(true, in_string); + switch (ch.charCodeAt(0)) { + case 110 : return "\n"; + case 114 : return "\r"; + case 116 : return "\t"; + case 98 : return "\b"; + case 118 : return "\u000b"; // \v + case 102 : return "\f"; + case 48 : return "\0"; + case 120 : return String.fromCharCode(hex_bytes(2)); // \x + case 117 : return String.fromCharCode(hex_bytes(4)); // \u + case 10 : return ""; // newline + default : return ch; } - function try_() { - var body = block_(), bcatch = null, bfinally = null; - if (is("keyword", "catch")) { - var start = S.token; - next(); - expect("("); - var name = as_symbol(AST_SymbolCatch); - expect(")"); - bcatch = new AST_Catch({ - start: start, - argname: name, - body: block_(), - end: prev() - }); - } - if (is("keyword", "finally")) { - var start = S.token; - next(); - bfinally = new AST_Finally({ - start: start, - body: block_(), - end: prev() + }; + + function hex_bytes(n) { + var num = 0; + for (; n > 0; --n) { + var digit = parseInt(next(true), 16); + if (isNaN(digit)) + parse_error("Invalid hex-character pattern in string"); + num = (num << 4) | digit; + } + return num; + }; + + var read_string = with_eof_error("Unterminated string constant", function(){ + var quote = next(), ret = ""; + for (;;) { + var ch = next(true); + if (ch == "\\") { + // read OctalEscapeSequence (XXX: deprecated if "strict mode") + // https://github.com/mishoo/UglifyJS/issues/178 + var octal_len = 0, first = null; + ch = read_while(function(ch){ + if (ch >= "0" && ch <= "7") { + if (!first) { + first = ch; + return ++octal_len; + } + else if (first <= "3" && octal_len <= 2) return ++octal_len; + else if (first >= "4" && octal_len <= 1) return ++octal_len; + } + return false; }); + if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8)); + else ch = read_escaped_char(true); } - if (!bcatch && !bfinally) croak("Missing catch/finally blocks"); - return new AST_Try({ - body: body, - bcatch: bcatch, - bfinally: bfinally - }); - } - function vardefs(no_in, in_const) { - var a = []; - for (;;) { - a.push(new AST_VarDef({ - start: S.token, - name: as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), - value: is("operator", "=") ? (next(), expression(false, no_in)) : null, - end: prev() - })); - if (!is("punc", ",")) break; - next(); - } - return a; + else if (ch == quote) break; + ret += ch; } - var var_ = function(no_in) { - return new AST_Var({ - start: prev(), - definitions: vardefs(no_in, false), - end: prev() - }); - }; - var const_ = function() { - return new AST_Const({ - start: prev(), - definitions: vardefs(false, true), - end: prev() - }); - }; - var new_ = function() { - var start = S.token; - expect_token("operator", "new"); - var newexp = expr_atom(false), args; - if (is("punc", "(")) { - next(); - args = expr_list(")"); - } else { - args = []; - } - return subscripts(new AST_New({ - start: start, - expression: newexp, - args: args, - end: prev() - }), true); - }; - function as_atom_node() { - var tok = S.token, ret; - switch (tok.type) { - case "name": - return as_symbol(AST_SymbolRef); - - case "num": - ret = new AST_Number({ - start: tok, - end: tok, - value: tok.value - }); - break; - - case "string": - ret = new AST_String({ - start: tok, - end: tok, - value: tok.value - }); - break; + return token("string", ret); + }); - case "regexp": - ret = new AST_RegExp({ - start: tok, - end: tok, - value: tok.value - }); - break; + function skip_line_comment(type) { + var regex_allowed = S.regex_allowed; + var i = find("\n"), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + S.comments_before.push(token(type, ret, true)); + S.regex_allowed = regex_allowed; + return next_token(); + }; - case "atom": - switch (tok.value) { - case "false": - ret = new AST_False({ - start: tok, - end: tok - }); - break; + var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){ + var regex_allowed = S.regex_allowed; + var i = find("*/", true); + var text = S.text.substring(S.pos, i); + var a = text.split("\n"), n = a.length; + // update stream position + S.pos = i + 2; + S.line += n - 1; + if (n > 1) S.col = a[n - 1].length; + else S.col += a[n - 1].length; + S.col += 2; + var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0; + S.comments_before.push(token("comment2", text, true)); + S.regex_allowed = regex_allowed; + S.newline_before = nlb; + return next_token(); + }); - case "true": - ret = new AST_True({ - start: tok, - end: tok - }); - break; + function read_name() { + var backslash = false, name = "", ch, escaped = false, hex; + while ((ch = peek()) != null) { + if (!backslash) { + if (ch == "\\") escaped = backslash = true, next(); + else if (is_identifier_char(ch)) name += next(); + else break; + } + else { + if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX"); + ch = read_escaped_char(); + if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier"); + name += ch; + backslash = false; + } + } + if (KEYWORDS(name) && escaped) { + hex = name.charCodeAt(0).toString(16).toUpperCase(); + name = "\\u" + "0000".substr(hex.length) + hex + name.slice(1); + } + return name; + }; - case "null": - ret = new AST_Null({ - start: tok, - end: tok - }); - break; - } - break; - } - next(); - return ret; + var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){ + var prev_backslash = false, ch, in_class = false; + while ((ch = next(true))) if (prev_backslash) { + regexp += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + regexp += ch; + } else if (ch == "]" && in_class) { + in_class = false; + regexp += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + regexp += ch; } - var expr_atom = function(allow_calls) { - if (is("operator", "new")) { - return new_(); - } - var start = S.token; - if (is("punc")) { - switch (start.value) { - case "(": - next(); - var ex = expression(true); - ex.start = start; - ex.end = S.token; - expect(")"); - return subscripts(ex, allow_calls); - - case "[": - return subscripts(array_(), allow_calls); - - case "{": - return subscripts(object_(), allow_calls); - } - unexpected(); - } - if (is("keyword", "function")) { + var mods = read_name(); + return token("regexp", new RegExp(regexp, mods)); + }); + + function read_operator(prefix) { + function grow(op) { + if (!peek()) return op; + var bigger = op + peek(); + if (OPERATORS(bigger)) { next(); - var func = function_(false); - func.start = start; - func.end = prev(); - return subscripts(func, allow_calls); - } - if (ATOMIC_START_TOKEN[S.token.type]) { - return subscripts(as_atom_node(), allow_calls); + return grow(bigger); + } else { + return op; } - unexpected(); }; - function expr_list(closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; - while (!is("punc", closing)) { - if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push(new AST_Hole({ - start: S.token, - end: S.token - })); - } else { - a.push(expression(false)); - } - } - next(); - return a; - } - var array_ = embed_tokens(function() { - expect("["); - return new AST_Array({ - elements: expr_list("]", !options.strict, true) - }); - }); - var object_ = embed_tokens(function() { - expect("{"); - var first = true, a = []; - while (!is("punc", "}")) { - if (first) first = false; else expect(","); - if (!options.strict && is("punc", "}")) break; - var start = S.token; - var type = start.type; - var name = as_property_name(); - if (type == "name" && !is("punc", ":")) { - if (name == "get") { - a.push(new AST_ObjectGetter({ - start: start, - key: name, - value: function_(false, AST_Accessor), - end: prev() - })); - continue; - } - if (name == "set") { - a.push(new AST_ObjectSetter({ - start: start, - key: name, - value: function_(false, AST_Accessor), - end: prev() - })); - continue; - } - } - expect(":"); - a.push(new AST_ObjectKeyVal({ - start: start, - key: name, - value: expression(false), - end: prev() - })); - } - next(); - return new AST_Object({ - properties: a - }); - }); - function as_property_name() { - var tmp = S.token; - next(); - switch (tmp.type) { - case "num": - case "string": - case "name": - case "operator": - case "keyword": - case "atom": - return tmp.value; + return token("operator", grow(prefix || next())); + }; - default: - unexpected(); - } - } - function as_name() { - var tmp = S.token; + function handle_slash() { + next(); + switch (peek()) { + case "/": next(); - switch (tmp.type) { - case "name": - case "operator": - case "keyword": - case "atom": - return tmp.value; - - default: - unexpected(); - } - } - function as_symbol(type, noerror) { - if (!is("name")) { - if (!noerror) croak("Name expected"); - return null; - } - var name = S.token.value; - var sym = new (name == "this" ? AST_This : type)({ - name: String(S.token.value), - start: S.token, - end: S.token - }); + return skip_line_comment("comment1"); + case "*": next(); - return sym; + return skip_multiline_comment(); } - var subscripts = function(expr, allow_calls) { - var start = expr.start; - if (is("punc", ".")) { - next(); - return subscripts(new AST_Dot({ - start: start, - expression: expr, - property: as_name(), - end: prev() - }), allow_calls); - } - if (is("punc", "[")) { - next(); - var prop = expression(true); - expect("]"); - return subscripts(new AST_Sub({ - start: start, - expression: expr, - property: prop, - end: prev() - }), allow_calls); - } - if (allow_calls && is("punc", "(")) { - next(); - return subscripts(new AST_Call({ - start: start, - expression: expr, - args: expr_list(")"), - end: prev() - }), true); - } - return expr; - }; - var maybe_unary = function(allow_calls) { - var start = S.token; - if (is("operator") && UNARY_PREFIX(start.value)) { - next(); - var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); - ex.start = start; - ex.end = prev(); - return ex; - } - var val = expr_atom(allow_calls); - while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { - val = make_unary(AST_UnaryPostfix, S.token.value, val); - val.start = start; - val.end = S.token; - next(); + return S.regex_allowed ? read_regexp("") : read_operator("/"); + }; + + function handle_dot() { + next(); + return is_digit(peek().charCodeAt(0)) + ? read_num(".") + : token("punc", "."); + }; + + function read_word() { + var word = read_name(); + if (prev_was_dot) return token("name", word); + return KEYWORDS_ATOM(word) ? token("atom", word) + : !KEYWORDS(word) ? token("name", word) + : OPERATORS(word) ? token("operator", word) + : token("keyword", word); + }; + + function with_eof_error(eof_error, cont) { + return function(x) { + try { + return cont(x); + } catch(ex) { + if (ex === EX_EOF) parse_error(eof_error); + else throw ex; } - return val; }; - function make_unary(ctor, op, expr) { - if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator"); - return new ctor({ - operator: op, - expression: expr - }); + }; + + function next_token(force_regexp) { + if (force_regexp != null) + return read_regexp(force_regexp); + skip_whitespace(); + start_token(); + if (html5_comments) { + if (looking_at("") && S.newline_before) { + forward(3); + return skip_line_comment("comment4"); + } + } + var ch = peek(); + if (!ch) return token("eof"); + var code = ch.charCodeAt(0); + switch (code) { + case 34: case 39: return read_string(); + case 46: return handle_dot(); + case 47: return handle_slash(); + } + if (is_digit(code)) return read_num(); + if (PUNC_CHARS(ch)) return token("punc", next()); + if (OPERATOR_CHARS(ch)) return read_operator(); + if (code == 92 || is_identifier_start(code)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = makePredicate([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = makePredicate([ "--", "++" ]); + +var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0; i < a.length; ++i) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = i + 1; } - var expr_op = function(left, min_prec, no_in) { - var op = is("operator") ? S.token.value : null; - if (op == "in" && no_in) op = null; - var prec = op != null ? PRECEDENCE[op] : null; - if (prec != null && prec > min_prec) { - next(); - var right = expr_op(maybe_unary(true), prec, no_in); - return expr_op(new AST_Binary({ - start: left.start, - left: left, - operator: op, - right: right, - end: right.end - }), min_prec, no_in); - } - return left; - }; - function expr_ops(no_in) { - return expr_op(maybe_unary(true), 0, no_in); + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function parse($TEXT, options) { + + options = defaults(options, { + strict : false, + filename : null, + toplevel : null, + expression : false, + html5_comments : true, + }); + + var S = { + input : (typeof $TEXT == "string" + ? tokenizer($TEXT, options.filename, + options.html5_comments) + : $TEXT), + token : null, + prev : null, + peeked : null, + in_function : 0, + in_directives : true, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + S.in_directives = S.in_directives && ( + S.token.type == "string" || is("punc", ";") + ); + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + ctx.filename, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); } - var maybe_conditional = function(no_in) { + token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !options.strict && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function parenthesised() { + expect("("); + var exp = expression(true); + expect(")"); + return exp; + }; + + function embed_tokens(parser) { + return function() { var start = S.token; - var expr = expr_ops(no_in); - if (is("operator", "?")) { - next(); - var yes = expression(false); - expect(":"); - return new AST_Conditional({ - start: start, - condition: expr, - consequent: yes, - alternative: expression(false, no_in), - end: peek() - }); - } + var expr = parser(); + var end = prev(); + expr.start = start; + expr.end = end; return expr; }; - function is_assignable(expr) { - if (!options.strict) return true; - if (expr instanceof AST_This) return false; - return expr instanceof AST_PropAccess || expr instanceof AST_Symbol; + }; + + function handle_regexp() { + if (is("operator", "/") || is("operator", "/=")) { + S.peeked = null; + S.token = S.input(S.token.value.substr(1)); // force regexp } - var maybe_assign = function(no_in) { - var start = S.token; - var left = maybe_conditional(no_in), val = S.token.value; - if (is("operator") && ASSIGNMENT(val)) { - if (is_assignable(left)) { - next(); - return new AST_Assign({ - start: start, - left: left, - operator: val, - right: maybe_assign(no_in), - end: prev() - }); - } - croak("Invalid assignment"); - } - return left; - }; - var expression = function(commas, no_in) { - var start = S.token; - var expr = maybe_assign(no_in); - if (commas && is("punc", ",")) { - next(); - return new AST_Seq({ - start: start, - car: expr, - cdr: expression(true, no_in), - end: peek() + }; + + var statement = embed_tokens(function() { + var tmp; + handle_regexp(); + switch (S.token.type) { + case "string": + var dir = S.in_directives, stat = simple_statement(); + // XXXv2: decide how to fix directives + if (dir && stat.body instanceof AST_String && !is("punc", ",")) + return new AST_Directive({ value: stat.body.value }); + return stat; + case "num": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement() + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return new AST_BlockStatement({ + start : S.token, + body : block_(), + end : prev() }); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return new AST_EmptyStatement(); + default: + unexpected(); } - return expr; - }; - function in_loop(cont) { - ++S.in_loop; - var ret = cont(); - --S.in_loop; - return ret; - } - if (options.expression) { - return expression(true); - } - return function() { - var start = S.token; - var body = []; - while (!is("eof")) body.push(statement()); - var end = prev(); - var toplevel = options.toplevel; - if (toplevel) { - toplevel.body = toplevel.body.concat(body); - toplevel.end = end; - } else { - toplevel = new AST_Toplevel({ - start: start, - body: body, - end: end + + case "keyword": + switch (tmp = S.token.value, next(), tmp) { + case "break": + return break_cont(AST_Break); + + case "continue": + return break_cont(AST_Continue); + + case "debugger": + semicolon(); + return new AST_Debugger(); + + case "do": + return new AST_Do({ + body : in_loop(statement), + condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp) + }); + + case "while": + return new AST_While({ + condition : parenthesised(), + body : in_loop(statement) + }); + + case "for": + return for_(); + + case "function": + return function_(AST_Defun); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return new AST_Return({ + value: ( is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : (tmp = expression(true), semicolon(), tmp) ) + }); + + case "switch": + return new AST_Switch({ + expression : parenthesised(), + body : in_loop(switch_body_) + }); + + case "throw": + if (S.token.nlb) + croak("Illegal newline after 'throw'"); + return new AST_Throw({ + value: (tmp = expression(true), semicolon(), tmp) }); + + case "try": + return try_(); + + case "var": + return tmp = var_(), semicolon(), tmp; + + case "const": + return tmp = const_(), semicolon(), tmp; + + case "with": + return new AST_With({ + expression : parenthesised(), + body : statement() + }); + + default: + unexpected(); } - return toplevel; - }(); - } - "use strict"; - function TreeTransformer(before, after) { - TreeWalker.call(this); - this.before = before; - this.after = after; - } - TreeTransformer.prototype = new TreeWalker(); - (function(undefined) { - function _(node, descend) { - node.DEFMETHOD("transform", function(tw, in_list) { - var x, y; - tw.push(this); - if (tw.before) x = tw.before(this, descend, in_list); - if (x === undefined) { - if (!tw.after) { - x = this; - descend(x, tw); - } else { - tw.stack[tw.stack.length - 1] = x = this.clone(); - descend(x, tw); - y = tw.after(x, in_list); - if (y !== undefined) x = y; - } + } + }); + + function labeled_statement() { + var label = as_symbol(AST_Label); + if (find_if(function(l){ return l.name == label.name }, S.labels)) { + // ECMA-262, 12.12: An ECMAScript program is considered + // syntactically incorrect if it contains a + // LabelledStatement that is enclosed by a + // LabelledStatement with the same Identifier as label. + croak("Label " + label.name + " defined twice"); + } + expect(":"); + S.labels.push(label); + var stat = statement(); + S.labels.pop(); + if (!(stat instanceof AST_IterationStatement)) { + // check for `continue` that refers to this label. + // those should be reported as syntax errors. + // https://github.com/mishoo/UglifyJS2/issues/287 + label.references.forEach(function(ref){ + if (ref instanceof AST_Continue) { + ref = ref.label.start; + croak("Continue label `" + label.name + "` refers to non-IterationStatement.", + ref.line, ref.col, ref.pos); } - tw.pop(); - return x; }); } - function do_list(list, tw) { - return MAP(list, function(node) { - return node.transform(tw, true); - }); + return new AST_LabeledStatement({ body: stat, label: label }); + }; + + function simple_statement(tmp) { + return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); + }; + + function break_cont(type) { + var label = null, ldef; + if (!can_insert_semicolon()) { + label = as_symbol(AST_LabelRef, true); + } + if (label != null) { + ldef = find_if(function(l){ return l.name == label.name }, S.labels); + if (!ldef) + croak("Undefined label " + label.name); + label.thedef = ldef; + } + else if (S.in_loop == 0) + croak(type.TYPE + " not inside a loop or switch"); + semicolon(); + var stat = new type({ label: label }); + if (ldef) ldef.references.push(stat); + return stat; + }; + + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) { + if (init instanceof AST_Var && init.definitions.length > 1) + croak("Only one variable declaration allowed in for..in loop"); + next(); + return for_in(init); + } } - _(AST_Node, noop); - _(AST_LabeledStatement, function(self, tw) { - self.label = self.label.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_SimpleStatement, function(self, tw) { - self.body = self.body.transform(tw); - }); - _(AST_Block, function(self, tw) { - self.body = do_list(self.body, tw); - }); - _(AST_DWLoop, function(self, tw) { - self.condition = self.condition.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_For, function(self, tw) { - if (self.init) self.init = self.init.transform(tw); - if (self.condition) self.condition = self.condition.transform(tw); - if (self.step) self.step = self.step.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_ForIn, function(self, tw) { - self.init = self.init.transform(tw); - self.object = self.object.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_With, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_Exit, function(self, tw) { - if (self.value) self.value = self.value.transform(tw); - }); - _(AST_LoopControl, function(self, tw) { - if (self.label) self.label = self.label.transform(tw); - }); - _(AST_If, function(self, tw) { - self.condition = self.condition.transform(tw); - self.body = self.body.transform(tw); - if (self.alternative) self.alternative = self.alternative.transform(tw); - }); - _(AST_Switch, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = do_list(self.body, tw); - }); - _(AST_Case, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = do_list(self.body, tw); - }); - _(AST_Try, function(self, tw) { - self.body = do_list(self.body, tw); - if (self.bcatch) self.bcatch = self.bcatch.transform(tw); - if (self.bfinally) self.bfinally = self.bfinally.transform(tw); - }); - _(AST_Catch, function(self, tw) { - self.argname = self.argname.transform(tw); - self.body = do_list(self.body, tw); - }); - _(AST_Definitions, function(self, tw) { - self.definitions = do_list(self.definitions, tw); - }); - _(AST_VarDef, function(self, tw) { - self.name = self.name.transform(tw); - if (self.value) self.value = self.value.transform(tw); - }); - _(AST_Lambda, function(self, tw) { - if (self.name) self.name = self.name.transform(tw); - self.argnames = do_list(self.argnames, tw); - self.body = do_list(self.body, tw); - }); - _(AST_Call, function(self, tw) { - self.expression = self.expression.transform(tw); - self.args = do_list(self.args, tw); - }); - _(AST_Seq, function(self, tw) { - self.car = self.car.transform(tw); - self.cdr = self.cdr.transform(tw); - }); - _(AST_Dot, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - _(AST_Sub, function(self, tw) { - self.expression = self.expression.transform(tw); - self.property = self.property.transform(tw); + return regular_for(init); + }; + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(true); + expect(";"); + var step = is("punc", ")") ? null : expression(true); + expect(")"); + return new AST_For({ + init : init, + condition : test, + step : step, + body : in_loop(statement) }); - _(AST_Unary, function(self, tw) { - self.expression = self.expression.transform(tw); + }; + + function for_in(init) { + var lhs = init instanceof AST_Var ? init.definitions[0].name : null; + var obj = expression(true); + expect(")"); + return new AST_ForIn({ + init : init, + name : lhs, + object : obj, + body : in_loop(statement) }); - _(AST_Binary, function(self, tw) { - self.left = self.left.transform(tw); - self.right = self.right.transform(tw); + }; + + var function_ = function(ctor) { + var in_statement = ctor === AST_Defun; + var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return new ctor({ + name: name, + argnames: (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + a.push(as_symbol(AST_SymbolFunarg)); + } + next(); + return a; + })(true, []), + body: (function(loop, labels){ + ++S.in_function; + S.in_directives = true; + S.in_loop = 0; + S.labels = []; + var a = block_(); + --S.in_function; + S.in_loop = loop; + S.labels = labels; + return a; + })(S.in_loop, S.labels) }); - _(AST_Conditional, function(self, tw) { - self.condition = self.condition.transform(tw); - self.consequent = self.consequent.transform(tw); - self.alternative = self.alternative.transform(tw); + }; + + function if_() { + var cond = parenthesised(), body = statement(), belse = null; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return new AST_If({ + condition : cond, + body : body, + alternative : belse }); - _(AST_Array, function(self, tw) { - self.elements = do_list(self.elements, tw); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + function switch_body_() { + expect("{"); + var a = [], cur = null, branch = null, tmp; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Case({ + start : (tmp = S.token, next(), tmp), + expression : expression(true), + body : cur + }); + a.push(branch); + expect(":"); + } + else if (is("keyword", "default")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Default({ + start : (tmp = S.token, next(), expect(":"), tmp), + body : cur + }); + a.push(branch); + } + else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + if (branch) branch.end = prev(); + next(); + return a; + }; + + function try_() { + var body = block_(), bcatch = null, bfinally = null; + if (is("keyword", "catch")) { + var start = S.token; + next(); + expect("("); + var name = as_symbol(AST_SymbolCatch); + expect(")"); + bcatch = new AST_Catch({ + start : start, + argname : name, + body : block_(), + end : prev() + }); + } + if (is("keyword", "finally")) { + var start = S.token; + next(); + bfinally = new AST_Finally({ + start : start, + body : block_(), + end : prev() + }); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return new AST_Try({ + body : body, + bcatch : bcatch, + bfinally : bfinally }); - _(AST_Object, function(self, tw) { - self.properties = do_list(self.properties, tw); + }; + + function vardefs(no_in, in_const) { + var a = []; + for (;;) { + a.push(new AST_VarDef({ + start : S.token, + name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), + value : is("operator", "=") ? (next(), expression(false, no_in)) : null, + end : prev() + })); + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + var var_ = function(no_in) { + return new AST_Var({ + start : prev(), + definitions : vardefs(no_in, false), + end : prev() }); - _(AST_ObjectProperty, function(self, tw) { - self.value = self.value.transform(tw); + }; + + var const_ = function() { + return new AST_Const({ + start : prev(), + definitions : vardefs(false, true), + end : prev() }); - })(); - "use strict"; - function SymbolDef(scope, index, orig) { - this.name = orig.name; - this.orig = [ orig ]; - this.scope = scope; - this.references = []; - this.global = false; - this.mangled_name = null; - this.undeclared = false; - this.constant = false; - this.index = index; - } - SymbolDef.prototype = { - unmangleable: function(options) { - return this.global && !(options && options.toplevel) || this.undeclared || !(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with); - }, - mangle: function(options) { - if (!this.mangled_name && !this.unmangleable(options)) { - var s = this.scope; - if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8) s = s.parent_scope; - this.mangled_name = s.next_mangled(options); + }; + + var new_ = function() { + var start = S.token; + expect_token("operator", "new"); + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(new AST_New({ + start : start, + expression : newexp, + args : args, + end : prev() + }), true); + }; + + function as_atom_node() { + var tok = S.token, ret; + switch (tok.type) { + case "name": + case "keyword": + ret = _make_symbol(AST_SymbolRef); + break; + case "num": + ret = new AST_Number({ start: tok, end: tok, value: tok.value }); + break; + case "string": + ret = new AST_String({ start: tok, end: tok, value: tok.value }); + break; + case "regexp": + ret = new AST_RegExp({ start: tok, end: tok, value: tok.value }); + break; + case "atom": + switch (tok.value) { + case "false": + ret = new AST_False({ start: tok, end: tok }); + break; + case "true": + ret = new AST_True({ start: tok, end: tok }); + break; + case "null": + ret = new AST_Null({ start: tok, end: tok }); + break; } + break; } + next(); + return ret; }; - AST_Toplevel.DEFMETHOD("figure_out_scope", function() { - var self = this; - var scope = self.parent_scope = null; - var labels = new Dictionary(); - var nesting = 0; - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_Scope) { - node.init_scope_vars(nesting); - var save_scope = node.parent_scope = scope; - var save_labels = labels; - ++nesting; - scope = node; - labels = new Dictionary(); - descend(); - labels = save_labels; - scope = save_scope; - --nesting; - return true; - } - if (node instanceof AST_Directive) { - node.scope = scope; - push_uniq(scope.directives, node.value); - return true; - } - if (node instanceof AST_With) { - for (var s = scope; s; s = s.parent_scope) s.uses_with = true; - return; - } - if (node instanceof AST_LabeledStatement) { - var l = node.label; - if (labels.has(l.name)) throw new Error(string_template("Label {name} defined twice", l)); - labels.set(l.name, l); - descend(); - labels.del(l.name); - return true; - } - if (node instanceof AST_Symbol) { - node.scope = scope; - } - if (node instanceof AST_Label) { - node.thedef = node; - node.init_scope_vars(); - } - if (node instanceof AST_SymbolLambda) { - scope.def_function(node); - } else if (node instanceof AST_SymbolDefun) { - (node.scope = scope.parent_scope).def_function(node); - } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) { - var def = scope.def_variable(node); - def.constant = node instanceof AST_SymbolConst; - def.init = tw.parent().value; - } else if (node instanceof AST_SymbolCatch) { - scope.def_variable(node); + + var expr_atom = function(allow_calls) { + if (is("operator", "new")) { + return new_(); + } + var start = S.token; + if (is("punc")) { + switch (start.value) { + case "(": + next(); + var ex = expression(true); + ex.start = start; + ex.end = S.token; + expect(")"); + return subscripts(ex, allow_calls); + case "[": + return subscripts(array_(), allow_calls); + case "{": + return subscripts(object_(), allow_calls); } - if (node instanceof AST_LabelRef) { - var sym = labels.get(node.name); - if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { - name: node.name, - line: node.start.line, - col: node.start.col - })); - node.thedef = sym; + unexpected(); + } + if (is("keyword", "function")) { + next(); + var func = function_(AST_Function); + func.start = start; + func.end = prev(); + return subscripts(func, allow_calls); + } + if (ATOMIC_START_TOKEN[S.token.type]) { + return subscripts(as_atom_node(), allow_calls); + } + unexpected(); + }; + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push(new AST_Hole({ start: S.token, end: S.token })); + } else { + a.push(expression(false)); } + } + next(); + return a; + }; + + var array_ = embed_tokens(function() { + expect("["); + return new AST_Array({ + elements: expr_list("]", !options.strict, true) }); - self.walk(tw); - var func = null; - var globals = self.globals = new Dictionary(); - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_Lambda) { - var prev_func = func; - func = node; - descend(); - func = prev_func; - return true; + }); + + var object_ = embed_tokens(function() { + expect("{"); + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!options.strict && is("punc", "}")) + // allow trailing comma + break; + var start = S.token; + var type = start.type; + var name = as_property_name(); + if (type == "name" && !is("punc", ":")) { + if (name == "get") { + a.push(new AST_ObjectGetter({ + start : start, + key : as_atom_node(), + value : function_(AST_Accessor), + end : prev() + })); + continue; + } + if (name == "set") { + a.push(new AST_ObjectSetter({ + start : start, + key : as_atom_node(), + value : function_(AST_Accessor), + end : prev() + })); + continue; + } } - if (node instanceof AST_LabelRef) { - node.reference(); - return true; + expect(":"); + a.push(new AST_ObjectKeyVal({ + start : start, + key : name, + value : expression(false), + end : prev() + })); + } + next(); + return new AST_Object({ properties: a }); + }); + + function as_property_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "num": + case "string": + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + default: + unexpected(); + } + }; + + function as_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + default: + unexpected(); + } + }; + + function _make_symbol(type) { + var name = S.token.value; + return new (name == "this" ? AST_This : type)({ + name : String(name), + start : S.token, + end : S.token + }); + }; + + function as_symbol(type, noerror) { + if (!is("name")) { + if (!noerror) croak("Name expected"); + return null; + } + var sym = _make_symbol(type); + next(); + return sym; + }; + + var subscripts = function(expr, allow_calls) { + var start = expr.start; + if (is("punc", ".")) { + next(); + return subscripts(new AST_Dot({ + start : start, + expression : expr, + property : as_name(), + end : prev() + }), allow_calls); + } + if (is("punc", "[")) { + next(); + var prop = expression(true); + expect("]"); + return subscripts(new AST_Sub({ + start : start, + expression : expr, + property : prop, + end : prev() + }), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(new AST_Call({ + start : start, + expression : expr, + args : expr_list(")"), + end : prev() + }), true); + } + return expr; + }; + + var maybe_unary = function(allow_calls) { + var start = S.token; + if (is("operator") && UNARY_PREFIX(start.value)) { + next(); + handle_regexp(); + var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); + ex.start = start; + ex.end = prev(); + return ex; + } + var val = expr_atom(allow_calls); + while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { + val = make_unary(AST_UnaryPostfix, S.token.value, val); + val.start = start; + val.end = S.token; + next(); + } + return val; + }; + + function make_unary(ctor, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return new ctor({ operator: op, expression: expr }); + }; + + var expr_op = function(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(new AST_Binary({ + start : left.start, + left : left, + operator : op, + right : right, + end : right.end + }), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(maybe_unary(true), 0, no_in); + }; + + var maybe_conditional = function(no_in) { + var start = S.token; + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return new AST_Conditional({ + start : start, + condition : expr, + consequent : yes, + alternative : expression(false, no_in), + end : peek() + }); + } + return expr; + }; + + function is_assignable(expr) { + if (!options.strict) return true; + if (expr instanceof AST_This) return false; + return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol); + }; + + var maybe_assign = function(no_in) { + var start = S.token; + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && ASSIGNMENT(val)) { + if (is_assignable(left)) { + next(); + return new AST_Assign({ + start : start, + left : left, + operator : val, + right : maybe_assign(no_in), + end : prev() + }); } - if (node instanceof AST_SymbolRef) { - var name = node.name; - var sym = node.scope.find_variable(name); - if (!sym) { - var g; - if (globals.has(name)) { - g = globals.get(name); - } else { - g = new SymbolDef(self, globals.size(), node); - g.undeclared = true; - g.global = true; - globals.set(name, g); - } - node.thedef = g; - if (name == "eval" && tw.parent() instanceof AST_Call) { - for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) s.uses_eval = true; - } - if (name == "arguments") { - func.uses_arguments = true; - } + croak("Invalid assignment"); + } + return left; + }; + + var expression = function(commas, no_in) { + var start = S.token; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return new AST_Seq({ + start : start, + car : expr, + cdr : expression(true, no_in), + end : peek() + }); + } + return expr; + }; + + function in_loop(cont) { + ++S.in_loop; + var ret = cont(); + --S.in_loop; + return ret; + }; + + if (options.expression) { + return expression(true); + } + + return (function(){ + var start = S.token; + var body = []; + while (!is("eof")) + body.push(statement()); + var end = prev(); + var toplevel = options.toplevel; + if (toplevel) { + toplevel.body = toplevel.body.concat(body); + toplevel.end = end; + } else { + toplevel = new AST_Toplevel({ start: start, body: body, end: end }); + } + return toplevel; + })(); + +}; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +"use strict"; + +// Tree transformer helpers. + +function TreeTransformer(before, after) { + TreeWalker.call(this); + this.before = before; + this.after = after; +} +TreeTransformer.prototype = new TreeWalker; + +(function(undefined){ + + function _(node, descend) { + node.DEFMETHOD("transform", function(tw, in_list){ + var x, y; + tw.push(this); + if (tw.before) x = tw.before(this, descend, in_list); + if (x === undefined) { + if (!tw.after) { + x = this; + descend(x, tw); } else { - node.thedef = sym; + tw.stack[tw.stack.length - 1] = x = this.clone(); + descend(x, tw); + y = tw.after(x, in_list); + if (y !== undefined) x = y; } - node.reference(); - return true; } + tw.pop(); + return x; }); - self.walk(tw); - }); - AST_Scope.DEFMETHOD("init_scope_vars", function(nesting) { - this.directives = []; - this.variables = new Dictionary(); - this.functions = new Dictionary(); - this.uses_with = false; - this.uses_eval = false; - this.parent_scope = null; - this.enclosed = []; - this.cname = -1; - this.nesting = nesting; - }); - AST_Scope.DEFMETHOD("strict", function() { - return this.has_directive("use strict"); - }); - AST_Lambda.DEFMETHOD("init_scope_vars", function() { - AST_Scope.prototype.init_scope_vars.apply(this, arguments); - this.uses_arguments = false; - }); - AST_SymbolRef.DEFMETHOD("reference", function() { - var def = this.definition(); - def.references.push(this); - var s = this.scope; - while (s) { - push_uniq(s.enclosed, def); - if (s === def.scope) break; - s = s.parent_scope; - } - this.frame = this.scope.nesting - def.scope.nesting; - }); - AST_Label.DEFMETHOD("init_scope_vars", function() { - this.references = []; + }; + + function do_list(list, tw) { + return MAP(list, function(node){ + return node.transform(tw, true); + }); + }; + + _(AST_Node, noop); + + _(AST_LabeledStatement, function(self, tw){ + self.label = self.label.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_SimpleStatement, function(self, tw){ + self.body = self.body.transform(tw); + }); + + _(AST_Block, function(self, tw){ + self.body = do_list(self.body, tw); + }); + + _(AST_DWLoop, function(self, tw){ + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_For, function(self, tw){ + if (self.init) self.init = self.init.transform(tw); + if (self.condition) self.condition = self.condition.transform(tw); + if (self.step) self.step = self.step.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_ForIn, function(self, tw){ + self.init = self.init.transform(tw); + self.object = self.object.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_With, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_Exit, function(self, tw){ + if (self.value) self.value = self.value.transform(tw); + }); + + _(AST_LoopControl, function(self, tw){ + if (self.label) self.label = self.label.transform(tw); + }); + + _(AST_If, function(self, tw){ + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + if (self.alternative) self.alternative = self.alternative.transform(tw); + }); + + _(AST_Switch, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Case, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Try, function(self, tw){ + self.body = do_list(self.body, tw); + if (self.bcatch) self.bcatch = self.bcatch.transform(tw); + if (self.bfinally) self.bfinally = self.bfinally.transform(tw); + }); + + _(AST_Catch, function(self, tw){ + self.argname = self.argname.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Definitions, function(self, tw){ + self.definitions = do_list(self.definitions, tw); + }); + + _(AST_VarDef, function(self, tw){ + self.name = self.name.transform(tw); + if (self.value) self.value = self.value.transform(tw); + }); + + _(AST_Lambda, function(self, tw){ + if (self.name) self.name = self.name.transform(tw); + self.argnames = do_list(self.argnames, tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Call, function(self, tw){ + self.expression = self.expression.transform(tw); + self.args = do_list(self.args, tw); + }); + + _(AST_Seq, function(self, tw){ + self.car = self.car.transform(tw); + self.cdr = self.cdr.transform(tw); + }); + + _(AST_Dot, function(self, tw){ + self.expression = self.expression.transform(tw); + }); + + _(AST_Sub, function(self, tw){ + self.expression = self.expression.transform(tw); + self.property = self.property.transform(tw); + }); + + _(AST_Unary, function(self, tw){ + self.expression = self.expression.transform(tw); + }); + + _(AST_Binary, function(self, tw){ + self.left = self.left.transform(tw); + self.right = self.right.transform(tw); + }); + + _(AST_Conditional, function(self, tw){ + self.condition = self.condition.transform(tw); + self.consequent = self.consequent.transform(tw); + self.alternative = self.alternative.transform(tw); + }); + + _(AST_Array, function(self, tw){ + self.elements = do_list(self.elements, tw); }); - AST_LabelRef.DEFMETHOD("reference", function() { - this.thedef.references.push(this); + + _(AST_Object, function(self, tw){ + self.properties = do_list(self.properties, tw); + }); + + _(AST_ObjectProperty, function(self, tw){ + self.value = self.value.transform(tw); + }); + +})(); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +"use strict"; + +function SymbolDef(scope, index, orig) { + this.name = orig.name; + this.orig = [ orig ]; + this.scope = scope; + this.references = []; + this.global = false; + this.mangled_name = null; + this.undeclared = false; + this.constant = false; + this.index = index; +}; + +SymbolDef.prototype = { + unmangleable: function(options) { + return (this.global && !(options && options.toplevel)) + || this.undeclared + || (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with)); + }, + mangle: function(options) { + if (!this.mangled_name && !this.unmangleable(options)) { + var s = this.scope; + if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda) + s = s.parent_scope; + this.mangled_name = s.next_mangled(options, this); + } + } +}; + +AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ + options = defaults(options, { + screw_ie8: false }); - AST_Scope.DEFMETHOD("find_variable", function(name) { - if (name instanceof AST_Symbol) name = name.name; - return this.variables.get(name) || this.parent_scope && this.parent_scope.find_variable(name); + + // pass 1: setup scope chaining and handle definitions + var self = this; + var scope = self.parent_scope = null; + var defun = null; + var nesting = 0; + var tw = new TreeWalker(function(node, descend){ + if (options.screw_ie8 && node instanceof AST_Catch) { + var save_scope = scope; + scope = new AST_Scope(node); + scope.init_scope_vars(nesting); + scope.parent_scope = save_scope; + descend(); + scope = save_scope; + return true; + } + if (node instanceof AST_Scope) { + node.init_scope_vars(nesting); + var save_scope = node.parent_scope = scope; + var save_defun = defun; + defun = scope = node; + ++nesting; descend(); --nesting; + scope = save_scope; + defun = save_defun; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_Directive) { + node.scope = scope; + push_uniq(scope.directives, node.value); + return true; + } + if (node instanceof AST_With) { + for (var s = scope; s; s = s.parent_scope) + s.uses_with = true; + return; + } + if (node instanceof AST_Symbol) { + node.scope = scope; + } + if (node instanceof AST_SymbolLambda) { + defun.def_function(node); + } + else if (node instanceof AST_SymbolDefun) { + // Careful here, the scope where this should be defined is + // the parent scope. The reason is that we enter a new + // scope when we encounter the AST_Defun node (which is + // instanceof AST_Scope) but we get to the symbol a bit + // later. + (node.scope = defun.parent_scope).def_function(node); + } + else if (node instanceof AST_SymbolVar + || node instanceof AST_SymbolConst) { + var def = defun.def_variable(node); + def.constant = node instanceof AST_SymbolConst; + def.init = tw.parent().value; + } + else if (node instanceof AST_SymbolCatch) { + (options.screw_ie8 ? scope : defun) + .def_variable(node); + } }); - AST_Scope.DEFMETHOD("has_directive", function(value) { - return this.parent_scope && this.parent_scope.has_directive(value) || (this.directives.indexOf(value) >= 0 ? this : null); + self.walk(tw); + + // pass 2: find back references and eval + var func = null; + var globals = self.globals = new Dictionary(); + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_Lambda) { + var prev_func = func; + func = node; + descend(); + func = prev_func; + return true; + } + if (node instanceof AST_SymbolRef) { + var name = node.name; + var sym = node.scope.find_variable(name); + if (!sym) { + var g; + if (globals.has(name)) { + g = globals.get(name); + } else { + g = new SymbolDef(self, globals.size(), node); + g.undeclared = true; + g.global = true; + globals.set(name, g); + } + node.thedef = g; + if (name == "eval" && tw.parent() instanceof AST_Call) { + for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) + s.uses_eval = true; + } + if (func && name == "arguments") { + func.uses_arguments = true; + } + } else { + node.thedef = sym; + } + node.reference(); + return true; + } }); - AST_Scope.DEFMETHOD("def_function", function(symbol) { - this.functions.set(symbol.name, this.def_variable(symbol)); + self.walk(tw); +}); + +AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){ + this.directives = []; // contains the directives defined in this scope, i.e. "use strict" + this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) + this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) + this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement + this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` + this.parent_scope = null; // the parent scope + this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes + this.cname = -1; // the current index for mangling functions/variables + this.nesting = nesting; // the nesting level of this scope (0 means toplevel) +}); + +AST_Scope.DEFMETHOD("strict", function(){ + return this.has_directive("use strict"); +}); + +AST_Lambda.DEFMETHOD("init_scope_vars", function(){ + AST_Scope.prototype.init_scope_vars.apply(this, arguments); + this.uses_arguments = false; +}); + +AST_SymbolRef.DEFMETHOD("reference", function() { + var def = this.definition(); + def.references.push(this); + var s = this.scope; + while (s) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + s = s.parent_scope; + } + this.frame = this.scope.nesting - def.scope.nesting; +}); + +AST_Scope.DEFMETHOD("find_variable", function(name){ + if (name instanceof AST_Symbol) name = name.name; + return this.variables.get(name) + || (this.parent_scope && this.parent_scope.find_variable(name)); +}); + +AST_Scope.DEFMETHOD("has_directive", function(value){ + return this.parent_scope && this.parent_scope.has_directive(value) + || (this.directives.indexOf(value) >= 0 ? this : null); +}); + +AST_Scope.DEFMETHOD("def_function", function(symbol){ + this.functions.set(symbol.name, this.def_variable(symbol)); +}); + +AST_Scope.DEFMETHOD("def_variable", function(symbol){ + var def; + if (!this.variables.has(symbol.name)) { + def = new SymbolDef(this, this.variables.size(), symbol); + this.variables.set(symbol.name, def); + def.global = !this.parent_scope; + } else { + def = this.variables.get(symbol.name); + def.orig.push(symbol); + } + return symbol.thedef = def; +}); + +AST_Scope.DEFMETHOD("next_mangled", function(options){ + var ext = this.enclosed; + out: while (true) { + var m = base54(++this.cname); + if (!is_identifier(m)) continue; // skip over "do" + + // https://github.com/mishoo/UglifyJS2/issues/242 -- do not + // shadow a name excepted from mangling. + if (options.except.indexOf(m) >= 0) continue; + + // we must ensure that the mangled name does not shadow a name + // from some parent scope that is referenced in this or in + // inner scopes. + for (var i = ext.length; --i >= 0;) { + var sym = ext[i]; + var name = sym.mangled_name || (sym.unmangleable(options) && sym.name); + if (m == name) continue out; + } + return m; + } +}); + +AST_Function.DEFMETHOD("next_mangled", function(options, def){ + // #179, #326 + // in Safari strict mode, something like (function x(x){...}) is a syntax error; + // a function expression's argument cannot shadow the function expression's name + + var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition(); + while (true) { + var name = AST_Lambda.prototype.next_mangled.call(this, options, def); + if (!(tricky_def && tricky_def.mangled_name == name)) + return name; + } +}); + +AST_Scope.DEFMETHOD("references", function(sym){ + if (sym instanceof AST_Symbol) sym = sym.definition(); + return this.enclosed.indexOf(sym) < 0 ? null : sym; +}); + +AST_Symbol.DEFMETHOD("unmangleable", function(options){ + return this.definition().unmangleable(options); +}); + +// property accessors are not mangleable +AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){ + return true; +}); + +// labels are always mangleable +AST_Label.DEFMETHOD("unmangleable", function(){ + return false; +}); + +AST_Symbol.DEFMETHOD("unreferenced", function(){ + return this.definition().references.length == 0 + && !(this.scope.uses_eval || this.scope.uses_with); +}); + +AST_Symbol.DEFMETHOD("undeclared", function(){ + return this.definition().undeclared; +}); + +AST_LabelRef.DEFMETHOD("undeclared", function(){ + return false; +}); + +AST_Label.DEFMETHOD("undeclared", function(){ + return false; +}); + +AST_Symbol.DEFMETHOD("definition", function(){ + return this.thedef; +}); + +AST_Symbol.DEFMETHOD("global", function(){ + return this.definition().global; +}); + +AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ + return defaults(options, { + except : [], + eval : false, + sort : false, + toplevel : false, + screw_ie8 : false }); - AST_Scope.DEFMETHOD("def_variable", function(symbol) { - var def; - if (!this.variables.has(symbol.name)) { - def = new SymbolDef(this, this.variables.size(), symbol); - this.variables.set(symbol.name, def); - def.global = !this.parent_scope; - } else { - def = this.variables.get(symbol.name); - def.orig.push(symbol); - } - return symbol.thedef = def; - }); - AST_Scope.DEFMETHOD("next_mangled", function(options) { - var ext = this.enclosed; - out: while (true) { - var m = base54(++this.cname); - if (!is_identifier(m)) continue; - for (var i = ext.length; --i >= 0; ) { - var sym = ext[i]; - var name = sym.mangled_name || sym.unmangleable(options) && sym.name; - if (m == name) continue out; - } - return m; +}); + +AST_Toplevel.DEFMETHOD("mangle_names", function(options){ + options = this._default_mangler_options(options); + // We only need to mangle declaration nodes. Special logic wired + // into the code generator will display the mangled name if it's + // present (and for AST_SymbolRef-s it'll use the mangled name of + // the AST_SymbolDeclaration that it points to). + var lname = -1; + var to_mangle = []; + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_LabeledStatement) { + // lname is incremented when we get to the AST_Label + var save_nesting = lname; + descend(); + lname = save_nesting; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_Scope) { + var p = tw.parent(), a = []; + node.variables.each(function(symbol){ + if (options.except.indexOf(symbol.name) < 0) { + a.push(symbol); + } + }); + if (options.sort) a.sort(function(a, b){ + return b.references.length - a.references.length; + }); + to_mangle.push.apply(to_mangle, a); + return; + } + if (node instanceof AST_Label) { + var name; + do name = base54(++lname); while (!is_identifier(name)); + node.mangled_name = name; + return true; } }); - AST_Scope.DEFMETHOD("references", function(sym) { - if (sym instanceof AST_Symbol) sym = sym.definition(); - return this.enclosed.indexOf(sym) < 0 ? null : sym; - }); - AST_Symbol.DEFMETHOD("unmangleable", function(options) { - return this.definition().unmangleable(options); - }); - AST_SymbolAccessor.DEFMETHOD("unmangleable", function() { - return true; - }); - AST_Label.DEFMETHOD("unmangleable", function() { - return false; - }); - AST_Symbol.DEFMETHOD("unreferenced", function() { - return this.definition().references.length == 0 && !(this.scope.uses_eval || this.scope.uses_with); - }); - AST_Symbol.DEFMETHOD("undeclared", function() { - return this.definition().undeclared; - }); - AST_LabelRef.DEFMETHOD("undeclared", function() { - return false; - }); - AST_Label.DEFMETHOD("undeclared", function() { - return false; - }); - AST_Symbol.DEFMETHOD("definition", function() { - return this.thedef; - }); - AST_Symbol.DEFMETHOD("global", function() { - return this.definition().global; + this.walk(tw); + to_mangle.forEach(function(def){ def.mangle(options) }); +}); + +AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ + options = this._default_mangler_options(options); + var tw = new TreeWalker(function(node){ + if (node instanceof AST_Constant) + base54.consider(node.print_to_string()); + else if (node instanceof AST_Return) + base54.consider("return"); + else if (node instanceof AST_Throw) + base54.consider("throw"); + else if (node instanceof AST_Continue) + base54.consider("continue"); + else if (node instanceof AST_Break) + base54.consider("break"); + else if (node instanceof AST_Debugger) + base54.consider("debugger"); + else if (node instanceof AST_Directive) + base54.consider(node.value); + else if (node instanceof AST_While) + base54.consider("while"); + else if (node instanceof AST_Do) + base54.consider("do while"); + else if (node instanceof AST_If) { + base54.consider("if"); + if (node.alternative) base54.consider("else"); + } + else if (node instanceof AST_Var) + base54.consider("var"); + else if (node instanceof AST_Const) + base54.consider("const"); + else if (node instanceof AST_Lambda) + base54.consider("function"); + else if (node instanceof AST_For) + base54.consider("for"); + else if (node instanceof AST_ForIn) + base54.consider("for in"); + else if (node instanceof AST_Switch) + base54.consider("switch"); + else if (node instanceof AST_Case) + base54.consider("case"); + else if (node instanceof AST_Default) + base54.consider("default"); + else if (node instanceof AST_With) + base54.consider("with"); + else if (node instanceof AST_ObjectSetter) + base54.consider("set" + node.key); + else if (node instanceof AST_ObjectGetter) + base54.consider("get" + node.key); + else if (node instanceof AST_ObjectKeyVal) + base54.consider(node.key); + else if (node instanceof AST_New) + base54.consider("new"); + else if (node instanceof AST_This) + base54.consider("this"); + else if (node instanceof AST_Try) + base54.consider("try"); + else if (node instanceof AST_Catch) + base54.consider("catch"); + else if (node instanceof AST_Finally) + base54.consider("finally"); + else if (node instanceof AST_Symbol && node.unmangleable(options)) + base54.consider(node.name); + else if (node instanceof AST_Unary || node instanceof AST_Binary) + base54.consider(node.operator); + else if (node instanceof AST_Dot) + base54.consider(node.property); }); - AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) { - return defaults(options, { - except: [], - eval: false, - sort: false, - toplevel: false, - screw_ie8: false + this.walk(tw); + base54.sort(); +}); + +var base54 = (function() { + var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; + var chars, frequency; + function reset() { + frequency = Object.create(null); + chars = string.split("").map(function(ch){ return ch.charCodeAt(0) }); + chars.forEach(function(ch){ frequency[ch] = 0 }); + } + base54.consider = function(str){ + for (var i = str.length; --i >= 0;) { + var code = str.charCodeAt(i); + if (code in frequency) ++frequency[code]; + } + }; + base54.sort = function() { + chars = mergeSort(chars, function(a, b){ + if (is_digit(a) && !is_digit(b)) return 1; + if (is_digit(b) && !is_digit(a)) return -1; + return frequency[b] - frequency[a]; }); + }; + base54.reset = reset; + reset(); + base54.get = function(){ return chars }; + base54.freq = function(){ return frequency }; + function base54(num) { + var ret = "", base = 54; + do { + ret += String.fromCharCode(chars[num % base]); + num = Math.floor(num / base); + base = 64; + } while (num > 0); + return ret; + }; + return base54; +})(); + +AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ + options = defaults(options, { + undeclared : false, // this makes a lot of noise + unreferenced : true, + assign_to_global : true, + func_arguments : true, + nested_defuns : true, + eval : true }); - AST_Toplevel.DEFMETHOD("mangle_names", function(options) { - options = this._default_mangler_options(options); - var lname = -1; - var to_mangle = []; - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_LabeledStatement) { - var save_nesting = lname; - descend(); - lname = save_nesting; - return true; - } - if (node instanceof AST_Scope) { - var p = tw.parent(), a = []; - node.variables.each(function(symbol) { - if (options.except.indexOf(symbol.name) < 0) { - a.push(symbol); - } - }); - if (options.sort) a.sort(function(a, b) { - return b.references.length - a.references.length; + var tw = new TreeWalker(function(node){ + if (options.undeclared + && node instanceof AST_SymbolRef + && node.undeclared()) + { + // XXX: this also warns about JS standard names, + // i.e. Object, Array, parseInt etc. Should add a list of + // exceptions. + AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.assign_to_global) + { + var sym = null; + if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) + sym = node.left; + else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) + sym = node.init; + if (sym + && (sym.undeclared() + || (sym.global() && sym.scope !== sym.definition().scope))) { + AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { + msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", + name: sym.name, + file: sym.start.file, + line: sym.start.line, + col: sym.start.col }); - to_mangle.push.apply(to_mangle, a); - return; - } - if (node instanceof AST_Label) { - var name; - do name = base54(++lname); while (!is_identifier(name)); - node.mangled_name = name; - return true; } - }); - this.walk(tw); - to_mangle.forEach(function(def) { - def.mangle(options); - }); - }); - AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { - options = this._default_mangler_options(options); - var tw = new TreeWalker(function(node) { - if (node instanceof AST_Constant) base54.consider(node.print_to_string()); else if (node instanceof AST_Return) base54.consider("return"); else if (node instanceof AST_Throw) base54.consider("throw"); else if (node instanceof AST_Continue) base54.consider("continue"); else if (node instanceof AST_Break) base54.consider("break"); else if (node instanceof AST_Debugger) base54.consider("debugger"); else if (node instanceof AST_Directive) base54.consider(node.value); else if (node instanceof AST_While) base54.consider("while"); else if (node instanceof AST_Do) base54.consider("do while"); else if (node instanceof AST_If) { - base54.consider("if"); - if (node.alternative) base54.consider("else"); - } else if (node instanceof AST_Var) base54.consider("var"); else if (node instanceof AST_Const) base54.consider("const"); else if (node instanceof AST_Lambda) base54.consider("function"); else if (node instanceof AST_For) base54.consider("for"); else if (node instanceof AST_ForIn) base54.consider("for in"); else if (node instanceof AST_Switch) base54.consider("switch"); else if (node instanceof AST_Case) base54.consider("case"); else if (node instanceof AST_Default) base54.consider("default"); else if (node instanceof AST_With) base54.consider("with"); else if (node instanceof AST_ObjectSetter) base54.consider("set" + node.key); else if (node instanceof AST_ObjectGetter) base54.consider("get" + node.key); else if (node instanceof AST_ObjectKeyVal) base54.consider(node.key); else if (node instanceof AST_New) base54.consider("new"); else if (node instanceof AST_This) base54.consider("this"); else if (node instanceof AST_Try) base54.consider("try"); else if (node instanceof AST_Catch) base54.consider("catch"); else if (node instanceof AST_Finally) base54.consider("finally"); else if (node instanceof AST_Symbol && node.unmangleable(options)) base54.consider(node.name); else if (node instanceof AST_Unary || node instanceof AST_Binary) base54.consider(node.operator); else if (node instanceof AST_Dot) base54.consider(node.property); - }); - this.walk(tw); - base54.sort(); - }); - var base54 = function() { - var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; - var chars, frequency; - function reset() { - frequency = Object.create(null); - chars = string.split("").map(function(ch) { - return ch.charCodeAt(0); - }); - chars.forEach(function(ch) { - frequency[ch] = 0; - }); } - base54.consider = function(str) { - for (var i = str.length; --i >= 0; ) { - var code = str.charCodeAt(i); - if (code in frequency) ++frequency[code]; - } - }; - base54.sort = function() { - chars = mergeSort(chars, function(a, b) { - if (is_digit(a) && !is_digit(b)) return 1; - if (is_digit(b) && !is_digit(a)) return -1; - return frequency[b] - frequency[a]; + if (options.eval + && node instanceof AST_SymbolRef + && node.undeclared() + && node.name == "eval") { + AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); + } + if (options.unreferenced + && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) + && node.unreferenced()) { + AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { + type: node instanceof AST_Label ? "Label" : "Symbol", + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.func_arguments + && node instanceof AST_Lambda + && node.uses_arguments) { + AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { + name: node.name ? node.name.name : "anonymous", + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.nested_defuns + && node instanceof AST_Defun + && !(tw.parent() instanceof AST_Scope)) { + AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", { + name: node.name.name, + type: tw.parent().TYPE, + file: node.start.file, + line: node.start.line, + col: node.start.col }); - }; - base54.reset = reset; - reset(); - base54.get = function() { - return chars; - }; - base54.freq = function() { - return frequency; - }; - function base54(num) { - var ret = "", base = 54; - do { - ret += String.fromCharCode(chars[num % base]); - num = Math.floor(num / base); - base = 64; - } while (num > 0); - return ret; } - return base54; - }(); - AST_Toplevel.DEFMETHOD("scope_warnings", function(options) { - options = defaults(options, { - undeclared: false, - unreferenced: true, - assign_to_global: true, - func_arguments: true, - nested_defuns: true, - eval: true - }); - var tw = new TreeWalker(function(node) { - if (options.undeclared && node instanceof AST_SymbolRef && node.undeclared()) { - AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { - name: node.name, - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - if (options.assign_to_global) { - var sym = null; - if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) sym = node.left; else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) sym = node.init; - if (sym && (sym.undeclared() || sym.global() && sym.scope !== sym.definition().scope)) { - AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { - msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", - name: sym.name, - file: sym.start.file, - line: sym.start.line, - col: sym.start.col - }); - } - } - if (options.eval && node instanceof AST_SymbolRef && node.undeclared() && node.name == "eval") { - AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); - } - if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) && node.unreferenced()) { - AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { - type: node instanceof AST_Label ? "Label" : "Symbol", - name: node.name, - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - if (options.func_arguments && node instanceof AST_Lambda && node.uses_arguments) { - AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { - name: node.name ? node.name.name : "anonymous", - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - if (options.nested_defuns && node instanceof AST_Defun && !(tw.parent() instanceof AST_Scope)) { - AST_Node.warn('Function {name} declared in nested statement "{type}" [{file}:{line},{col}]', { - name: node.name.name, - type: tw.parent().TYPE, - file: node.start.file, - line: node.start.line, - col: node.start.col - }); + }); + this.walk(tw); +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +"use strict"; + +function OutputStream(options) { + + options = defaults(options, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : true, + ascii_only : false, + inline_script : false, + width : 80, + max_line_len : 32000, + beautify : false, + source_map : null, + bracketize : false, + semicolons : true, + comments : false, + preserve_line : false, + screw_ie8 : false, + preamble : null, + }, true); + + var indentation = 0; + var current_col = 0; + var current_line = 1; + var current_pos = 0; + var OUTPUT = ""; + + function to_ascii(str, identifier) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + if (code.length <= 2 && !identifier) { + while (code.length < 2) code = "0" + code; + return "\\x" + code; + } else { + while (code.length < 4) code = "0" + code; + return "\\u" + code; } }); - this.walk(tw); - }); - "use strict"; - function OutputStream(options) { - options = defaults(options, { - indent_start: 0, - indent_level: 4, - quote_keys: false, - space_colon: true, - ascii_only: false, - inline_script: false, - width: 80, - max_line_len: 32e3, - beautify: false, - source_map: null, - bracketize: false, - semicolons: true, - comments: false, - preserve_line: false, - screw_ie8: false - }, true); - var indentation = 0; - var current_col = 0; - var current_line = 1; - var current_pos = 0; - var OUTPUT = ""; - function to_ascii(str, identifier) { - return str.replace(/[\u0080-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); - if (code.length <= 2 && !identifier) { - while (code.length < 2) code = "0" + code; - return "\\x" + code; - } else { - while (code.length < 4) code = "0" + code; - return "\\u" + code; - } - }); - } - function make_string(str) { - var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s) { - switch (s) { - case "\\": - return "\\\\"; + }; - case "\b": - return "\\b"; + function make_string(str) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + case "\0": return "\\x00"; + } + return s; + }); + if (options.ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; + }; + + function encode_string(str) { + var ret = make_string(str); + if (options.inline_script) + ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + }; - case "\f": - return "\\f"; + function make_name(name) { + name = name.toString(); + if (options.ascii_only) + name = to_ascii(name, true); + return name; + }; - case "\n": - return "\\n"; + function make_indent(back) { + return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); + }; - case "\r": - return "\\r"; + /* -----[ beautification/minification ]----- */ - case "\u2028": - return "\\u2028"; + var might_need_space = false; + var might_need_semicolon = false; + var last = null; - case "\u2029": - return "\\u2029"; + function last_char() { + return last.charAt(last.length - 1); + }; - case '"': - ++dq; - return '"'; + function maybe_newline() { + if (options.max_line_len && current_col > options.max_line_len) + print("\n"); + }; - case "'": - ++sq; - return "'"; + var requireSemicolonChars = makePredicate("( [ + * / - , ."); - case "\x00": - return "\\x00"; - } - return s; - }); - if (options.ascii_only) str = to_ascii(str); - if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; else return '"' + str.replace(/\x22/g, '\\"') + '"'; - } - function encode_string(str) { - var ret = make_string(str); - if (options.inline_script) ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); - return ret; - } - function make_name(name) { - name = name.toString(); - if (options.ascii_only) name = to_ascii(name, true); - return name; - } - function make_indent(back) { - return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); - } - var might_need_space = false; - var might_need_semicolon = false; - var last = null; - function last_char() { - return last.charAt(last.length - 1); - } - function maybe_newline() { - if (options.max_line_len && current_col > options.max_line_len) print("\n"); - } - var requireSemicolonChars = makePredicate("( [ + * / - , ."); - function print(str) { - str = String(str); - var ch = str.charAt(0); - if (might_need_semicolon) { - if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { - if (options.semicolons || requireSemicolonChars(ch)) { - OUTPUT += ";"; - current_col++; - current_pos++; - } else { - OUTPUT += "\n"; - current_pos++; - current_line++; - current_col = 0; - } - if (!options.beautify) might_need_space = false; - } - might_need_semicolon = false; - maybe_newline(); - } - if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { - var target_line = stack[stack.length - 1].start.line; - while (current_line < target_line) { + function print(str) { + str = String(str); + var ch = str.charAt(0); + if (might_need_semicolon) { + if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { + if (options.semicolons || requireSemicolonChars(ch)) { + OUTPUT += ";"; + current_col++; + current_pos++; + } else { OUTPUT += "\n"; current_pos++; current_line++; current_col = 0; - might_need_space = false; - } - } - if (might_need_space) { - var prev = last_char(); - if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\") || /^[\+\-\/]$/.test(ch) && ch == prev) { - OUTPUT += " "; - current_col++; - current_pos++; } - might_need_space = false; - } - var a = str.split(/\r?\n/), n = a.length - 1; - current_line += n; - if (n == 0) { - current_col += a[n].length; - } else { - current_col = a[n].length; - } - current_pos += str.length; - last = str; - OUTPUT += str; - } - var space = options.beautify ? function() { - print(" "); - } : function() { - might_need_space = true; - }; - var indent = options.beautify ? function(half) { - if (options.beautify) { - print(make_indent(half ? .5 : 0)); + if (!options.beautify) + might_need_space = false; } - } : noop; - var with_indent = options.beautify ? function(col, cont) { - if (col === true) col = next_indent(); - var save_indentation = indentation; - indentation = col; - var ret = cont(); - indentation = save_indentation; - return ret; - } : function(col, cont) { - return cont(); - }; - var newline = options.beautify ? function() { - print("\n"); - } : noop; - var semicolon = options.beautify ? function() { - print(";"); - } : function() { - might_need_semicolon = true; - }; - function force_semicolon() { might_need_semicolon = false; - print(";"); + maybe_newline(); } - function next_indent() { - return indentation + options.indent_level; - } - function with_block(cont) { - var ret; - print("{"); - newline(); - with_indent(next_indent(), function() { - ret = cont(); - }); - indent(); - print("}"); - return ret; + + if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { + var target_line = stack[stack.length - 1].start.line; + while (current_line < target_line) { + OUTPUT += "\n"; + current_pos++; + current_line++; + current_col = 0; + might_need_space = false; + } } - function with_parens(cont) { - print("("); - var ret = cont(); - print(")"); - return ret; + + if (might_need_space) { + var prev = last_char(); + if ((is_identifier_char(prev) + && (is_identifier_char(ch) || ch == "\\")) + || (/^[\+\-\/]$/.test(ch) && ch == prev)) + { + OUTPUT += " "; + current_col++; + current_pos++; + } + might_need_space = false; + } + var a = str.split(/\r?\n/), n = a.length - 1; + current_line += n; + if (n == 0) { + current_col += a[n].length; + } else { + current_col = a[n].length; } - function with_square(cont) { - print("["); - var ret = cont(); - print("]"); - return ret; + current_pos += str.length; + last = str; + OUTPUT += str; + }; + + var space = options.beautify ? function() { + print(" "); + } : function() { + might_need_space = true; + }; + + var indent = options.beautify ? function(half) { + if (options.beautify) { + print(make_indent(half ? 0.5 : 0)); } - function comma() { - print(","); - space(); + } : noop; + + var with_indent = options.beautify ? function(col, cont) { + if (col === true) col = next_indent(); + var save_indentation = indentation; + indentation = col; + var ret = cont(); + indentation = save_indentation; + return ret; + } : function(col, cont) { return cont() }; + + var newline = options.beautify ? function() { + print("\n"); + } : noop; + + var semicolon = options.beautify ? function() { + print(";"); + } : function() { + might_need_semicolon = true; + }; + + function force_semicolon() { + might_need_semicolon = false; + print(";"); + }; + + function next_indent() { + return indentation + options.indent_level; + }; + + function with_block(cont) { + var ret; + print("{"); + newline(); + with_indent(next_indent(), function(){ + ret = cont(); + }); + indent(); + print("}"); + return ret; + }; + + function with_parens(cont) { + print("("); + //XXX: still nice to have that for argument lists + //var ret = with_indent(current_col, cont); + var ret = cont(); + print(")"); + return ret; + }; + + function with_square(cont) { + print("["); + //var ret = with_indent(current_col, cont); + var ret = cont(); + print("]"); + return ret; + }; + + function comma() { + print(","); + space(); + }; + + function colon() { + print(":"); + if (options.space_colon) space(); + }; + + var add_mapping = options.source_map ? function(token, name) { + try { + if (token) options.source_map.add( + token.file || "?", + current_line, current_col, + token.line, token.col, + (!name && token.type == "name") ? token.value : name + ); + } catch(ex) { + AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { + file: token.file, + line: token.line, + col: token.col, + cline: current_line, + ccol: current_col, + name: name || "" + }) + } + } : noop; + + function get() { + return OUTPUT; + }; + + if (options.preamble) { + print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); + } + + var stack = []; + return { + get : get, + toString : get, + indent : indent, + indentation : function() { return indentation }, + current_width : function() { return current_col - indentation }, + should_break : function() { return options.width && this.current_width() >= options.width }, + newline : newline, + print : print, + space : space, + comma : comma, + colon : colon, + last : function() { return last }, + semicolon : semicolon, + force_semicolon : force_semicolon, + to_ascii : to_ascii, + print_name : function(name) { print(make_name(name)) }, + print_string : function(str) { print(encode_string(str)) }, + next_indent : next_indent, + with_indent : with_indent, + with_block : with_block, + with_parens : with_parens, + with_square : with_square, + add_mapping : add_mapping, + option : function(opt) { return options[opt] }, + line : function() { return current_line }, + col : function() { return current_col }, + pos : function() { return current_pos }, + push_node : function(node) { stack.push(node) }, + pop_node : function() { return stack.pop() }, + stack : function() { return stack }, + parent : function(n) { + return stack[stack.length - 2 - (n || 0)]; } - function colon() { - print(":"); - if (options.space_colon) space(); + }; + +}; + +/* -----[ code generators ]----- */ + +(function(){ + + /* -----[ utils ]----- */ + + function DEFPRINT(nodetype, generator) { + nodetype.DEFMETHOD("_codegen", generator); + }; + + AST_Node.DEFMETHOD("print", function(stream, force_parens){ + var self = this, generator = self._codegen; + function doit() { + self.add_comments(stream); + self.add_source_map(stream); + generator(self, stream); + } + stream.push_node(self); + if (force_parens || self.needs_parens(stream)) { + stream.with_parens(doit); + } else { + doit(); } - var add_mapping = options.source_map ? function(token, name) { - try { - if (token) options.source_map.add(token.file || "?", current_line, current_col, token.line, token.col, !name && token.type == "name" ? token.value : name); - } catch (ex) { - AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { - file: token.file, - line: token.line, - col: token.col, - cline: current_line, - ccol: current_col, - name: name || "" - }); - } - } : noop; - function get() { - return OUTPUT; - } - var stack = []; - return { - get: get, - toString: get, - indent: indent, - indentation: function() { - return indentation; - }, - current_width: function() { - return current_col - indentation; - }, - should_break: function() { - return options.width && this.current_width() >= options.width; - }, - newline: newline, - print: print, - space: space, - comma: comma, - colon: colon, - last: function() { - return last; - }, - semicolon: semicolon, - force_semicolon: force_semicolon, - to_ascii: to_ascii, - print_name: function(name) { - print(make_name(name)); - }, - print_string: function(str) { - print(encode_string(str)); - }, - next_indent: next_indent, - with_indent: with_indent, - with_block: with_block, - with_parens: with_parens, - with_square: with_square, - add_mapping: add_mapping, - option: function(opt) { - return options[opt]; - }, - line: function() { - return current_line; - }, - col: function() { - return current_col; - }, - pos: function() { - return current_pos; - }, - push_node: function(node) { - stack.push(node); - }, - pop_node: function() { - return stack.pop(); - }, - stack: function() { - return stack; - }, - parent: function(n) { - return stack[stack.length - 2 - (n || 0)]; - } - }; - } - (function() { - function DEFPRINT(nodetype, generator) { - nodetype.DEFMETHOD("_codegen", generator); - } - AST_Node.DEFMETHOD("print", function(stream, force_parens) { - var self = this, generator = self._codegen; - function doit() { - self.add_comments(stream); - self.add_source_map(stream); - generator(self, stream); - } - stream.push_node(self); - if (force_parens || self.needs_parens(stream)) { - stream.with_parens(doit); - } else { - doit(); - } - stream.pop_node(); - }); - AST_Node.DEFMETHOD("print_to_string", function(options) { - var s = OutputStream(options); - this.print(s); - return s.get(); - }); - AST_Node.DEFMETHOD("add_comments", function(output) { - var c = output.option("comments"), self = this; - if (c) { - var start = self.start; - if (start && !start._comments_dumped) { - start._comments_dumped = true; - var comments = start.comments_before; - if (self instanceof AST_Exit && self.value && self.value.start.comments_before.length > 0) { - comments = (comments || []).concat(self.value.start.comments_before); - self.value.start.comments_before = []; - } - if (c.test) { - comments = comments.filter(function(comment) { - return c.test(comment.value); - }); - } else if (typeof c == "function") { - comments = comments.filter(function(comment) { - return c(self, comment); - }); + stream.pop_node(); + }); + + AST_Node.DEFMETHOD("print_to_string", function(options){ + var s = OutputStream(options); + this.print(s); + return s.get(); + }); + + /* -----[ comments ]----- */ + + AST_Node.DEFMETHOD("add_comments", function(output){ + var c = output.option("comments"), self = this; + if (c) { + var start = self.start; + if (start && !start._comments_dumped) { + start._comments_dumped = true; + var comments = start.comments_before || []; + + // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 + // if this node is `return` or `throw`, we cannot allow comments before + // the returned or thrown value. + if (self instanceof AST_Exit && self.value + && self.value.start.comments_before + && self.value.start.comments_before.length > 0) { + comments = comments.concat(self.value.start.comments_before); + self.value.start.comments_before = []; + } + + if (c.test) { + comments = comments.filter(function(comment){ + return c.test(comment.value); + }); + } else if (typeof c == "function") { + comments = comments.filter(function(comment){ + return c(self, comment); + }); + } + comments.forEach(function(c){ + if (/comment[134]/.test(c.type)) { + output.print("//" + c.value + "\n"); + output.indent(); } - comments.forEach(function(c) { - if (c.type == "comment1") { - output.print("//" + c.value + "\n"); + else if (c.type == "comment2") { + output.print("/*" + c.value + "*/"); + if (start.nlb) { + output.print("\n"); output.indent(); - } else if (c.type == "comment2") { - output.print("/*" + c.value + "*/"); - if (start.nlb) { - output.print("\n"); - output.indent(); - } else { - output.space(); - } + } else { + output.space(); } - }); - } + } + }); } - }); - function PARENS(nodetype, func) { - nodetype.DEFMETHOD("needs_parens", func); } - PARENS(AST_Node, function() { - return false; - }); - PARENS(AST_Function, function(output) { - return first_in_statement(output); - }); - PARENS(AST_Object, function(output) { - return first_in_statement(output); - }); - PARENS(AST_Unary, function(output) { - var p = output.parent(); - return p instanceof AST_PropAccess && p.expression === this; - }); - PARENS(AST_Seq, function(output) { - var p = output.parent(); - return p instanceof AST_Call || p instanceof AST_Unary || p instanceof AST_Binary || p instanceof AST_VarDef || p instanceof AST_Dot || p instanceof AST_Array || p instanceof AST_ObjectProperty || p instanceof AST_Conditional; - }); - PARENS(AST_Binary, function(output) { - var p = output.parent(); - if (p instanceof AST_Call && p.expression === this) return true; - if (p instanceof AST_Unary) return true; - if (p instanceof AST_PropAccess && p.expression === this) return true; - if (p instanceof AST_Binary) { - var po = p.operator, pp = PRECEDENCE[po]; - var so = this.operator, sp = PRECEDENCE[so]; - if (pp > sp || pp == sp && this === p.right && !(so == po && (so == "*" || so == "&&" || so == "||"))) { - return true; - } - } - }); - PARENS(AST_PropAccess, function(output) { - var p = output.parent(); - if (p instanceof AST_New && p.expression === this) { - try { - this.walk(new TreeWalker(function(node) { - if (node instanceof AST_Call) throw p; - })); - } catch (ex) { - if (ex !== p) throw ex; - return true; - } + }); + + /* -----[ PARENTHESES ]----- */ + + function PARENS(nodetype, func) { + nodetype.DEFMETHOD("needs_parens", func); + }; + + PARENS(AST_Node, function(){ + return false; + }); + + // a function expression needs parens around it when it's provably + // the first token to appear in a statement. + PARENS(AST_Function, function(output){ + return first_in_statement(output); + }); + + // same goes for an object literal, because otherwise it would be + // interpreted as a block of code. + PARENS(AST_Object, function(output){ + return first_in_statement(output); + }); + + PARENS(AST_Unary, function(output){ + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this; + }); + + PARENS(AST_Seq, function(output){ + var p = output.parent(); + return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) + || p instanceof AST_Unary // !(foo, bar, baz) + || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 + || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 + || p instanceof AST_Dot // (1, {foo:2}).foo ==> 2 + || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] + || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 + || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) + * ==> 20 (side effect, set a := 10 and b := 20) */ + ; + }); + + PARENS(AST_Binary, function(output){ + var p = output.parent(); + // (foo && bar)() + if (p instanceof AST_Call && p.expression === this) + return true; + // typeof (foo && bar) + if (p instanceof AST_Unary) + return true; + // (foo && bar)["prop"], (foo && bar).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + // this deals with precedence: 3 * (2 + 1) + if (p instanceof AST_Binary) { + var po = p.operator, pp = PRECEDENCE[po]; + var so = this.operator, sp = PRECEDENCE[so]; + if (pp > sp + || (pp == sp + && this === p.right)) { + return true; } - }); - PARENS(AST_Call, function(output) { - var p = output.parent(); - return p instanceof AST_New && p.expression === this; - }); - PARENS(AST_New, function(output) { - var p = output.parent(); - if (no_constructor_parens(this, output) && (p instanceof AST_PropAccess || p instanceof AST_Call && p.expression === this)) return true; - }); - PARENS(AST_Number, function(output) { - var p = output.parent(); - if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) return true; - }); - PARENS(AST_NaN, function(output) { - var p = output.parent(); - if (p instanceof AST_PropAccess && p.expression === this) return true; - }); - function assign_and_conditional_paren_rules(output) { - var p = output.parent(); - if (p instanceof AST_Unary) return true; - if (p instanceof AST_Binary && !(p instanceof AST_Assign)) return true; - if (p instanceof AST_Call && p.expression === this) return true; - if (p instanceof AST_Conditional && p.condition === this) return true; - if (p instanceof AST_PropAccess && p.expression === this) return true; - } - PARENS(AST_Assign, assign_and_conditional_paren_rules); - PARENS(AST_Conditional, assign_and_conditional_paren_rules); - DEFPRINT(AST_Directive, function(self, output) { - output.print_string(self.value); - output.semicolon(); - }); - DEFPRINT(AST_Debugger, function(self, output) { - output.print("debugger"); - output.semicolon(); - }); - function display_body(body, is_toplevel, output) { - var last = body.length - 1; - body.forEach(function(stmt, i) { - if (!(stmt instanceof AST_EmptyStatement)) { - output.indent(); - stmt.print(output); - if (!(i == last && is_toplevel)) { - output.newline(); - if (is_toplevel) output.newline(); - } - } - }); } - AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) { - force_statement(this.body, output); - }); - DEFPRINT(AST_Statement, function(self, output) { - self.body.print(output); - output.semicolon(); - }); - DEFPRINT(AST_Toplevel, function(self, output) { - display_body(self.body, true, output); - output.print(""); - }); - DEFPRINT(AST_LabeledStatement, function(self, output) { - self.label.print(output); - output.colon(); - self.body.print(output); - }); - DEFPRINT(AST_SimpleStatement, function(self, output) { - self.body.print(output); - output.semicolon(); - }); - function print_bracketed(body, output) { - if (body.length > 0) output.with_block(function() { - display_body(body, false, output); - }); else output.print("{}"); + }); + + PARENS(AST_PropAccess, function(output){ + var p = output.parent(); + if (p instanceof AST_New && p.expression === this) { + // i.e. new (foo.bar().baz) + // + // if there's one call into this subtree, then we need + // parens around it too, otherwise the call will be + // interpreted as passing the arguments to the upper New + // expression. + try { + this.walk(new TreeWalker(function(node){ + if (node instanceof AST_Call) throw p; + })); + } catch(ex) { + if (ex !== p) throw ex; + return true; + } } - DEFPRINT(AST_BlockStatement, function(self, output) { - print_bracketed(self.body, output); + }); + + PARENS(AST_Call, function(output){ + var p = output.parent(), p1; + if (p instanceof AST_New && p.expression === this) + return true; + + // workaround for Safari bug. + // https://bugs.webkit.org/show_bug.cgi?id=123506 + return this.expression instanceof AST_Function + && p instanceof AST_PropAccess + && p.expression === this + && (p1 = output.parent(1)) instanceof AST_Assign + && p1.left === p; + }); + + PARENS(AST_New, function(output){ + var p = output.parent(); + if (no_constructor_parens(this, output) + && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]() + || p instanceof AST_Call && p.expression === this)) // (new foo)(bar) + return true; + }); + + PARENS(AST_Number, function(output){ + var p = output.parent(); + if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + PARENS(AST_NaN, function(output){ + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + function assign_and_conditional_paren_rules(output) { + var p = output.parent(); + // !(a = false) → true + if (p instanceof AST_Unary) + return true; + // 1 + (a = 2) + 3 → 6, side effect setting a = 2 + if (p instanceof AST_Binary && !(p instanceof AST_Assign)) + return true; + // (a = func)() —or— new (a = Object)() + if (p instanceof AST_Call && p.expression === this) + return true; + // (a = foo) ? bar : baz + if (p instanceof AST_Conditional && p.condition === this) + return true; + // (a = foo)["prop"] —or— (a = foo).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }; + + PARENS(AST_Assign, assign_and_conditional_paren_rules); + PARENS(AST_Conditional, assign_and_conditional_paren_rules); + + /* -----[ PRINTERS ]----- */ + + DEFPRINT(AST_Directive, function(self, output){ + output.print_string(self.value); + output.semicolon(); + }); + DEFPRINT(AST_Debugger, function(self, output){ + output.print("debugger"); + output.semicolon(); + }); + + /* -----[ statements ]----- */ + + function display_body(body, is_toplevel, output) { + var last = body.length - 1; + body.forEach(function(stmt, i){ + if (!(stmt instanceof AST_EmptyStatement)) { + output.indent(); + stmt.print(output); + if (!(i == last && is_toplevel)) { + output.newline(); + if (is_toplevel) output.newline(); + } + } }); - DEFPRINT(AST_EmptyStatement, function(self, output) { - output.semicolon(); + }; + + AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){ + force_statement(this.body, output); + }); + + DEFPRINT(AST_Statement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + DEFPRINT(AST_Toplevel, function(self, output){ + display_body(self.body, true, output); + output.print(""); + }); + DEFPRINT(AST_LabeledStatement, function(self, output){ + self.label.print(output); + output.colon(); + self.body.print(output); + }); + DEFPRINT(AST_SimpleStatement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + function print_bracketed(body, output) { + if (body.length > 0) output.with_block(function(){ + display_body(body, false, output); }); - DEFPRINT(AST_Do, function(self, output) { - output.print("do"); - output.space(); - self._do_print_body(output); - output.space(); - output.print("while"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.semicolon(); + else output.print("{}"); + }; + DEFPRINT(AST_BlockStatement, function(self, output){ + print_bracketed(self.body, output); + }); + DEFPRINT(AST_EmptyStatement, function(self, output){ + output.semicolon(); + }); + DEFPRINT(AST_Do, function(self, output){ + output.print("do"); + output.space(); + self._do_print_body(output); + output.space(); + output.print("while"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); }); - DEFPRINT(AST_While, function(self, output) { - output.print("while"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.space(); - self._do_print_body(output); + output.semicolon(); + }); + DEFPRINT(AST_While, function(self, output){ + output.print("while"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); }); - DEFPRINT(AST_For, function(self, output) { - output.print("for"); - output.space(); - output.with_parens(function() { - if (self.init) { - if (self.init instanceof AST_Definitions) { - self.init.print(output); - } else { - parenthesize_for_noin(self.init, output, true); - } - output.print(";"); - output.space(); - } else { - output.print(";"); - } - if (self.condition) { - self.condition.print(output); - output.print(";"); - output.space(); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_For, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + if (self.init) { + if (self.init instanceof AST_Definitions) { + self.init.print(output); } else { - output.print(";"); - } - if (self.step) { - self.step.print(output); + parenthesize_for_noin(self.init, output, true); } - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_ForIn, function(self, output) { - output.print("for"); - output.space(); - output.with_parens(function() { - self.init.print(output); - output.space(); - output.print("in"); + output.print(";"); output.space(); - self.object.print(output); - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_With, function(self, output) { - output.print("with"); - output.space(); - output.with_parens(function() { - self.expression.print(output); - }); - output.space(); - self._do_print_body(output); - }); - AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) { - var self = this; - if (!nokeyword) { - output.print("function"); - } - if (self.name) { - output.space(); - self.name.print(output); + } else { + output.print(";"); } - output.with_parens(function() { - self.argnames.forEach(function(arg, i) { - if (i) output.comma(); - arg.print(output); - }); - }); - output.space(); - print_bracketed(self.body, output); - }); - DEFPRINT(AST_Lambda, function(self, output) { - self._do_print(output); - }); - AST_Exit.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - if (this.value) { + if (self.condition) { + self.condition.print(output); + output.print(";"); output.space(); - this.value.print(output); + } else { + output.print(";"); } - output.semicolon(); - }); - DEFPRINT(AST_Return, function(self, output) { - self._do_print(output, "return"); - }); - DEFPRINT(AST_Throw, function(self, output) { - self._do_print(output, "throw"); - }); - AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - if (this.label) { - output.space(); - this.label.print(output); + if (self.step) { + self.step.print(output); } - output.semicolon(); }); - DEFPRINT(AST_Break, function(self, output) { - self._do_print(output, "break"); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_ForIn, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + self.init.print(output); + output.space(); + output.print("in"); + output.space(); + self.object.print(output); }); - DEFPRINT(AST_Continue, function(self, output) { - self._do_print(output, "continue"); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_With, function(self, output){ + output.print("with"); + output.space(); + output.with_parens(function(){ + self.expression.print(output); }); - function make_then(self, output) { - if (output.option("bracketize")) { - make_block(self.body, output); - return; - } - if (!self.body) return output.force_semicolon(); - if (self.body instanceof AST_Do && !output.option("screw_ie8")) { - make_block(self.body, output); - return; - } - var b = self.body; - while (true) { - if (b instanceof AST_If) { - if (!b.alternative) { - make_block(self.body, output); - return; - } - b = b.alternative; - } else if (b instanceof AST_StatementWithBody) { - b = b.body; - } else break; - } - force_statement(self.body, output); + output.space(); + self._do_print_body(output); + }); + + /* -----[ functions ]----- */ + AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){ + var self = this; + if (!nokeyword) { + output.print("function"); } - DEFPRINT(AST_If, function(self, output) { - output.print("if"); + if (self.name) { output.space(); - output.with_parens(function() { - self.condition.print(output); + self.name.print(output); + } + output.with_parens(function(){ + self.argnames.forEach(function(arg, i){ + if (i) output.comma(); + arg.print(output); }); - output.space(); - if (self.alternative) { - make_then(self, output); - output.space(); - output.print("else"); - output.space(); - force_statement(self.alternative, output); - } else { - self._do_print_body(output); - } }); - DEFPRINT(AST_Switch, function(self, output) { - output.print("switch"); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Lambda, function(self, output){ + self._do_print(output); + }); + + /* -----[ exits ]----- */ + AST_Exit.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (this.value) { output.space(); - output.with_parens(function() { - self.expression.print(output); - }); + this.value.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Return, function(self, output){ + self._do_print(output, "return"); + }); + DEFPRINT(AST_Throw, function(self, output){ + self._do_print(output, "throw"); + }); + + /* -----[ loop control ]----- */ + AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (this.label) { output.space(); - if (self.body.length > 0) output.with_block(function() { - self.body.forEach(function(stmt, i) { - if (i) output.newline(); - output.indent(true); - stmt.print(output); - }); - }); else output.print("{}"); - }); - AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) { - if (this.body.length > 0) { - output.newline(); - this.body.forEach(function(stmt) { - output.indent(); - stmt.print(output); - output.newline(); - }); + this.label.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Break, function(self, output){ + self._do_print(output, "break"); + }); + DEFPRINT(AST_Continue, function(self, output){ + self._do_print(output, "continue"); + }); + + /* -----[ if ]----- */ + function make_then(self, output) { + if (output.option("bracketize")) { + make_block(self.body, output); + return; + } + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + if (!self.body) + return output.force_semicolon(); + if (self.body instanceof AST_Do + && !output.option("screw_ie8")) { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE + // croaks with "syntax error" on code like this: if (foo) + // do ... while(cond); else ... we need block brackets + // around do/while + make_block(self.body, output); + return; + } + var b = self.body; + while (true) { + if (b instanceof AST_If) { + if (!b.alternative) { + make_block(self.body, output); + return; + } + b = b.alternative; } + else if (b instanceof AST_StatementWithBody) { + b = b.body; + } + else break; + } + force_statement(self.body, output); + }; + DEFPRINT(AST_If, function(self, output){ + output.print("if"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); }); - DEFPRINT(AST_Default, function(self, output) { - output.print("default:"); - self._do_print_body(output); - }); - DEFPRINT(AST_Case, function(self, output) { - output.print("case"); + output.space(); + if (self.alternative) { + make_then(self, output); output.space(); - self.expression.print(output); - output.print(":"); + output.print("else"); + output.space(); + force_statement(self.alternative, output); + } else { self._do_print_body(output); + } + }); + + /* -----[ switch ]----- */ + DEFPRINT(AST_Switch, function(self, output){ + output.print("switch"); + output.space(); + output.with_parens(function(){ + self.expression.print(output); }); - DEFPRINT(AST_Try, function(self, output) { - output.print("try"); - output.space(); - print_bracketed(self.body, output); - if (self.bcatch) { - output.space(); - self.bcatch.print(output); - } - if (self.bfinally) { - output.space(); - self.bfinally.print(output); - } + output.space(); + if (self.body.length > 0) output.with_block(function(){ + self.body.forEach(function(stmt, i){ + if (i) output.newline(); + output.indent(true); + stmt.print(output); + }); }); - DEFPRINT(AST_Catch, function(self, output) { - output.print("catch"); - output.space(); - output.with_parens(function() { - self.argname.print(output); + else output.print("{}"); + }); + AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){ + if (this.body.length > 0) { + output.newline(); + this.body.forEach(function(stmt){ + output.indent(); + stmt.print(output); + output.newline(); }); + } + }); + DEFPRINT(AST_Default, function(self, output){ + output.print("default:"); + self._do_print_body(output); + }); + DEFPRINT(AST_Case, function(self, output){ + output.print("case"); + output.space(); + self.expression.print(output); + output.print(":"); + self._do_print_body(output); + }); + + /* -----[ exceptions ]----- */ + DEFPRINT(AST_Try, function(self, output){ + output.print("try"); + output.space(); + print_bracketed(self.body, output); + if (self.bcatch) { output.space(); - print_bracketed(self.body, output); - }); - DEFPRINT(AST_Finally, function(self, output) { - output.print("finally"); + self.bcatch.print(output); + } + if (self.bfinally) { output.space(); - print_bracketed(self.body, output); - }); - AST_Definitions.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); + self.bfinally.print(output); + } + }); + DEFPRINT(AST_Catch, function(self, output){ + output.print("catch"); + output.space(); + output.with_parens(function(){ + self.argname.print(output); + }); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Finally, function(self, output){ + output.print("finally"); + output.space(); + print_bracketed(self.body, output); + }); + + /* -----[ var/const ]----- */ + AST_Definitions.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + output.space(); + this.definitions.forEach(function(def, i){ + if (i) output.comma(); + def.print(output); + }); + var p = output.parent(); + var in_for = p instanceof AST_For || p instanceof AST_ForIn; + var avoid_semicolon = in_for && p.init === this; + if (!avoid_semicolon) + output.semicolon(); + }); + DEFPRINT(AST_Var, function(self, output){ + self._do_print(output, "var"); + }); + DEFPRINT(AST_Const, function(self, output){ + self._do_print(output, "const"); + }); + + function parenthesize_for_noin(node, output, noin) { + if (!noin) node.print(output); + else try { + // need to take some precautions here: + // https://github.com/mishoo/UglifyJS2/issues/60 + node.walk(new TreeWalker(function(node){ + if (node instanceof AST_Binary && node.operator == "in") + throw output; + })); + node.print(output); + } catch(ex) { + if (ex !== output) throw ex; + node.print(output, true); + } + }; + + DEFPRINT(AST_VarDef, function(self, output){ + self.name.print(output); + if (self.value) { + output.space(); + output.print("="); output.space(); - this.definitions.forEach(function(def, i) { + var p = output.parent(1); + var noin = p instanceof AST_For || p instanceof AST_ForIn; + parenthesize_for_noin(self.value, output, noin); + } + }); + + /* -----[ other expressions ]----- */ + DEFPRINT(AST_Call, function(self, output){ + self.expression.print(output); + if (self instanceof AST_New && no_constructor_parens(self, output)) + return; + output.with_parens(function(){ + self.args.forEach(function(expr, i){ if (i) output.comma(); - def.print(output); + expr.print(output); }); - var p = output.parent(); - var in_for = p instanceof AST_For || p instanceof AST_ForIn; - var avoid_semicolon = in_for && p.init === this; - if (!avoid_semicolon) output.semicolon(); - }); - DEFPRINT(AST_Var, function(self, output) { - self._do_print(output, "var"); }); - DEFPRINT(AST_Const, function(self, output) { - self._do_print(output, "const"); - }); - function parenthesize_for_noin(node, output, noin) { - if (!noin) node.print(output); else try { - node.walk(new TreeWalker(function(node) { - if (node instanceof AST_Binary && node.operator == "in") throw output; - })); - node.print(output); - } catch (ex) { - if (ex !== output) throw ex; - node.print(output, true); + }); + DEFPRINT(AST_New, function(self, output){ + output.print("new"); + output.space(); + AST_Call.prototype._codegen(self, output); + }); + + AST_Seq.DEFMETHOD("_do_print", function(output){ + this.car.print(output); + if (this.cdr) { + output.comma(); + if (output.should_break()) { + output.newline(); + output.indent(); } + this.cdr.print(output); } - DEFPRINT(AST_VarDef, function(self, output) { - self.name.print(output); - if (self.value) { - output.space(); - output.print("="); - output.space(); - var p = output.parent(1); - var noin = p instanceof AST_For || p instanceof AST_ForIn; - parenthesize_for_noin(self.value, output, noin); - } - }); - DEFPRINT(AST_Call, function(self, output) { - self.expression.print(output); - if (self instanceof AST_New && no_constructor_parens(self, output)) return; - output.with_parens(function() { - self.args.forEach(function(expr, i) { - if (i) output.comma(); - expr.print(output); - }); - }); - }); - DEFPRINT(AST_New, function(self, output) { - output.print("new"); - output.space(); - AST_Call.prototype._codegen(self, output); - }); - AST_Seq.DEFMETHOD("_do_print", function(output) { - this.car.print(output); - if (this.cdr) { - output.comma(); - if (output.should_break()) { - output.newline(); - output.indent(); - } - this.cdr.print(output); - } - }); - DEFPRINT(AST_Seq, function(self, output) { - self._do_print(output); - }); - DEFPRINT(AST_Dot, function(self, output) { - var expr = self.expression; - expr.print(output); - if (expr instanceof AST_Number && expr.getValue() >= 0) { - if (!/[xa-f.]/i.test(output.last())) { - output.print("."); - } - } - output.print("."); - output.add_mapping(self.end); - output.print_name(self.property); - }); - DEFPRINT(AST_Sub, function(self, output) { - self.expression.print(output); - output.print("["); - self.property.print(output); - output.print("]"); - }); - DEFPRINT(AST_UnaryPrefix, function(self, output) { - var op = self.operator; - output.print(op); - if (/^[a-z]/i.test(op)) output.space(); - self.expression.print(output); - }); - DEFPRINT(AST_UnaryPostfix, function(self, output) { - self.expression.print(output); - output.print(self.operator); - }); - DEFPRINT(AST_Binary, function(self, output) { - self.left.print(output); - output.space(); - output.print(self.operator); - output.space(); - self.right.print(output); - }); - DEFPRINT(AST_Conditional, function(self, output) { - self.condition.print(output); - output.space(); - output.print("?"); + }); + DEFPRINT(AST_Seq, function(self, output){ + self._do_print(output); + // var p = output.parent(); + // if (p instanceof AST_Statement) { + // output.with_indent(output.next_indent(), function(){ + // self._do_print(output); + // }); + // } else { + // self._do_print(output); + // } + }); + DEFPRINT(AST_Dot, function(self, output){ + var expr = self.expression; + expr.print(output); + if (expr instanceof AST_Number && expr.getValue() >= 0) { + if (!/[xa-f.]/i.test(output.last())) { + output.print("."); + } + } + output.print("."); + // the name after dot would be mapped about here. + output.add_mapping(self.end); + output.print_name(self.property); + }); + DEFPRINT(AST_Sub, function(self, output){ + self.expression.print(output); + output.print("["); + self.property.print(output); + output.print("]"); + }); + DEFPRINT(AST_UnaryPrefix, function(self, output){ + var op = self.operator; + output.print(op); + if (/^[a-z]/i.test(op)) output.space(); - self.consequent.print(output); + self.expression.print(output); + }); + DEFPRINT(AST_UnaryPostfix, function(self, output){ + self.expression.print(output); + output.print(self.operator); + }); + DEFPRINT(AST_Binary, function(self, output){ + self.left.print(output); + output.space(); + output.print(self.operator); + if (self.operator == "<" + && self.right instanceof AST_UnaryPrefix + && self.right.operator == "!" + && self.right.expression instanceof AST_UnaryPrefix + && self.right.expression.operator == "--") { + // space is mandatory to avoid outputting ") && S.newline_before) { + forward(3); + return skip_line_comment("comment4"); + } + } + var ch = peek(); + if (!ch) return token("eof"); + var code = ch.charCodeAt(0); + switch (code) { + case 34: case 39: return read_string(); + case 46: return handle_dot(); + case 47: return handle_slash(); + } + if (is_digit(code)) return read_num(); + if (PUNC_CHARS(ch)) return token("punc", next()); + if (OPERATOR_CHARS(ch)) return read_operator(); + if (code == 92 || is_identifier_start(code)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = makePredicate([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = makePredicate([ "--", "++" ]); + +var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0; i < a.length; ++i) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = i + 1; + } + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function parse($TEXT, options) { + + options = defaults(options, { + strict : false, + filename : null, + toplevel : null, + expression : false, + html5_comments : true, + }); + + var S = { + input : (typeof $TEXT == "string" + ? tokenizer($TEXT, options.filename, + options.html5_comments) + : $TEXT), + token : null, + prev : null, + peeked : null, + in_function : 0, + in_directives : true, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + S.in_directives = S.in_directives && ( + S.token.type == "string" || is("punc", ";") + ); + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + ctx.filename, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !options.strict && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function parenthesised() { + expect("("); + var exp = expression(true); + expect(")"); + return exp; + }; + + function embed_tokens(parser) { + return function() { + var start = S.token; + var expr = parser(); + var end = prev(); + expr.start = start; + expr.end = end; + return expr; + }; + }; + + function handle_regexp() { + if (is("operator", "/") || is("operator", "/=")) { + S.peeked = null; + S.token = S.input(S.token.value.substr(1)); // force regexp + } + }; + + var statement = embed_tokens(function() { + var tmp; + handle_regexp(); + switch (S.token.type) { + case "string": + var dir = S.in_directives, stat = simple_statement(); + // XXXv2: decide how to fix directives + if (dir && stat.body instanceof AST_String && !is("punc", ",")) + return new AST_Directive({ value: stat.body.value }); + return stat; + case "num": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement() + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return new AST_BlockStatement({ + start : S.token, + body : block_(), + end : prev() + }); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return new AST_EmptyStatement(); + default: + unexpected(); + } + + case "keyword": + switch (tmp = S.token.value, next(), tmp) { + case "break": + return break_cont(AST_Break); + + case "continue": + return break_cont(AST_Continue); + + case "debugger": + semicolon(); + return new AST_Debugger(); + + case "do": + return new AST_Do({ + body : in_loop(statement), + condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp) + }); + + case "while": + return new AST_While({ + condition : parenthesised(), + body : in_loop(statement) + }); + + case "for": + return for_(); + + case "function": + return function_(AST_Defun); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return new AST_Return({ + value: ( is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : (tmp = expression(true), semicolon(), tmp) ) + }); + + case "switch": + return new AST_Switch({ + expression : parenthesised(), + body : in_loop(switch_body_) + }); + + case "throw": + if (S.token.nlb) + croak("Illegal newline after 'throw'"); + return new AST_Throw({ + value: (tmp = expression(true), semicolon(), tmp) + }); + + case "try": + return try_(); + + case "var": + return tmp = var_(), semicolon(), tmp; + + case "const": + return tmp = const_(), semicolon(), tmp; + + case "with": + return new AST_With({ + expression : parenthesised(), + body : statement() + }); + + default: + unexpected(); + } + } + }); + + function labeled_statement() { + var label = as_symbol(AST_Label); + if (find_if(function(l){ return l.name == label.name }, S.labels)) { + // ECMA-262, 12.12: An ECMAScript program is considered + // syntactically incorrect if it contains a + // LabelledStatement that is enclosed by a + // LabelledStatement with the same Identifier as label. + croak("Label " + label.name + " defined twice"); + } + expect(":"); + S.labels.push(label); + var stat = statement(); + S.labels.pop(); + if (!(stat instanceof AST_IterationStatement)) { + // check for `continue` that refers to this label. + // those should be reported as syntax errors. + // https://github.com/mishoo/UglifyJS2/issues/287 + label.references.forEach(function(ref){ + if (ref instanceof AST_Continue) { + ref = ref.label.start; + croak("Continue label `" + label.name + "` refers to non-IterationStatement.", + ref.line, ref.col, ref.pos); + } }); - }; - function if_() { - var cond = parenthesised(), body = statement(), belse = null; - if (is("keyword", "else")) { + } + return new AST_LabeledStatement({ body: stat, label: label }); + }; + + function simple_statement(tmp) { + return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); + }; + + function break_cont(type) { + var label = null, ldef; + if (!can_insert_semicolon()) { + label = as_symbol(AST_LabelRef, true); + } + if (label != null) { + ldef = find_if(function(l){ return l.name == label.name }, S.labels); + if (!ldef) + croak("Undefined label " + label.name); + label.thedef = ldef; + } + else if (S.in_loop == 0) + croak(type.TYPE + " not inside a loop or switch"); + semicolon(); + var stat = new type({ label: label }); + if (ldef) ldef.references.push(stat); + return stat; + }; + + function for_() { + expect("("); + var init = null; + if (!is("punc", ";")) { + init = is("keyword", "var") + ? (next(), var_(true)) + : expression(true, true); + if (is("operator", "in")) { + if (init instanceof AST_Var && init.definitions.length > 1) + croak("Only one variable declaration allowed in for..in loop"); + next(); + return for_in(init); + } + } + return regular_for(init); + }; + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(true); + expect(";"); + var step = is("punc", ")") ? null : expression(true); + expect(")"); + return new AST_For({ + init : init, + condition : test, + step : step, + body : in_loop(statement) + }); + }; + + function for_in(init) { + var lhs = init instanceof AST_Var ? init.definitions[0].name : null; + var obj = expression(true); + expect(")"); + return new AST_ForIn({ + init : init, + name : lhs, + object : obj, + body : in_loop(statement) + }); + }; + + var function_ = function(ctor) { + var in_statement = ctor === AST_Defun; + var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return new ctor({ + name: name, + argnames: (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + a.push(as_symbol(AST_SymbolFunarg)); + } next(); - belse = statement(); + return a; + })(true, []), + body: (function(loop, labels){ + ++S.in_function; + S.in_directives = true; + S.in_loop = 0; + S.labels = []; + var a = block_(); + --S.in_function; + S.in_loop = loop; + S.labels = labels; + return a; + })(S.in_loop, S.labels) + }); + }; + + function if_() { + var cond = parenthesised(), body = statement(), belse = null; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return new AST_If({ + condition : cond, + body : body, + alternative : belse + }); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + function switch_body_() { + expect("{"); + var a = [], cur = null, branch = null, tmp; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Case({ + start : (tmp = S.token, next(), tmp), + expression : expression(true), + body : cur + }); + a.push(branch); + expect(":"); + } + else if (is("keyword", "default")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Default({ + start : (tmp = S.token, next(), expect(":"), tmp), + body : cur + }); + a.push(branch); + } + else { + if (!cur) unexpected(); + cur.push(statement()); } - return new AST_If({ - condition: cond, - body: body, - alternative: belse + } + if (branch) branch.end = prev(); + next(); + return a; + }; + + function try_() { + var body = block_(), bcatch = null, bfinally = null; + if (is("keyword", "catch")) { + var start = S.token; + next(); + expect("("); + var name = as_symbol(AST_SymbolCatch); + expect(")"); + bcatch = new AST_Catch({ + start : start, + argname : name, + body : block_(), + end : prev() + }); + } + if (is("keyword", "finally")) { + var start = S.token; + next(); + bfinally = new AST_Finally({ + start : start, + body : block_(), + end : prev() }); } - function block_() { - expect("{"); - var a = []; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - a.push(statement()); - } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return new AST_Try({ + body : body, + bcatch : bcatch, + bfinally : bfinally + }); + }; + + function vardefs(no_in, in_const) { + var a = []; + for (;;) { + a.push(new AST_VarDef({ + start : S.token, + name : as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), + value : is("operator", "=") ? (next(), expression(false, no_in)) : null, + end : prev() + })); + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + var var_ = function(no_in) { + return new AST_Var({ + start : prev(), + definitions : vardefs(no_in, false), + end : prev() + }); + }; + + var const_ = function() { + return new AST_Const({ + start : prev(), + definitions : vardefs(false, true), + end : prev() + }); + }; + + var new_ = function() { + var start = S.token; + expect_token("operator", "new"); + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(new AST_New({ + start : start, + expression : newexp, + args : args, + end : prev() + }), true); + }; + + function as_atom_node() { + var tok = S.token, ret; + switch (tok.type) { + case "name": + case "keyword": + ret = _make_symbol(AST_SymbolRef); + break; + case "num": + ret = new AST_Number({ start: tok, end: tok, value: tok.value }); + break; + case "string": + ret = new AST_String({ start: tok, end: tok, value: tok.value }); + break; + case "regexp": + ret = new AST_RegExp({ start: tok, end: tok, value: tok.value }); + break; + case "atom": + switch (tok.value) { + case "false": + ret = new AST_False({ start: tok, end: tok }); + break; + case "true": + ret = new AST_True({ start: tok, end: tok }); + break; + case "null": + ret = new AST_Null({ start: tok, end: tok }); + break; + } + break; + } + next(); + return ret; + }; + + var expr_atom = function(allow_calls) { + if (is("operator", "new")) { + return new_(); + } + var start = S.token; + if (is("punc")) { + switch (start.value) { + case "(": + next(); + var ex = expression(true); + ex.start = start; + ex.end = S.token; + expect(")"); + return subscripts(ex, allow_calls); + case "[": + return subscripts(array_(), allow_calls); + case "{": + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + var func = function_(AST_Function); + func.start = start; + func.end = prev(); + return subscripts(func, allow_calls); + } + if (ATOMIC_START_TOKEN[S.token.type]) { + return subscripts(as_atom_node(), allow_calls); + } + unexpected(); + }; + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push(new AST_Hole({ start: S.token, end: S.token })); + } else { + a.push(expression(false)); + } + } + next(); + return a; + }; + + var array_ = embed_tokens(function() { + expect("["); + return new AST_Array({ + elements: expr_list("]", !options.strict, true) + }); + }); + + var object_ = embed_tokens(function() { + expect("{"); + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!options.strict && is("punc", "}")) + // allow trailing comma + break; + var start = S.token; + var type = start.type; + var name = as_property_name(); + if (type == "name" && !is("punc", ":")) { + if (name == "get") { + a.push(new AST_ObjectGetter({ + start : start, + key : as_atom_node(), + value : function_(AST_Accessor), + end : prev() + })); + continue; + } + if (name == "set") { + a.push(new AST_ObjectSetter({ + start : start, + key : as_atom_node(), + value : function_(AST_Accessor), + end : prev() + })); + continue; + } + } + expect(":"); + a.push(new AST_ObjectKeyVal({ + start : start, + key : name, + value : expression(false), + end : prev() + })); + } + next(); + return new AST_Object({ properties: a }); + }); + + function as_property_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "num": + case "string": + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + default: + unexpected(); + } + }; + + function as_name() { + var tmp = S.token; + next(); + switch (tmp.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return tmp.value; + default: + unexpected(); + } + }; + + function _make_symbol(type) { + var name = S.token.value; + return new (name == "this" ? AST_This : type)({ + name : String(name), + start : S.token, + end : S.token + }); + }; + + function as_symbol(type, noerror) { + if (!is("name")) { + if (!noerror) croak("Name expected"); + return null; + } + var sym = _make_symbol(type); + next(); + return sym; + }; + + var subscripts = function(expr, allow_calls) { + var start = expr.start; + if (is("punc", ".")) { next(); - return a; + return subscripts(new AST_Dot({ + start : start, + expression : expr, + property : as_name(), + end : prev() + }), allow_calls); } - function switch_body_() { - expect("{"); - var a = [], cur = null, branch = null, tmp; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - if (is("keyword", "case")) { - if (branch) branch.end = prev(); - cur = []; - branch = new AST_Case({ - start: (tmp = S.token, next(), tmp), - expression: expression(true), - body: cur - }); - a.push(branch); - expect(":"); - } else if (is("keyword", "default")) { - if (branch) branch.end = prev(); - cur = []; - branch = new AST_Default({ - start: (tmp = S.token, next(), expect(":"), tmp), - body: cur - }); - a.push(branch); - } else { - if (!cur) unexpected(); - cur.push(statement()); - } - } - if (branch) branch.end = prev(); + if (is("punc", "[")) { next(); - return a; + var prop = expression(true); + expect("]"); + return subscripts(new AST_Sub({ + start : start, + expression : expr, + property : prop, + end : prev() + }), allow_calls); } - function try_() { - var body = block_(), bcatch = null, bfinally = null; - if (is("keyword", "catch")) { - var start = S.token; - next(); - expect("("); - var name = as_symbol(AST_SymbolCatch); - expect(")"); - bcatch = new AST_Catch({ - start: start, - argname: name, - body: block_(), - end: prev() - }); - } - if (is("keyword", "finally")) { - var start = S.token; - next(); - bfinally = new AST_Finally({ - start: start, - body: block_(), - end: prev() - }); - } - if (!bcatch && !bfinally) croak("Missing catch/finally blocks"); - return new AST_Try({ - body: body, - bcatch: bcatch, - bfinally: bfinally + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(new AST_Call({ + start : start, + expression : expr, + args : expr_list(")"), + end : prev() + }), true); + } + return expr; + }; + + var maybe_unary = function(allow_calls) { + var start = S.token; + if (is("operator") && UNARY_PREFIX(start.value)) { + next(); + handle_regexp(); + var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); + ex.start = start; + ex.end = prev(); + return ex; + } + var val = expr_atom(allow_calls); + while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { + val = make_unary(AST_UnaryPostfix, S.token.value, val); + val.start = start; + val.end = S.token; + next(); + } + return val; + }; + + function make_unary(ctor, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return new ctor({ operator: op, expression: expr }); + }; + + var expr_op = function(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op == "in" && no_in) op = null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(new AST_Binary({ + start : left.start, + left : left, + operator : op, + right : right, + end : right.end + }), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(maybe_unary(true), 0, no_in); + }; + + var maybe_conditional = function(no_in) { + var start = S.token; + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return new AST_Conditional({ + start : start, + condition : expr, + consequent : yes, + alternative : expression(false, no_in), + end : peek() }); } - function vardefs(no_in, in_const) { - var a = []; - for (;;) { - a.push(new AST_VarDef({ - start: S.token, - name: as_symbol(in_const ? AST_SymbolConst : AST_SymbolVar), - value: is("operator", "=") ? (next(), expression(false, no_in)) : null, - end: prev() - })); - if (!is("punc", ",")) break; + return expr; + }; + + function is_assignable(expr) { + if (!options.strict) return true; + if (expr instanceof AST_This) return false; + return (expr instanceof AST_PropAccess || expr instanceof AST_Symbol); + }; + + var maybe_assign = function(no_in) { + var start = S.token; + var left = maybe_conditional(no_in), val = S.token.value; + if (is("operator") && ASSIGNMENT(val)) { + if (is_assignable(left)) { next(); + return new AST_Assign({ + start : start, + left : left, + operator : val, + right : maybe_assign(no_in), + end : prev() + }); } - return a; + croak("Invalid assignment"); } - var var_ = function(no_in) { - return new AST_Var({ - start: prev(), - definitions: vardefs(no_in, false), - end: prev() - }); - }; - var const_ = function() { - return new AST_Const({ - start: prev(), - definitions: vardefs(false, true), - end: prev() + return left; + }; + + var expression = function(commas, no_in) { + var start = S.token; + var expr = maybe_assign(no_in); + if (commas && is("punc", ",")) { + next(); + return new AST_Seq({ + start : start, + car : expr, + cdr : expression(true, no_in), + end : peek() }); - }; - var new_ = function() { - var start = S.token; - expect_token("operator", "new"); - var newexp = expr_atom(false), args; - if (is("punc", "(")) { - next(); - args = expr_list(")"); - } else { - args = []; + } + return expr; + }; + + function in_loop(cont) { + ++S.in_loop; + var ret = cont(); + --S.in_loop; + return ret; + }; + + if (options.expression) { + return expression(true); + } + + return (function(){ + var start = S.token; + var body = []; + while (!is("eof")) + body.push(statement()); + var end = prev(); + var toplevel = options.toplevel; + if (toplevel) { + toplevel.body = toplevel.body.concat(body); + toplevel.end = end; + } else { + toplevel = new AST_Toplevel({ start: start, body: body, end: end }); + } + return toplevel; + })(); + +}; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +"use strict"; + +// Tree transformer helpers. + +function TreeTransformer(before, after) { + TreeWalker.call(this); + this.before = before; + this.after = after; +} +TreeTransformer.prototype = new TreeWalker; + +(function(undefined){ + + function _(node, descend) { + node.DEFMETHOD("transform", function(tw, in_list){ + var x, y; + tw.push(this); + if (tw.before) x = tw.before(this, descend, in_list); + if (x === undefined) { + if (!tw.after) { + x = this; + descend(x, tw); + } else { + tw.stack[tw.stack.length - 1] = x = this.clone(); + descend(x, tw); + y = tw.after(x, in_list); + if (y !== undefined) x = y; + } } - return subscripts(new AST_New({ - start: start, - expression: newexp, - args: args, - end: prev() - }), true); - }; - function as_atom_node() { - var tok = S.token, ret; - switch (tok.type) { - case "name": - return as_symbol(AST_SymbolRef); - - case "num": - ret = new AST_Number({ - start: tok, - end: tok, - value: tok.value - }); - break; + tw.pop(); + return x; + }); + }; - case "string": - ret = new AST_String({ - start: tok, - end: tok, - value: tok.value - }); - break; + function do_list(list, tw) { + return MAP(list, function(node){ + return node.transform(tw, true); + }); + }; - case "regexp": - ret = new AST_RegExp({ - start: tok, - end: tok, - value: tok.value - }); - break; + _(AST_Node, noop); + + _(AST_LabeledStatement, function(self, tw){ + self.label = self.label.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_SimpleStatement, function(self, tw){ + self.body = self.body.transform(tw); + }); + + _(AST_Block, function(self, tw){ + self.body = do_list(self.body, tw); + }); + + _(AST_DWLoop, function(self, tw){ + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_For, function(self, tw){ + if (self.init) self.init = self.init.transform(tw); + if (self.condition) self.condition = self.condition.transform(tw); + if (self.step) self.step = self.step.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_ForIn, function(self, tw){ + self.init = self.init.transform(tw); + self.object = self.object.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_With, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = self.body.transform(tw); + }); + + _(AST_Exit, function(self, tw){ + if (self.value) self.value = self.value.transform(tw); + }); + + _(AST_LoopControl, function(self, tw){ + if (self.label) self.label = self.label.transform(tw); + }); + + _(AST_If, function(self, tw){ + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + if (self.alternative) self.alternative = self.alternative.transform(tw); + }); + + _(AST_Switch, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Case, function(self, tw){ + self.expression = self.expression.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Try, function(self, tw){ + self.body = do_list(self.body, tw); + if (self.bcatch) self.bcatch = self.bcatch.transform(tw); + if (self.bfinally) self.bfinally = self.bfinally.transform(tw); + }); + + _(AST_Catch, function(self, tw){ + self.argname = self.argname.transform(tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Definitions, function(self, tw){ + self.definitions = do_list(self.definitions, tw); + }); + + _(AST_VarDef, function(self, tw){ + self.name = self.name.transform(tw); + if (self.value) self.value = self.value.transform(tw); + }); + + _(AST_Lambda, function(self, tw){ + if (self.name) self.name = self.name.transform(tw); + self.argnames = do_list(self.argnames, tw); + self.body = do_list(self.body, tw); + }); + + _(AST_Call, function(self, tw){ + self.expression = self.expression.transform(tw); + self.args = do_list(self.args, tw); + }); + + _(AST_Seq, function(self, tw){ + self.car = self.car.transform(tw); + self.cdr = self.cdr.transform(tw); + }); + + _(AST_Dot, function(self, tw){ + self.expression = self.expression.transform(tw); + }); + + _(AST_Sub, function(self, tw){ + self.expression = self.expression.transform(tw); + self.property = self.property.transform(tw); + }); + + _(AST_Unary, function(self, tw){ + self.expression = self.expression.transform(tw); + }); + + _(AST_Binary, function(self, tw){ + self.left = self.left.transform(tw); + self.right = self.right.transform(tw); + }); + + _(AST_Conditional, function(self, tw){ + self.condition = self.condition.transform(tw); + self.consequent = self.consequent.transform(tw); + self.alternative = self.alternative.transform(tw); + }); + + _(AST_Array, function(self, tw){ + self.elements = do_list(self.elements, tw); + }); + + _(AST_Object, function(self, tw){ + self.properties = do_list(self.properties, tw); + }); + + _(AST_ObjectProperty, function(self, tw){ + self.value = self.value.transform(tw); + }); + +})(); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. - case "atom": - switch (tok.value) { - case "false": - ret = new AST_False({ - start: tok, - end: tok - }); - break; + ***********************************************************************/ - case "true": - ret = new AST_True({ - start: tok, - end: tok - }); - break; +"use strict"; + +function SymbolDef(scope, index, orig) { + this.name = orig.name; + this.orig = [ orig ]; + this.scope = scope; + this.references = []; + this.global = false; + this.mangled_name = null; + this.undeclared = false; + this.constant = false; + this.index = index; +}; - case "null": - ret = new AST_Null({ - start: tok, - end: tok - }); - break; - } - break; - } - next(); - return ret; - } - var expr_atom = function(allow_calls) { - if (is("operator", "new")) { - return new_(); - } - var start = S.token; - if (is("punc")) { - switch (start.value) { - case "(": - next(); - var ex = expression(true); - ex.start = start; - ex.end = S.token; - expect(")"); - return subscripts(ex, allow_calls); - - case "[": - return subscripts(array_(), allow_calls); - - case "{": - return subscripts(object_(), allow_calls); - } - unexpected(); - } - if (is("keyword", "function")) { - next(); - var func = function_(false); - func.start = start; - func.end = prev(); - return subscripts(func, allow_calls); - } - if (ATOMIC_START_TOKEN[S.token.type]) { - return subscripts(as_atom_node(), allow_calls); - } - unexpected(); - }; - function expr_list(closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; - while (!is("punc", closing)) { - if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push(new AST_Hole({ - start: S.token, - end: S.token - })); - } else { - a.push(expression(false)); - } - } - next(); - return a; +SymbolDef.prototype = { + unmangleable: function(options) { + return (this.global && !(options && options.toplevel)) + || this.undeclared + || (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with)); + }, + mangle: function(options) { + if (!this.mangled_name && !this.unmangleable(options)) { + var s = this.scope; + if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda) + s = s.parent_scope; + this.mangled_name = s.next_mangled(options, this); } - var array_ = embed_tokens(function() { - expect("["); - return new AST_Array({ - elements: expr_list("]", !options.strict, true) - }); - }); - var object_ = embed_tokens(function() { - expect("{"); - var first = true, a = []; - while (!is("punc", "}")) { - if (first) first = false; else expect(","); - if (!options.strict && is("punc", "}")) break; - var start = S.token; - var type = start.type; - var name = as_property_name(); - if (type == "name" && !is("punc", ":")) { - if (name == "get") { - a.push(new AST_ObjectGetter({ - start: start, - key: name, - value: function_(false, AST_Accessor), - end: prev() - })); - continue; - } - if (name == "set") { - a.push(new AST_ObjectSetter({ - start: start, - key: name, - value: function_(false, AST_Accessor), - end: prev() - })); - continue; - } - } - expect(":"); - a.push(new AST_ObjectKeyVal({ - start: start, - key: name, - value: expression(false), - end: prev() - })); - } - next(); - return new AST_Object({ - properties: a - }); - }); - function as_property_name() { - var tmp = S.token; - next(); - switch (tmp.type) { - case "num": - case "string": - case "name": - case "operator": - case "keyword": - case "atom": - return tmp.value; + } +}; - default: - unexpected(); - } - } - function as_name() { - var tmp = S.token; - next(); - switch (tmp.type) { - case "name": - case "operator": - case "keyword": - case "atom": - return tmp.value; +AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ + options = defaults(options, { + screw_ie8: false + }); - default: - unexpected(); - } - } - function as_symbol(type, noerror) { - if (!is("name")) { - if (!noerror) croak("Name expected"); - return null; - } - var name = S.token.value; - var sym = new (name == "this" ? AST_This : type)({ - name: String(S.token.value), - start: S.token, - end: S.token - }); - next(); - return sym; + // pass 1: setup scope chaining and handle definitions + var self = this; + var scope = self.parent_scope = null; + var defun = null; + var nesting = 0; + var tw = new TreeWalker(function(node, descend){ + if (options.screw_ie8 && node instanceof AST_Catch) { + var save_scope = scope; + scope = new AST_Scope(node); + scope.init_scope_vars(nesting); + scope.parent_scope = save_scope; + descend(); + scope = save_scope; + return true; } - var subscripts = function(expr, allow_calls) { - var start = expr.start; - if (is("punc", ".")) { - next(); - return subscripts(new AST_Dot({ - start: start, - expression: expr, - property: as_name(), - end: prev() - }), allow_calls); - } - if (is("punc", "[")) { - next(); - var prop = expression(true); - expect("]"); - return subscripts(new AST_Sub({ - start: start, - expression: expr, - property: prop, - end: prev() - }), allow_calls); - } - if (allow_calls && is("punc", "(")) { - next(); - return subscripts(new AST_Call({ - start: start, - expression: expr, - args: expr_list(")"), - end: prev() - }), true); - } - return expr; - }; - var maybe_unary = function(allow_calls) { - var start = S.token; - if (is("operator") && UNARY_PREFIX(start.value)) { - next(); - var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls)); - ex.start = start; - ex.end = prev(); - return ex; - } - var val = expr_atom(allow_calls); - while (is("operator") && UNARY_POSTFIX(S.token.value) && !S.token.nlb) { - val = make_unary(AST_UnaryPostfix, S.token.value, val); - val.start = start; - val.end = S.token; - next(); - } - return val; - }; - function make_unary(ctor, op, expr) { - if ((op == "++" || op == "--") && !is_assignable(expr)) croak("Invalid use of " + op + " operator"); - return new ctor({ - operator: op, - expression: expr - }); + if (node instanceof AST_Scope) { + node.init_scope_vars(nesting); + var save_scope = node.parent_scope = scope; + var save_defun = defun; + defun = scope = node; + ++nesting; descend(); --nesting; + scope = save_scope; + defun = save_defun; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_Directive) { + node.scope = scope; + push_uniq(scope.directives, node.value); + return true; } - var expr_op = function(left, min_prec, no_in) { - var op = is("operator") ? S.token.value : null; - if (op == "in" && no_in) op = null; - var prec = op != null ? PRECEDENCE[op] : null; - if (prec != null && prec > min_prec) { - next(); - var right = expr_op(maybe_unary(true), prec, no_in); - return expr_op(new AST_Binary({ - start: left.start, - left: left, - operator: op, - right: right, - end: right.end - }), min_prec, no_in); - } - return left; - }; - function expr_ops(no_in) { - return expr_op(maybe_unary(true), 0, no_in); + if (node instanceof AST_With) { + for (var s = scope; s; s = s.parent_scope) + s.uses_with = true; + return; } - var maybe_conditional = function(no_in) { - var start = S.token; - var expr = expr_ops(no_in); - if (is("operator", "?")) { - next(); - var yes = expression(false); - expect(":"); - return new AST_Conditional({ - start: start, - condition: expr, - consequent: yes, - alternative: expression(false, no_in), - end: peek() - }); - } - return expr; - }; - function is_assignable(expr) { - if (!options.strict) return true; - if (expr instanceof AST_This) return false; - return expr instanceof AST_PropAccess || expr instanceof AST_Symbol; + if (node instanceof AST_Symbol) { + node.scope = scope; } - var maybe_assign = function(no_in) { - var start = S.token; - var left = maybe_conditional(no_in), val = S.token.value; - if (is("operator") && ASSIGNMENT(val)) { - if (is_assignable(left)) { - next(); - return new AST_Assign({ - start: start, - left: left, - operator: val, - right: maybe_assign(no_in), - end: prev() - }); - } - croak("Invalid assignment"); - } - return left; - }; - var expression = function(commas, no_in) { - var start = S.token; - var expr = maybe_assign(no_in); - if (commas && is("punc", ",")) { - next(); - return new AST_Seq({ - start: start, - car: expr, - cdr: expression(true, no_in), - end: peek() - }); - } - return expr; - }; - function in_loop(cont) { - ++S.in_loop; - var ret = cont(); - --S.in_loop; - return ret; + if (node instanceof AST_SymbolLambda) { + defun.def_function(node); } - if (options.expression) { - return expression(true); + else if (node instanceof AST_SymbolDefun) { + // Careful here, the scope where this should be defined is + // the parent scope. The reason is that we enter a new + // scope when we encounter the AST_Defun node (which is + // instanceof AST_Scope) but we get to the symbol a bit + // later. + (node.scope = defun.parent_scope).def_function(node); } - return function() { - var start = S.token; - var body = []; - while (!is("eof")) body.push(statement()); - var end = prev(); - var toplevel = options.toplevel; - if (toplevel) { - toplevel.body = toplevel.body.concat(body); - toplevel.end = end; - } else { - toplevel = new AST_Toplevel({ - start: start, - body: body, - end: end - }); - } - return toplevel; - }(); - } - "use strict"; - function TreeTransformer(before, after) { - TreeWalker.call(this); - this.before = before; - this.after = after; - } - TreeTransformer.prototype = new TreeWalker(); - (function(undefined) { - function _(node, descend) { - node.DEFMETHOD("transform", function(tw, in_list) { - var x, y; - tw.push(this); - if (tw.before) x = tw.before(this, descend, in_list); - if (x === undefined) { - if (!tw.after) { - x = this; - descend(x, tw); - } else { - tw.stack[tw.stack.length - 1] = x = this.clone(); - descend(x, tw); - y = tw.after(x, in_list); - if (y !== undefined) x = y; - } - } - tw.pop(); - return x; - }); + else if (node instanceof AST_SymbolVar + || node instanceof AST_SymbolConst) { + var def = defun.def_variable(node); + def.constant = node instanceof AST_SymbolConst; + def.init = tw.parent().value; } - function do_list(list, tw) { - return MAP(list, function(node) { - return node.transform(tw, true); - }); + else if (node instanceof AST_SymbolCatch) { + (options.screw_ie8 ? scope : defun) + .def_variable(node); } - _(AST_Node, noop); - _(AST_LabeledStatement, function(self, tw) { - self.label = self.label.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_SimpleStatement, function(self, tw) { - self.body = self.body.transform(tw); - }); - _(AST_Block, function(self, tw) { - self.body = do_list(self.body, tw); - }); - _(AST_DWLoop, function(self, tw) { - self.condition = self.condition.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_For, function(self, tw) { - if (self.init) self.init = self.init.transform(tw); - if (self.condition) self.condition = self.condition.transform(tw); - if (self.step) self.step = self.step.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_ForIn, function(self, tw) { - self.init = self.init.transform(tw); - self.object = self.object.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_With, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = self.body.transform(tw); - }); - _(AST_Exit, function(self, tw) { - if (self.value) self.value = self.value.transform(tw); - }); - _(AST_LoopControl, function(self, tw) { - if (self.label) self.label = self.label.transform(tw); - }); - _(AST_If, function(self, tw) { - self.condition = self.condition.transform(tw); - self.body = self.body.transform(tw); - if (self.alternative) self.alternative = self.alternative.transform(tw); - }); - _(AST_Switch, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = do_list(self.body, tw); - }); - _(AST_Case, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = do_list(self.body, tw); - }); - _(AST_Try, function(self, tw) { - self.body = do_list(self.body, tw); - if (self.bcatch) self.bcatch = self.bcatch.transform(tw); - if (self.bfinally) self.bfinally = self.bfinally.transform(tw); - }); - _(AST_Catch, function(self, tw) { - self.argname = self.argname.transform(tw); - self.body = do_list(self.body, tw); - }); - _(AST_Definitions, function(self, tw) { - self.definitions = do_list(self.definitions, tw); - }); - _(AST_VarDef, function(self, tw) { - self.name = self.name.transform(tw); - if (self.value) self.value = self.value.transform(tw); - }); - _(AST_Lambda, function(self, tw) { - if (self.name) self.name = self.name.transform(tw); - self.argnames = do_list(self.argnames, tw); - self.body = do_list(self.body, tw); - }); - _(AST_Call, function(self, tw) { - self.expression = self.expression.transform(tw); - self.args = do_list(self.args, tw); - }); - _(AST_Seq, function(self, tw) { - self.car = self.car.transform(tw); - self.cdr = self.cdr.transform(tw); - }); - _(AST_Dot, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - _(AST_Sub, function(self, tw) { - self.expression = self.expression.transform(tw); - self.property = self.property.transform(tw); - }); - _(AST_Unary, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - _(AST_Binary, function(self, tw) { - self.left = self.left.transform(tw); - self.right = self.right.transform(tw); - }); - _(AST_Conditional, function(self, tw) { - self.condition = self.condition.transform(tw); - self.consequent = self.consequent.transform(tw); - self.alternative = self.alternative.transform(tw); - }); - _(AST_Array, function(self, tw) { - self.elements = do_list(self.elements, tw); - }); - _(AST_Object, function(self, tw) { - self.properties = do_list(self.properties, tw); - }); - _(AST_ObjectProperty, function(self, tw) { - self.value = self.value.transform(tw); - }); - })(); - "use strict"; - function SymbolDef(scope, index, orig) { - this.name = orig.name; - this.orig = [ orig ]; - this.scope = scope; - this.references = []; - this.global = false; - this.mangled_name = null; - this.undeclared = false; - this.constant = false; - this.index = index; - } - SymbolDef.prototype = { - unmangleable: function(options) { - return this.global && !(options && options.toplevel) || this.undeclared || !(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with); - }, - mangle: function(options) { - if (!this.mangled_name && !this.unmangleable(options)) { - var s = this.scope; - if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8) s = s.parent_scope; - this.mangled_name = s.next_mangled(options); - } + }); + self.walk(tw); + + // pass 2: find back references and eval + var func = null; + var globals = self.globals = new Dictionary(); + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_Lambda) { + var prev_func = func; + func = node; + descend(); + func = prev_func; + return true; } - }; - AST_Toplevel.DEFMETHOD("figure_out_scope", function() { - var self = this; - var scope = self.parent_scope = null; - var labels = new Dictionary(); - var nesting = 0; - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_Scope) { - node.init_scope_vars(nesting); - var save_scope = node.parent_scope = scope; - var save_labels = labels; - ++nesting; - scope = node; - labels = new Dictionary(); - descend(); - labels = save_labels; - scope = save_scope; - --nesting; - return true; - } - if (node instanceof AST_Directive) { - node.scope = scope; - push_uniq(scope.directives, node.value); - return true; - } - if (node instanceof AST_With) { - for (var s = scope; s; s = s.parent_scope) s.uses_with = true; - return; - } - if (node instanceof AST_LabeledStatement) { - var l = node.label; - if (labels.has(l.name)) throw new Error(string_template("Label {name} defined twice", l)); - labels.set(l.name, l); - descend(); - labels.del(l.name); - return true; - } - if (node instanceof AST_Symbol) { - node.scope = scope; - } - if (node instanceof AST_Label) { - node.thedef = node; - node.init_scope_vars(); - } - if (node instanceof AST_SymbolLambda) { - scope.def_function(node); - } else if (node instanceof AST_SymbolDefun) { - (node.scope = scope.parent_scope).def_function(node); - } else if (node instanceof AST_SymbolVar || node instanceof AST_SymbolConst) { - var def = scope.def_variable(node); - def.constant = node instanceof AST_SymbolConst; - def.init = tw.parent().value; - } else if (node instanceof AST_SymbolCatch) { - scope.def_variable(node); - } - if (node instanceof AST_LabelRef) { - var sym = labels.get(node.name); - if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { - name: node.name, - line: node.start.line, - col: node.start.col - })); - node.thedef = sym; - } - }); - self.walk(tw); - var func = null; - var globals = self.globals = new Dictionary(); - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_Lambda) { - var prev_func = func; - func = node; - descend(); - func = prev_func; - return true; - } - if (node instanceof AST_LabelRef) { - node.reference(); - return true; - } - if (node instanceof AST_SymbolRef) { - var name = node.name; - var sym = node.scope.find_variable(name); - if (!sym) { - var g; - if (globals.has(name)) { - g = globals.get(name); - } else { - g = new SymbolDef(self, globals.size(), node); - g.undeclared = true; - g.global = true; - globals.set(name, g); - } - node.thedef = g; - if (name == "eval" && tw.parent() instanceof AST_Call) { - for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) s.uses_eval = true; - } - if (name == "arguments") { - func.uses_arguments = true; - } + if (node instanceof AST_SymbolRef) { + var name = node.name; + var sym = node.scope.find_variable(name); + if (!sym) { + var g; + if (globals.has(name)) { + g = globals.get(name); } else { - node.thedef = sym; + g = new SymbolDef(self, globals.size(), node); + g.undeclared = true; + g.global = true; + globals.set(name, g); } - node.reference(); - return true; + node.thedef = g; + if (name == "eval" && tw.parent() instanceof AST_Call) { + for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) + s.uses_eval = true; + } + if (func && name == "arguments") { + func.uses_arguments = true; + } + } else { + node.thedef = sym; } - }); - self.walk(tw); - }); - AST_Scope.DEFMETHOD("init_scope_vars", function(nesting) { - this.directives = []; - this.variables = new Dictionary(); - this.functions = new Dictionary(); - this.uses_with = false; - this.uses_eval = false; - this.parent_scope = null; - this.enclosed = []; - this.cname = -1; - this.nesting = nesting; - }); - AST_Scope.DEFMETHOD("strict", function() { - return this.has_directive("use strict"); - }); - AST_Lambda.DEFMETHOD("init_scope_vars", function() { - AST_Scope.prototype.init_scope_vars.apply(this, arguments); - this.uses_arguments = false; - }); - AST_SymbolRef.DEFMETHOD("reference", function() { - var def = this.definition(); - def.references.push(this); - var s = this.scope; - while (s) { - push_uniq(s.enclosed, def); - if (s === def.scope) break; - s = s.parent_scope; - } - this.frame = this.scope.nesting - def.scope.nesting; - }); - AST_Label.DEFMETHOD("init_scope_vars", function() { - this.references = []; - }); - AST_LabelRef.DEFMETHOD("reference", function() { - this.thedef.references.push(this); - }); - AST_Scope.DEFMETHOD("find_variable", function(name) { - if (name instanceof AST_Symbol) name = name.name; - return this.variables.get(name) || this.parent_scope && this.parent_scope.find_variable(name); - }); - AST_Scope.DEFMETHOD("has_directive", function(value) { - return this.parent_scope && this.parent_scope.has_directive(value) || (this.directives.indexOf(value) >= 0 ? this : null); + node.reference(); + return true; + } }); - AST_Scope.DEFMETHOD("def_function", function(symbol) { - this.functions.set(symbol.name, this.def_variable(symbol)); + self.walk(tw); +}); + +AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){ + this.directives = []; // contains the directives defined in this scope, i.e. "use strict" + this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) + this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope) + this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement + this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` + this.parent_scope = null; // the parent scope + this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes + this.cname = -1; // the current index for mangling functions/variables + this.nesting = nesting; // the nesting level of this scope (0 means toplevel) +}); + +AST_Scope.DEFMETHOD("strict", function(){ + return this.has_directive("use strict"); +}); + +AST_Lambda.DEFMETHOD("init_scope_vars", function(){ + AST_Scope.prototype.init_scope_vars.apply(this, arguments); + this.uses_arguments = false; +}); + +AST_SymbolRef.DEFMETHOD("reference", function() { + var def = this.definition(); + def.references.push(this); + var s = this.scope; + while (s) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + s = s.parent_scope; + } + this.frame = this.scope.nesting - def.scope.nesting; +}); + +AST_Scope.DEFMETHOD("find_variable", function(name){ + if (name instanceof AST_Symbol) name = name.name; + return this.variables.get(name) + || (this.parent_scope && this.parent_scope.find_variable(name)); +}); + +AST_Scope.DEFMETHOD("has_directive", function(value){ + return this.parent_scope && this.parent_scope.has_directive(value) + || (this.directives.indexOf(value) >= 0 ? this : null); +}); + +AST_Scope.DEFMETHOD("def_function", function(symbol){ + this.functions.set(symbol.name, this.def_variable(symbol)); +}); + +AST_Scope.DEFMETHOD("def_variable", function(symbol){ + var def; + if (!this.variables.has(symbol.name)) { + def = new SymbolDef(this, this.variables.size(), symbol); + this.variables.set(symbol.name, def); + def.global = !this.parent_scope; + } else { + def = this.variables.get(symbol.name); + def.orig.push(symbol); + } + return symbol.thedef = def; +}); + +AST_Scope.DEFMETHOD("next_mangled", function(options){ + var ext = this.enclosed; + out: while (true) { + var m = base54(++this.cname); + if (!is_identifier(m)) continue; // skip over "do" + + // https://github.com/mishoo/UglifyJS2/issues/242 -- do not + // shadow a name excepted from mangling. + if (options.except.indexOf(m) >= 0) continue; + + // we must ensure that the mangled name does not shadow a name + // from some parent scope that is referenced in this or in + // inner scopes. + for (var i = ext.length; --i >= 0;) { + var sym = ext[i]; + var name = sym.mangled_name || (sym.unmangleable(options) && sym.name); + if (m == name) continue out; + } + return m; + } +}); + +AST_Function.DEFMETHOD("next_mangled", function(options, def){ + // #179, #326 + // in Safari strict mode, something like (function x(x){...}) is a syntax error; + // a function expression's argument cannot shadow the function expression's name + + var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition(); + while (true) { + var name = AST_Lambda.prototype.next_mangled.call(this, options, def); + if (!(tricky_def && tricky_def.mangled_name == name)) + return name; + } +}); + +AST_Scope.DEFMETHOD("references", function(sym){ + if (sym instanceof AST_Symbol) sym = sym.definition(); + return this.enclosed.indexOf(sym) < 0 ? null : sym; +}); + +AST_Symbol.DEFMETHOD("unmangleable", function(options){ + return this.definition().unmangleable(options); +}); + +// property accessors are not mangleable +AST_SymbolAccessor.DEFMETHOD("unmangleable", function(){ + return true; +}); + +// labels are always mangleable +AST_Label.DEFMETHOD("unmangleable", function(){ + return false; +}); + +AST_Symbol.DEFMETHOD("unreferenced", function(){ + return this.definition().references.length == 0 + && !(this.scope.uses_eval || this.scope.uses_with); +}); + +AST_Symbol.DEFMETHOD("undeclared", function(){ + return this.definition().undeclared; +}); + +AST_LabelRef.DEFMETHOD("undeclared", function(){ + return false; +}); + +AST_Label.DEFMETHOD("undeclared", function(){ + return false; +}); + +AST_Symbol.DEFMETHOD("definition", function(){ + return this.thedef; +}); + +AST_Symbol.DEFMETHOD("global", function(){ + return this.definition().global; +}); + +AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){ + return defaults(options, { + except : [], + eval : false, + sort : false, + toplevel : false, + screw_ie8 : false }); - AST_Scope.DEFMETHOD("def_variable", function(symbol) { - var def; - if (!this.variables.has(symbol.name)) { - def = new SymbolDef(this, this.variables.size(), symbol); - this.variables.set(symbol.name, def); - def.global = !this.parent_scope; - } else { - def = this.variables.get(symbol.name); - def.orig.push(symbol); +}); + +AST_Toplevel.DEFMETHOD("mangle_names", function(options){ + options = this._default_mangler_options(options); + // We only need to mangle declaration nodes. Special logic wired + // into the code generator will display the mangled name if it's + // present (and for AST_SymbolRef-s it'll use the mangled name of + // the AST_SymbolDeclaration that it points to). + var lname = -1; + var to_mangle = []; + var tw = new TreeWalker(function(node, descend){ + if (node instanceof AST_LabeledStatement) { + // lname is incremented when we get to the AST_Label + var save_nesting = lname; + descend(); + lname = save_nesting; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_Scope) { + var p = tw.parent(), a = []; + node.variables.each(function(symbol){ + if (options.except.indexOf(symbol.name) < 0) { + a.push(symbol); + } + }); + if (options.sort) a.sort(function(a, b){ + return b.references.length - a.references.length; + }); + to_mangle.push.apply(to_mangle, a); + return; } - return symbol.thedef = def; - }); - AST_Scope.DEFMETHOD("next_mangled", function(options) { - var ext = this.enclosed; - out: while (true) { - var m = base54(++this.cname); - if (!is_identifier(m)) continue; - for (var i = ext.length; --i >= 0; ) { - var sym = ext[i]; - var name = sym.mangled_name || sym.unmangleable(options) && sym.name; - if (m == name) continue out; - } - return m; + if (node instanceof AST_Label) { + var name; + do name = base54(++lname); while (!is_identifier(name)); + node.mangled_name = name; + return true; } }); - AST_Scope.DEFMETHOD("references", function(sym) { - if (sym instanceof AST_Symbol) sym = sym.definition(); - return this.enclosed.indexOf(sym) < 0 ? null : sym; - }); - AST_Symbol.DEFMETHOD("unmangleable", function(options) { - return this.definition().unmangleable(options); - }); - AST_SymbolAccessor.DEFMETHOD("unmangleable", function() { - return true; - }); - AST_Label.DEFMETHOD("unmangleable", function() { - return false; - }); - AST_Symbol.DEFMETHOD("unreferenced", function() { - return this.definition().references.length == 0 && !(this.scope.uses_eval || this.scope.uses_with); - }); - AST_Symbol.DEFMETHOD("undeclared", function() { - return this.definition().undeclared; - }); - AST_LabelRef.DEFMETHOD("undeclared", function() { - return false; - }); - AST_Label.DEFMETHOD("undeclared", function() { - return false; - }); - AST_Symbol.DEFMETHOD("definition", function() { - return this.thedef; - }); - AST_Symbol.DEFMETHOD("global", function() { - return this.definition().global; + this.walk(tw); + to_mangle.forEach(function(def){ def.mangle(options) }); +}); + +AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){ + options = this._default_mangler_options(options); + var tw = new TreeWalker(function(node){ + if (node instanceof AST_Constant) + base54.consider(node.print_to_string()); + else if (node instanceof AST_Return) + base54.consider("return"); + else if (node instanceof AST_Throw) + base54.consider("throw"); + else if (node instanceof AST_Continue) + base54.consider("continue"); + else if (node instanceof AST_Break) + base54.consider("break"); + else if (node instanceof AST_Debugger) + base54.consider("debugger"); + else if (node instanceof AST_Directive) + base54.consider(node.value); + else if (node instanceof AST_While) + base54.consider("while"); + else if (node instanceof AST_Do) + base54.consider("do while"); + else if (node instanceof AST_If) { + base54.consider("if"); + if (node.alternative) base54.consider("else"); + } + else if (node instanceof AST_Var) + base54.consider("var"); + else if (node instanceof AST_Const) + base54.consider("const"); + else if (node instanceof AST_Lambda) + base54.consider("function"); + else if (node instanceof AST_For) + base54.consider("for"); + else if (node instanceof AST_ForIn) + base54.consider("for in"); + else if (node instanceof AST_Switch) + base54.consider("switch"); + else if (node instanceof AST_Case) + base54.consider("case"); + else if (node instanceof AST_Default) + base54.consider("default"); + else if (node instanceof AST_With) + base54.consider("with"); + else if (node instanceof AST_ObjectSetter) + base54.consider("set" + node.key); + else if (node instanceof AST_ObjectGetter) + base54.consider("get" + node.key); + else if (node instanceof AST_ObjectKeyVal) + base54.consider(node.key); + else if (node instanceof AST_New) + base54.consider("new"); + else if (node instanceof AST_This) + base54.consider("this"); + else if (node instanceof AST_Try) + base54.consider("try"); + else if (node instanceof AST_Catch) + base54.consider("catch"); + else if (node instanceof AST_Finally) + base54.consider("finally"); + else if (node instanceof AST_Symbol && node.unmangleable(options)) + base54.consider(node.name); + else if (node instanceof AST_Unary || node instanceof AST_Binary) + base54.consider(node.operator); + else if (node instanceof AST_Dot) + base54.consider(node.property); }); - AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) { - return defaults(options, { - except: [], - eval: false, - sort: false, - toplevel: false, - screw_ie8: false + this.walk(tw); + base54.sort(); +}); + +var base54 = (function() { + var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; + var chars, frequency; + function reset() { + frequency = Object.create(null); + chars = string.split("").map(function(ch){ return ch.charCodeAt(0) }); + chars.forEach(function(ch){ frequency[ch] = 0 }); + } + base54.consider = function(str){ + for (var i = str.length; --i >= 0;) { + var code = str.charCodeAt(i); + if (code in frequency) ++frequency[code]; + } + }; + base54.sort = function() { + chars = mergeSort(chars, function(a, b){ + if (is_digit(a) && !is_digit(b)) return 1; + if (is_digit(b) && !is_digit(a)) return -1; + return frequency[b] - frequency[a]; }); + }; + base54.reset = reset; + reset(); + base54.get = function(){ return chars }; + base54.freq = function(){ return frequency }; + function base54(num) { + var ret = "", base = 54; + do { + ret += String.fromCharCode(chars[num % base]); + num = Math.floor(num / base); + base = 64; + } while (num > 0); + return ret; + }; + return base54; +})(); + +AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ + options = defaults(options, { + undeclared : false, // this makes a lot of noise + unreferenced : true, + assign_to_global : true, + func_arguments : true, + nested_defuns : true, + eval : true }); - AST_Toplevel.DEFMETHOD("mangle_names", function(options) { - options = this._default_mangler_options(options); - var lname = -1; - var to_mangle = []; - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_LabeledStatement) { - var save_nesting = lname; - descend(); - lname = save_nesting; - return true; - } - if (node instanceof AST_Scope) { - var p = tw.parent(), a = []; - node.variables.each(function(symbol) { - if (options.except.indexOf(symbol.name) < 0) { - a.push(symbol); - } - }); - if (options.sort) a.sort(function(a, b) { - return b.references.length - a.references.length; + var tw = new TreeWalker(function(node){ + if (options.undeclared + && node instanceof AST_SymbolRef + && node.undeclared()) + { + // XXX: this also warns about JS standard names, + // i.e. Object, Array, parseInt etc. Should add a list of + // exceptions. + AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col + }); + } + if (options.assign_to_global) + { + var sym = null; + if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) + sym = node.left; + else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) + sym = node.init; + if (sym + && (sym.undeclared() + || (sym.global() && sym.scope !== sym.definition().scope))) { + AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { + msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", + name: sym.name, + file: sym.start.file, + line: sym.start.line, + col: sym.start.col }); - to_mangle.push.apply(to_mangle, a); - return; - } - if (node instanceof AST_Label) { - var name; - do name = base54(++lname); while (!is_identifier(name)); - node.mangled_name = name; - return true; } - }); - this.walk(tw); - to_mangle.forEach(function(def) { - def.mangle(options); - }); - }); - AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { - options = this._default_mangler_options(options); - var tw = new TreeWalker(function(node) { - if (node instanceof AST_Constant) base54.consider(node.print_to_string()); else if (node instanceof AST_Return) base54.consider("return"); else if (node instanceof AST_Throw) base54.consider("throw"); else if (node instanceof AST_Continue) base54.consider("continue"); else if (node instanceof AST_Break) base54.consider("break"); else if (node instanceof AST_Debugger) base54.consider("debugger"); else if (node instanceof AST_Directive) base54.consider(node.value); else if (node instanceof AST_While) base54.consider("while"); else if (node instanceof AST_Do) base54.consider("do while"); else if (node instanceof AST_If) { - base54.consider("if"); - if (node.alternative) base54.consider("else"); - } else if (node instanceof AST_Var) base54.consider("var"); else if (node instanceof AST_Const) base54.consider("const"); else if (node instanceof AST_Lambda) base54.consider("function"); else if (node instanceof AST_For) base54.consider("for"); else if (node instanceof AST_ForIn) base54.consider("for in"); else if (node instanceof AST_Switch) base54.consider("switch"); else if (node instanceof AST_Case) base54.consider("case"); else if (node instanceof AST_Default) base54.consider("default"); else if (node instanceof AST_With) base54.consider("with"); else if (node instanceof AST_ObjectSetter) base54.consider("set" + node.key); else if (node instanceof AST_ObjectGetter) base54.consider("get" + node.key); else if (node instanceof AST_ObjectKeyVal) base54.consider(node.key); else if (node instanceof AST_New) base54.consider("new"); else if (node instanceof AST_This) base54.consider("this"); else if (node instanceof AST_Try) base54.consider("try"); else if (node instanceof AST_Catch) base54.consider("catch"); else if (node instanceof AST_Finally) base54.consider("finally"); else if (node instanceof AST_Symbol && node.unmangleable(options)) base54.consider(node.name); else if (node instanceof AST_Unary || node instanceof AST_Binary) base54.consider(node.operator); else if (node instanceof AST_Dot) base54.consider(node.property); - }); - this.walk(tw); - base54.sort(); - }); - var base54 = function() { - var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"; - var chars, frequency; - function reset() { - frequency = Object.create(null); - chars = string.split("").map(function(ch) { - return ch.charCodeAt(0); - }); - chars.forEach(function(ch) { - frequency[ch] = 0; + } + if (options.eval + && node instanceof AST_SymbolRef + && node.undeclared() + && node.name == "eval") { + AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); + } + if (options.unreferenced + && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) + && node.unreferenced()) { + AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { + type: node instanceof AST_Label ? "Label" : "Symbol", + name: node.name, + file: node.start.file, + line: node.start.line, + col: node.start.col }); } - base54.consider = function(str) { - for (var i = str.length; --i >= 0; ) { - var code = str.charCodeAt(i); - if (code in frequency) ++frequency[code]; - } - }; - base54.sort = function() { - chars = mergeSort(chars, function(a, b) { - if (is_digit(a) && !is_digit(b)) return 1; - if (is_digit(b) && !is_digit(a)) return -1; - return frequency[b] - frequency[a]; + if (options.func_arguments + && node instanceof AST_Lambda + && node.uses_arguments) { + AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { + name: node.name ? node.name.name : "anonymous", + file: node.start.file, + line: node.start.line, + col: node.start.col }); - }; - base54.reset = reset; - reset(); - base54.get = function() { - return chars; - }; - base54.freq = function() { - return frequency; - }; - function base54(num) { - var ret = "", base = 54; - do { - ret += String.fromCharCode(chars[num % base]); - num = Math.floor(num / base); - base = 64; - } while (num > 0); - return ret; } - return base54; - }(); - AST_Toplevel.DEFMETHOD("scope_warnings", function(options) { - options = defaults(options, { - undeclared: false, - unreferenced: true, - assign_to_global: true, - func_arguments: true, - nested_defuns: true, - eval: true - }); - var tw = new TreeWalker(function(node) { - if (options.undeclared && node instanceof AST_SymbolRef && node.undeclared()) { - AST_Node.warn("Undeclared symbol: {name} [{file}:{line},{col}]", { - name: node.name, - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - if (options.assign_to_global) { - var sym = null; - if (node instanceof AST_Assign && node.left instanceof AST_SymbolRef) sym = node.left; else if (node instanceof AST_ForIn && node.init instanceof AST_SymbolRef) sym = node.init; - if (sym && (sym.undeclared() || sym.global() && sym.scope !== sym.definition().scope)) { - AST_Node.warn("{msg}: {name} [{file}:{line},{col}]", { - msg: sym.undeclared() ? "Accidental global?" : "Assignment to global", - name: sym.name, - file: sym.start.file, - line: sym.start.line, - col: sym.start.col - }); - } - } - if (options.eval && node instanceof AST_SymbolRef && node.undeclared() && node.name == "eval") { - AST_Node.warn("Eval is used [{file}:{line},{col}]", node.start); - } - if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) && node.unreferenced()) { - AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { - type: node instanceof AST_Label ? "Label" : "Symbol", - name: node.name, - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - if (options.func_arguments && node instanceof AST_Lambda && node.uses_arguments) { - AST_Node.warn("arguments used in function {name} [{file}:{line},{col}]", { - name: node.name ? node.name.name : "anonymous", - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - if (options.nested_defuns && node instanceof AST_Defun && !(tw.parent() instanceof AST_Scope)) { - AST_Node.warn('Function {name} declared in nested statement "{type}" [{file}:{line},{col}]', { - name: node.name.name, - type: tw.parent().TYPE, - file: node.start.file, - line: node.start.line, - col: node.start.col - }); - } - }); - this.walk(tw); - }); - "use strict"; - function OutputStream(options) { - options = defaults(options, { - indent_start: 0, - indent_level: 4, - quote_keys: false, - space_colon: true, - ascii_only: false, - inline_script: false, - width: 80, - max_line_len: 32e3, - beautify: false, - source_map: null, - bracketize: false, - semicolons: true, - comments: false, - preserve_line: false, - screw_ie8: false - }, true); - var indentation = 0; - var current_col = 0; - var current_line = 1; - var current_pos = 0; - var OUTPUT = ""; - function to_ascii(str, identifier) { - return str.replace(/[\u0080-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); - if (code.length <= 2 && !identifier) { - while (code.length < 2) code = "0" + code; - return "\\x" + code; - } else { - while (code.length < 4) code = "0" + code; - return "\\u" + code; - } + if (options.nested_defuns + && node instanceof AST_Defun + && !(tw.parent() instanceof AST_Scope)) { + AST_Node.warn("Function {name} declared in nested statement \"{type}\" [{file}:{line},{col}]", { + name: node.name.name, + type: tw.parent().TYPE, + file: node.start.file, + line: node.start.line, + col: node.start.col }); } - function make_string(str) { - var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s) { - switch (s) { - case "\\": - return "\\\\"; + }); + this.walk(tw); +}); + +/*********************************************************************** - case "\b": - return "\\b"; + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- - case "\f": - return "\\f"; + Author: Mihai Bazon + + http://mihai.bazon.net/blog - case "\n": - return "\\n"; + Distributed under the BSD license: - case "\r": - return "\\r"; + Copyright 2012 (c) Mihai Bazon - case "\u2028": - return "\\u2028"; + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: - case "\u2029": - return "\\u2029"; + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. - case '"': - ++dq; - return '"'; + * 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. - case "'": - ++sq; - return "'"; + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. - case "\x00": - return "\\x00"; - } - return s; - }); - if (options.ascii_only) str = to_ascii(str); - if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; else return '"' + str.replace(/\x22/g, '\\"') + '"'; - } - function encode_string(str) { - var ret = make_string(str); - if (options.inline_script) ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); - return ret; - } - function make_name(name) { - name = name.toString(); - if (options.ascii_only) name = to_ascii(name, true); - return name; - } - function make_indent(back) { - return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); - } - var might_need_space = false; - var might_need_semicolon = false; - var last = null; - function last_char() { - return last.charAt(last.length - 1); - } - function maybe_newline() { - if (options.max_line_len && current_col > options.max_line_len) print("\n"); - } - var requireSemicolonChars = makePredicate("( [ + * / - , ."); - function print(str) { - str = String(str); - var ch = str.charAt(0); - if (might_need_semicolon) { - if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { - if (options.semicolons || requireSemicolonChars(ch)) { - OUTPUT += ";"; - current_col++; - current_pos++; - } else { - OUTPUT += "\n"; - current_pos++; - current_line++; - current_col = 0; - } - if (!options.beautify) might_need_space = false; - } - might_need_semicolon = false; - maybe_newline(); + ***********************************************************************/ + +"use strict"; + +function OutputStream(options) { + + options = defaults(options, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : true, + ascii_only : false, + inline_script : false, + width : 80, + max_line_len : 32000, + beautify : false, + source_map : null, + bracketize : false, + semicolons : true, + comments : false, + preserve_line : false, + screw_ie8 : false, + preamble : null, + }, true); + + var indentation = 0; + var current_col = 0; + var current_line = 1; + var current_pos = 0; + var OUTPUT = ""; + + function to_ascii(str, identifier) { + return str.replace(/[\u0080-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + if (code.length <= 2 && !identifier) { + while (code.length < 2) code = "0" + code; + return "\\x" + code; + } else { + while (code.length < 4) code = "0" + code; + return "\\u" + code; } - if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { - var target_line = stack[stack.length - 1].start.line; - while (current_line < target_line) { + }); + }; + + function make_string(str) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + case "\0": return "\\x00"; + } + return s; + }); + if (options.ascii_only) str = to_ascii(str); + if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'"; + else return '"' + str.replace(/\x22/g, '\\"') + '"'; + }; + + function encode_string(str) { + var ret = make_string(str); + if (options.inline_script) + ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1"); + return ret; + }; + + function make_name(name) { + name = name.toString(); + if (options.ascii_only) + name = to_ascii(name, true); + return name; + }; + + function make_indent(back) { + return repeat_string(" ", options.indent_start + indentation - back * options.indent_level); + }; + + /* -----[ beautification/minification ]----- */ + + var might_need_space = false; + var might_need_semicolon = false; + var last = null; + + function last_char() { + return last.charAt(last.length - 1); + }; + + function maybe_newline() { + if (options.max_line_len && current_col > options.max_line_len) + print("\n"); + }; + + var requireSemicolonChars = makePredicate("( [ + * / - , ."); + + function print(str) { + str = String(str); + var ch = str.charAt(0); + if (might_need_semicolon) { + if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) { + if (options.semicolons || requireSemicolonChars(ch)) { + OUTPUT += ";"; + current_col++; + current_pos++; + } else { OUTPUT += "\n"; current_pos++; current_line++; current_col = 0; - might_need_space = false; - } - } - if (might_need_space) { - var prev = last_char(); - if (is_identifier_char(prev) && (is_identifier_char(ch) || ch == "\\") || /^[\+\-\/]$/.test(ch) && ch == prev) { - OUTPUT += " "; - current_col++; - current_pos++; } - might_need_space = false; - } - var a = str.split(/\r?\n/), n = a.length - 1; - current_line += n; - if (n == 0) { - current_col += a[n].length; - } else { - current_col = a[n].length; + if (!options.beautify) + might_need_space = false; } - current_pos += str.length; - last = str; - OUTPUT += str; - } - var space = options.beautify ? function() { - print(" "); - } : function() { - might_need_space = true; - }; - var indent = options.beautify ? function(half) { - if (options.beautify) { - print(make_indent(half ? .5 : 0)); - } - } : noop; - var with_indent = options.beautify ? function(col, cont) { - if (col === true) col = next_indent(); - var save_indentation = indentation; - indentation = col; - var ret = cont(); - indentation = save_indentation; - return ret; - } : function(col, cont) { - return cont(); - }; - var newline = options.beautify ? function() { - print("\n"); - } : noop; - var semicolon = options.beautify ? function() { - print(";"); - } : function() { - might_need_semicolon = true; - }; - function force_semicolon() { might_need_semicolon = false; - print(";"); - } - function next_indent() { - return indentation + options.indent_level; - } - function with_block(cont) { - var ret; - print("{"); - newline(); - with_indent(next_indent(), function() { - ret = cont(); - }); - indent(); - print("}"); - return ret; - } - function with_parens(cont) { - print("("); - var ret = cont(); - print(")"); - return ret; + maybe_newline(); } - function with_square(cont) { - print("["); - var ret = cont(); - print("]"); - return ret; + + if (!options.beautify && options.preserve_line && stack[stack.length - 1]) { + var target_line = stack[stack.length - 1].start.line; + while (current_line < target_line) { + OUTPUT += "\n"; + current_pos++; + current_line++; + current_col = 0; + might_need_space = false; + } } - function comma() { - print(","); - space(); + + if (might_need_space) { + var prev = last_char(); + if ((is_identifier_char(prev) + && (is_identifier_char(ch) || ch == "\\")) + || (/^[\+\-\/]$/.test(ch) && ch == prev)) + { + OUTPUT += " "; + current_col++; + current_pos++; + } + might_need_space = false; } - function colon() { - print(":"); - if (options.space_colon) space(); + var a = str.split(/\r?\n/), n = a.length - 1; + current_line += n; + if (n == 0) { + current_col += a[n].length; + } else { + current_col = a[n].length; } - var add_mapping = options.source_map ? function(token, name) { - try { - if (token) options.source_map.add(token.file || "?", current_line, current_col, token.line, token.col, !name && token.type == "name" ? token.value : name); - } catch (ex) { - AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { - file: token.file, - line: token.line, - col: token.col, - cline: current_line, - ccol: current_col, - name: name || "" - }); - } - } : noop; - function get() { - return OUTPUT; + current_pos += str.length; + last = str; + OUTPUT += str; + }; + + var space = options.beautify ? function() { + print(" "); + } : function() { + might_need_space = true; + }; + + var indent = options.beautify ? function(half) { + if (options.beautify) { + print(make_indent(half ? 0.5 : 0)); } - var stack = []; - return { - get: get, - toString: get, - indent: indent, - indentation: function() { - return indentation; - }, - current_width: function() { - return current_col - indentation; - }, - should_break: function() { - return options.width && this.current_width() >= options.width; - }, - newline: newline, - print: print, - space: space, - comma: comma, - colon: colon, - last: function() { - return last; - }, - semicolon: semicolon, - force_semicolon: force_semicolon, - to_ascii: to_ascii, - print_name: function(name) { - print(make_name(name)); - }, - print_string: function(str) { - print(encode_string(str)); - }, - next_indent: next_indent, - with_indent: with_indent, - with_block: with_block, - with_parens: with_parens, - with_square: with_square, - add_mapping: add_mapping, - option: function(opt) { - return options[opt]; - }, - line: function() { - return current_line; - }, - col: function() { - return current_col; - }, - pos: function() { - return current_pos; - }, - push_node: function(node) { - stack.push(node); - }, - pop_node: function() { - return stack.pop(); - }, - stack: function() { - return stack; - }, - parent: function(n) { - return stack[stack.length - 2 - (n || 0)]; - } - }; + } : noop; + + var with_indent = options.beautify ? function(col, cont) { + if (col === true) col = next_indent(); + var save_indentation = indentation; + indentation = col; + var ret = cont(); + indentation = save_indentation; + return ret; + } : function(col, cont) { return cont() }; + + var newline = options.beautify ? function() { + print("\n"); + } : noop; + + var semicolon = options.beautify ? function() { + print(";"); + } : function() { + might_need_semicolon = true; + }; + + function force_semicolon() { + might_need_semicolon = false; + print(";"); + }; + + function next_indent() { + return indentation + options.indent_level; + }; + + function with_block(cont) { + var ret; + print("{"); + newline(); + with_indent(next_indent(), function(){ + ret = cont(); + }); + indent(); + print("}"); + return ret; + }; + + function with_parens(cont) { + print("("); + //XXX: still nice to have that for argument lists + //var ret = with_indent(current_col, cont); + var ret = cont(); + print(")"); + return ret; + }; + + function with_square(cont) { + print("["); + //var ret = with_indent(current_col, cont); + var ret = cont(); + print("]"); + return ret; + }; + + function comma() { + print(","); + space(); + }; + + function colon() { + print(":"); + if (options.space_colon) space(); + }; + + var add_mapping = options.source_map ? function(token, name) { + try { + if (token) options.source_map.add( + token.file || "?", + current_line, current_col, + token.line, token.col, + (!name && token.type == "name") ? token.value : name + ); + } catch(ex) { + AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { + file: token.file, + line: token.line, + col: token.col, + cline: current_line, + ccol: current_col, + name: name || "" + }) + } + } : noop; + + function get() { + return OUTPUT; + }; + + if (options.preamble) { + print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); } - (function() { - function DEFPRINT(nodetype, generator) { - nodetype.DEFMETHOD("_codegen", generator); + + var stack = []; + return { + get : get, + toString : get, + indent : indent, + indentation : function() { return indentation }, + current_width : function() { return current_col - indentation }, + should_break : function() { return options.width && this.current_width() >= options.width }, + newline : newline, + print : print, + space : space, + comma : comma, + colon : colon, + last : function() { return last }, + semicolon : semicolon, + force_semicolon : force_semicolon, + to_ascii : to_ascii, + print_name : function(name) { print(make_name(name)) }, + print_string : function(str) { print(encode_string(str)) }, + next_indent : next_indent, + with_indent : with_indent, + with_block : with_block, + with_parens : with_parens, + with_square : with_square, + add_mapping : add_mapping, + option : function(opt) { return options[opt] }, + line : function() { return current_line }, + col : function() { return current_col }, + pos : function() { return current_pos }, + push_node : function(node) { stack.push(node) }, + pop_node : function() { return stack.pop() }, + stack : function() { return stack }, + parent : function(n) { + return stack[stack.length - 2 - (n || 0)]; + } + }; + +}; + +/* -----[ code generators ]----- */ + +(function(){ + + /* -----[ utils ]----- */ + + function DEFPRINT(nodetype, generator) { + nodetype.DEFMETHOD("_codegen", generator); + }; + + AST_Node.DEFMETHOD("print", function(stream, force_parens){ + var self = this, generator = self._codegen; + function doit() { + self.add_comments(stream); + self.add_source_map(stream); + generator(self, stream); } - AST_Node.DEFMETHOD("print", function(stream, force_parens) { - var self = this, generator = self._codegen; - function doit() { - self.add_comments(stream); - self.add_source_map(stream); - generator(self, stream); - } - stream.push_node(self); - if (force_parens || self.needs_parens(stream)) { - stream.with_parens(doit); - } else { - doit(); - } - stream.pop_node(); - }); - AST_Node.DEFMETHOD("print_to_string", function(options) { - var s = OutputStream(options); - this.print(s); - return s.get(); - }); - AST_Node.DEFMETHOD("add_comments", function(output) { - var c = output.option("comments"), self = this; - if (c) { - var start = self.start; - if (start && !start._comments_dumped) { - start._comments_dumped = true; - var comments = start.comments_before; - if (self instanceof AST_Exit && self.value && self.value.start.comments_before.length > 0) { - comments = (comments || []).concat(self.value.start.comments_before); - self.value.start.comments_before = []; - } - if (c.test) { - comments = comments.filter(function(comment) { - return c.test(comment.value); - }); - } else if (typeof c == "function") { - comments = comments.filter(function(comment) { - return c(self, comment); - }); + stream.push_node(self); + if (force_parens || self.needs_parens(stream)) { + stream.with_parens(doit); + } else { + doit(); + } + stream.pop_node(); + }); + + AST_Node.DEFMETHOD("print_to_string", function(options){ + var s = OutputStream(options); + this.print(s); + return s.get(); + }); + + /* -----[ comments ]----- */ + + AST_Node.DEFMETHOD("add_comments", function(output){ + var c = output.option("comments"), self = this; + if (c) { + var start = self.start; + if (start && !start._comments_dumped) { + start._comments_dumped = true; + var comments = start.comments_before || []; + + // XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112 + // if this node is `return` or `throw`, we cannot allow comments before + // the returned or thrown value. + if (self instanceof AST_Exit && self.value + && self.value.start.comments_before + && self.value.start.comments_before.length > 0) { + comments = comments.concat(self.value.start.comments_before); + self.value.start.comments_before = []; + } + + if (c.test) { + comments = comments.filter(function(comment){ + return c.test(comment.value); + }); + } else if (typeof c == "function") { + comments = comments.filter(function(comment){ + return c(self, comment); + }); + } + comments.forEach(function(c){ + if (/comment[134]/.test(c.type)) { + output.print("//" + c.value + "\n"); + output.indent(); } - comments.forEach(function(c) { - if (c.type == "comment1") { - output.print("//" + c.value + "\n"); + else if (c.type == "comment2") { + output.print("/*" + c.value + "*/"); + if (start.nlb) { + output.print("\n"); output.indent(); - } else if (c.type == "comment2") { - output.print("/*" + c.value + "*/"); - if (start.nlb) { - output.print("\n"); - output.indent(); - } else { - output.space(); - } + } else { + output.space(); } - }); - } + } + }); } - }); - function PARENS(nodetype, func) { - nodetype.DEFMETHOD("needs_parens", func); } - PARENS(AST_Node, function() { - return false; - }); - PARENS(AST_Function, function(output) { - return first_in_statement(output); - }); - PARENS(AST_Object, function(output) { - return first_in_statement(output); - }); - PARENS(AST_Unary, function(output) { - var p = output.parent(); - return p instanceof AST_PropAccess && p.expression === this; - }); - PARENS(AST_Seq, function(output) { - var p = output.parent(); - return p instanceof AST_Call || p instanceof AST_Unary || p instanceof AST_Binary || p instanceof AST_VarDef || p instanceof AST_Dot || p instanceof AST_Array || p instanceof AST_ObjectProperty || p instanceof AST_Conditional; - }); - PARENS(AST_Binary, function(output) { - var p = output.parent(); - if (p instanceof AST_Call && p.expression === this) return true; - if (p instanceof AST_Unary) return true; - if (p instanceof AST_PropAccess && p.expression === this) return true; - if (p instanceof AST_Binary) { - var po = p.operator, pp = PRECEDENCE[po]; - var so = this.operator, sp = PRECEDENCE[so]; - if (pp > sp || pp == sp && this === p.right && !(so == po && (so == "*" || so == "&&" || so == "||"))) { - return true; - } - } - }); - PARENS(AST_PropAccess, function(output) { - var p = output.parent(); - if (p instanceof AST_New && p.expression === this) { - try { - this.walk(new TreeWalker(function(node) { - if (node instanceof AST_Call) throw p; - })); - } catch (ex) { - if (ex !== p) throw ex; - return true; - } + }); + + /* -----[ PARENTHESES ]----- */ + + function PARENS(nodetype, func) { + nodetype.DEFMETHOD("needs_parens", func); + }; + + PARENS(AST_Node, function(){ + return false; + }); + + // a function expression needs parens around it when it's provably + // the first token to appear in a statement. + PARENS(AST_Function, function(output){ + return first_in_statement(output); + }); + + // same goes for an object literal, because otherwise it would be + // interpreted as a block of code. + PARENS(AST_Object, function(output){ + return first_in_statement(output); + }); + + PARENS(AST_Unary, function(output){ + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this; + }); + + PARENS(AST_Seq, function(output){ + var p = output.parent(); + return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) + || p instanceof AST_Unary // !(foo, bar, baz) + || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 + || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 + || p instanceof AST_Dot // (1, {foo:2}).foo ==> 2 + || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] + || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 + || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) + * ==> 20 (side effect, set a := 10 and b := 20) */ + ; + }); + + PARENS(AST_Binary, function(output){ + var p = output.parent(); + // (foo && bar)() + if (p instanceof AST_Call && p.expression === this) + return true; + // typeof (foo && bar) + if (p instanceof AST_Unary) + return true; + // (foo && bar)["prop"], (foo && bar).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + // this deals with precedence: 3 * (2 + 1) + if (p instanceof AST_Binary) { + var po = p.operator, pp = PRECEDENCE[po]; + var so = this.operator, sp = PRECEDENCE[so]; + if (pp > sp + || (pp == sp + && this === p.right)) { + return true; } - }); - PARENS(AST_Call, function(output) { - var p = output.parent(); - return p instanceof AST_New && p.expression === this; - }); - PARENS(AST_New, function(output) { - var p = output.parent(); - if (no_constructor_parens(this, output) && (p instanceof AST_PropAccess || p instanceof AST_Call && p.expression === this)) return true; - }); - PARENS(AST_Number, function(output) { - var p = output.parent(); - if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) return true; - }); - PARENS(AST_NaN, function(output) { - var p = output.parent(); - if (p instanceof AST_PropAccess && p.expression === this) return true; - }); - function assign_and_conditional_paren_rules(output) { - var p = output.parent(); - if (p instanceof AST_Unary) return true; - if (p instanceof AST_Binary && !(p instanceof AST_Assign)) return true; - if (p instanceof AST_Call && p.expression === this) return true; - if (p instanceof AST_Conditional && p.condition === this) return true; - if (p instanceof AST_PropAccess && p.expression === this) return true; - } - PARENS(AST_Assign, assign_and_conditional_paren_rules); - PARENS(AST_Conditional, assign_and_conditional_paren_rules); - DEFPRINT(AST_Directive, function(self, output) { - output.print_string(self.value); - output.semicolon(); - }); - DEFPRINT(AST_Debugger, function(self, output) { - output.print("debugger"); - output.semicolon(); - }); - function display_body(body, is_toplevel, output) { - var last = body.length - 1; - body.forEach(function(stmt, i) { - if (!(stmt instanceof AST_EmptyStatement)) { - output.indent(); - stmt.print(output); - if (!(i == last && is_toplevel)) { - output.newline(); - if (is_toplevel) output.newline(); - } - } - }); } - AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) { - force_statement(this.body, output); - }); - DEFPRINT(AST_Statement, function(self, output) { - self.body.print(output); - output.semicolon(); - }); - DEFPRINT(AST_Toplevel, function(self, output) { - display_body(self.body, true, output); - output.print(""); - }); - DEFPRINT(AST_LabeledStatement, function(self, output) { - self.label.print(output); - output.colon(); - self.body.print(output); - }); - DEFPRINT(AST_SimpleStatement, function(self, output) { - self.body.print(output); - output.semicolon(); - }); - function print_bracketed(body, output) { - if (body.length > 0) output.with_block(function() { - display_body(body, false, output); - }); else output.print("{}"); + }); + + PARENS(AST_PropAccess, function(output){ + var p = output.parent(); + if (p instanceof AST_New && p.expression === this) { + // i.e. new (foo.bar().baz) + // + // if there's one call into this subtree, then we need + // parens around it too, otherwise the call will be + // interpreted as passing the arguments to the upper New + // expression. + try { + this.walk(new TreeWalker(function(node){ + if (node instanceof AST_Call) throw p; + })); + } catch(ex) { + if (ex !== p) throw ex; + return true; + } } - DEFPRINT(AST_BlockStatement, function(self, output) { - print_bracketed(self.body, output); - }); - DEFPRINT(AST_EmptyStatement, function(self, output) { - output.semicolon(); - }); - DEFPRINT(AST_Do, function(self, output) { - output.print("do"); - output.space(); - self._do_print_body(output); - output.space(); - output.print("while"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.semicolon(); - }); - DEFPRINT(AST_While, function(self, output) { - output.print("while"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_For, function(self, output) { - output.print("for"); - output.space(); - output.with_parens(function() { - if (self.init) { - if (self.init instanceof AST_Definitions) { - self.init.print(output); - } else { - parenthesize_for_noin(self.init, output, true); - } - output.print(";"); - output.space(); - } else { - output.print(";"); - } - if (self.condition) { - self.condition.print(output); - output.print(";"); - output.space(); - } else { - output.print(";"); - } - if (self.step) { - self.step.print(output); + }); + + PARENS(AST_Call, function(output){ + var p = output.parent(), p1; + if (p instanceof AST_New && p.expression === this) + return true; + + // workaround for Safari bug. + // https://bugs.webkit.org/show_bug.cgi?id=123506 + return this.expression instanceof AST_Function + && p instanceof AST_PropAccess + && p.expression === this + && (p1 = output.parent(1)) instanceof AST_Assign + && p1.left === p; + }); + + PARENS(AST_New, function(output){ + var p = output.parent(); + if (no_constructor_parens(this, output) + && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]() + || p instanceof AST_Call && p.expression === this)) // (new foo)(bar) + return true; + }); + + PARENS(AST_Number, function(output){ + var p = output.parent(); + if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + PARENS(AST_NaN, function(output){ + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + function assign_and_conditional_paren_rules(output) { + var p = output.parent(); + // !(a = false) → true + if (p instanceof AST_Unary) + return true; + // 1 + (a = 2) + 3 → 6, side effect setting a = 2 + if (p instanceof AST_Binary && !(p instanceof AST_Assign)) + return true; + // (a = func)() —or— new (a = Object)() + if (p instanceof AST_Call && p.expression === this) + return true; + // (a = foo) ? bar : baz + if (p instanceof AST_Conditional && p.condition === this) + return true; + // (a = foo)["prop"] —or— (a = foo).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }; + + PARENS(AST_Assign, assign_and_conditional_paren_rules); + PARENS(AST_Conditional, assign_and_conditional_paren_rules); + + /* -----[ PRINTERS ]----- */ + + DEFPRINT(AST_Directive, function(self, output){ + output.print_string(self.value); + output.semicolon(); + }); + DEFPRINT(AST_Debugger, function(self, output){ + output.print("debugger"); + output.semicolon(); + }); + + /* -----[ statements ]----- */ + + function display_body(body, is_toplevel, output) { + var last = body.length - 1; + body.forEach(function(stmt, i){ + if (!(stmt instanceof AST_EmptyStatement)) { + output.indent(); + stmt.print(output); + if (!(i == last && is_toplevel)) { + output.newline(); + if (is_toplevel) output.newline(); } - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_ForIn, function(self, output) { - output.print("for"); - output.space(); - output.with_parens(function() { - self.init.print(output); - output.space(); - output.print("in"); - output.space(); - self.object.print(output); - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_With, function(self, output) { - output.print("with"); - output.space(); - output.with_parens(function() { - self.expression.print(output); - }); - output.space(); - self._do_print_body(output); - }); - AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) { - var self = this; - if (!nokeyword) { - output.print("function"); - } - if (self.name) { - output.space(); - self.name.print(output); } - output.with_parens(function() { - self.argnames.forEach(function(arg, i) { - if (i) output.comma(); - arg.print(output); - }); - }); - output.space(); - print_bracketed(self.body, output); }); - DEFPRINT(AST_Lambda, function(self, output) { - self._do_print(output); - }); - AST_Exit.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - if (this.value) { - output.space(); - this.value.print(output); - } - output.semicolon(); + }; + + AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){ + force_statement(this.body, output); + }); + + DEFPRINT(AST_Statement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + DEFPRINT(AST_Toplevel, function(self, output){ + display_body(self.body, true, output); + output.print(""); + }); + DEFPRINT(AST_LabeledStatement, function(self, output){ + self.label.print(output); + output.colon(); + self.body.print(output); + }); + DEFPRINT(AST_SimpleStatement, function(self, output){ + self.body.print(output); + output.semicolon(); + }); + function print_bracketed(body, output) { + if (body.length > 0) output.with_block(function(){ + display_body(body, false, output); }); - DEFPRINT(AST_Return, function(self, output) { - self._do_print(output, "return"); + else output.print("{}"); + }; + DEFPRINT(AST_BlockStatement, function(self, output){ + print_bracketed(self.body, output); + }); + DEFPRINT(AST_EmptyStatement, function(self, output){ + output.semicolon(); + }); + DEFPRINT(AST_Do, function(self, output){ + output.print("do"); + output.space(); + self._do_print_body(output); + output.space(); + output.print("while"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); }); - DEFPRINT(AST_Throw, function(self, output) { - self._do_print(output, "throw"); + output.semicolon(); + }); + DEFPRINT(AST_While, function(self, output){ + output.print("while"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); }); - AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - if (this.label) { + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_For, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + if (self.init) { + if (self.init instanceof AST_Definitions) { + self.init.print(output); + } else { + parenthesize_for_noin(self.init, output, true); + } + output.print(";"); output.space(); - this.label.print(output); - } - output.semicolon(); - }); - DEFPRINT(AST_Break, function(self, output) { - self._do_print(output, "break"); - }); - DEFPRINT(AST_Continue, function(self, output) { - self._do_print(output, "continue"); - }); - function make_then(self, output) { - if (output.option("bracketize")) { - make_block(self.body, output); - return; - } - if (!self.body) return output.force_semicolon(); - if (self.body instanceof AST_Do && !output.option("screw_ie8")) { - make_block(self.body, output); - return; - } - var b = self.body; - while (true) { - if (b instanceof AST_If) { - if (!b.alternative) { - make_block(self.body, output); - return; - } - b = b.alternative; - } else if (b instanceof AST_StatementWithBody) { - b = b.body; - } else break; + } else { + output.print(";"); } - force_statement(self.body, output); - } - DEFPRINT(AST_If, function(self, output) { - output.print("if"); - output.space(); - output.with_parens(function() { + if (self.condition) { self.condition.print(output); - }); - output.space(); - if (self.alternative) { - make_then(self, output); + output.print(";"); output.space(); - output.print("else"); - output.space(); - force_statement(self.alternative, output); } else { - self._do_print_body(output); - } - }); - DEFPRINT(AST_Switch, function(self, output) { - output.print("switch"); - output.space(); - output.with_parens(function() { - self.expression.print(output); - }); - output.space(); - if (self.body.length > 0) output.with_block(function() { - self.body.forEach(function(stmt, i) { - if (i) output.newline(); - output.indent(true); - stmt.print(output); - }); - }); else output.print("{}"); - }); - AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) { - if (this.body.length > 0) { - output.newline(); - this.body.forEach(function(stmt) { - output.indent(); - stmt.print(output); - output.newline(); - }); - } - }); - DEFPRINT(AST_Default, function(self, output) { - output.print("default:"); - self._do_print_body(output); - }); - DEFPRINT(AST_Case, function(self, output) { - output.print("case"); - output.space(); - self.expression.print(output); - output.print(":"); - self._do_print_body(output); - }); - DEFPRINT(AST_Try, function(self, output) { - output.print("try"); - output.space(); - print_bracketed(self.body, output); - if (self.bcatch) { - output.space(); - self.bcatch.print(output); + output.print(";"); } - if (self.bfinally) { - output.space(); - self.bfinally.print(output); + if (self.step) { + self.step.print(output); } }); - DEFPRINT(AST_Catch, function(self, output) { - output.print("catch"); - output.space(); - output.with_parens(function() { - self.argname.print(output); - }); - output.space(); - print_bracketed(self.body, output); - }); - DEFPRINT(AST_Finally, function(self, output) { - output.print("finally"); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_ForIn, function(self, output){ + output.print("for"); + output.space(); + output.with_parens(function(){ + self.init.print(output); output.space(); - print_bracketed(self.body, output); - }); - AST_Definitions.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); + output.print("in"); output.space(); - this.definitions.forEach(function(def, i) { - if (i) output.comma(); - def.print(output); - }); - var p = output.parent(); - var in_for = p instanceof AST_For || p instanceof AST_ForIn; - var avoid_semicolon = in_for && p.init === this; - if (!avoid_semicolon) output.semicolon(); + self.object.print(output); }); - DEFPRINT(AST_Var, function(self, output) { - self._do_print(output, "var"); - }); - DEFPRINT(AST_Const, function(self, output) { - self._do_print(output, "const"); - }); - function parenthesize_for_noin(node, output, noin) { - if (!noin) node.print(output); else try { - node.walk(new TreeWalker(function(node) { - if (node instanceof AST_Binary && node.operator == "in") throw output; - })); - node.print(output); - } catch (ex) { - if (ex !== output) throw ex; - node.print(output, true); - } - } - DEFPRINT(AST_VarDef, function(self, output) { - self.name.print(output); - if (self.value) { - output.space(); - output.print("="); - output.space(); - var p = output.parent(1); - var noin = p instanceof AST_For || p instanceof AST_ForIn; - parenthesize_for_noin(self.value, output, noin); - } - }); - DEFPRINT(AST_Call, function(self, output) { + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_With, function(self, output){ + output.print("with"); + output.space(); + output.with_parens(function(){ self.expression.print(output); - if (self instanceof AST_New && no_constructor_parens(self, output)) return; - output.with_parens(function() { - self.args.forEach(function(expr, i) { - if (i) output.comma(); - expr.print(output); - }); + }); + output.space(); + self._do_print_body(output); + }); + + /* -----[ functions ]----- */ + AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword){ + var self = this; + if (!nokeyword) { + output.print("function"); + } + if (self.name) { + output.space(); + self.name.print(output); + } + output.with_parens(function(){ + self.argnames.forEach(function(arg, i){ + if (i) output.comma(); + arg.print(output); }); }); - DEFPRINT(AST_New, function(self, output) { - output.print("new"); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Lambda, function(self, output){ + self._do_print(output); + }); + + /* -----[ exits ]----- */ + AST_Exit.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (this.value) { output.space(); - AST_Call.prototype._codegen(self, output); - }); - AST_Seq.DEFMETHOD("_do_print", function(output) { - this.car.print(output); - if (this.cdr) { - output.comma(); - if (output.should_break()) { - output.newline(); - output.indent(); + this.value.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Return, function(self, output){ + self._do_print(output, "return"); + }); + DEFPRINT(AST_Throw, function(self, output){ + self._do_print(output, "throw"); + }); + + /* -----[ loop control ]----- */ + AST_LoopControl.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + if (this.label) { + output.space(); + this.label.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Break, function(self, output){ + self._do_print(output, "break"); + }); + DEFPRINT(AST_Continue, function(self, output){ + self._do_print(output, "continue"); + }); + + /* -----[ if ]----- */ + function make_then(self, output) { + if (output.option("bracketize")) { + make_block(self.body, output); + return; + } + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + if (!self.body) + return output.force_semicolon(); + if (self.body instanceof AST_Do + && !output.option("screw_ie8")) { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 IE + // croaks with "syntax error" on code like this: if (foo) + // do ... while(cond); else ... we need block brackets + // around do/while + make_block(self.body, output); + return; + } + var b = self.body; + while (true) { + if (b instanceof AST_If) { + if (!b.alternative) { + make_block(self.body, output); + return; } - this.cdr.print(output); + b = b.alternative; } - }); - DEFPRINT(AST_Seq, function(self, output) { - self._do_print(output); - }); - DEFPRINT(AST_Dot, function(self, output) { - var expr = self.expression; - expr.print(output); - if (expr instanceof AST_Number && expr.getValue() >= 0) { - if (!/[xa-f.]/i.test(output.last())) { - output.print("."); - } + else if (b instanceof AST_StatementWithBody) { + b = b.body; } - output.print("."); - output.add_mapping(self.end); - output.print_name(self.property); - }); - DEFPRINT(AST_Sub, function(self, output) { - self.expression.print(output); - output.print("["); - self.property.print(output); - output.print("]"); + else break; + } + force_statement(self.body, output); + }; + DEFPRINT(AST_If, function(self, output){ + output.print("if"); + output.space(); + output.with_parens(function(){ + self.condition.print(output); }); - DEFPRINT(AST_UnaryPrefix, function(self, output) { - var op = self.operator; - output.print(op); - if (/^[a-z]/i.test(op)) output.space(); + output.space(); + if (self.alternative) { + make_then(self, output); + output.space(); + output.print("else"); + output.space(); + force_statement(self.alternative, output); + } else { + self._do_print_body(output); + } + }); + + /* -----[ switch ]----- */ + DEFPRINT(AST_Switch, function(self, output){ + output.print("switch"); + output.space(); + output.with_parens(function(){ self.expression.print(output); }); - DEFPRINT(AST_UnaryPostfix, function(self, output) { - self.expression.print(output); - output.print(self.operator); + output.space(); + if (self.body.length > 0) output.with_block(function(){ + self.body.forEach(function(stmt, i){ + if (i) output.newline(); + output.indent(true); + stmt.print(output); + }); }); - DEFPRINT(AST_Binary, function(self, output) { - self.left.print(output); + else output.print("{}"); + }); + AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output){ + if (this.body.length > 0) { + output.newline(); + this.body.forEach(function(stmt){ + output.indent(); + stmt.print(output); + output.newline(); + }); + } + }); + DEFPRINT(AST_Default, function(self, output){ + output.print("default:"); + self._do_print_body(output); + }); + DEFPRINT(AST_Case, function(self, output){ + output.print("case"); + output.space(); + self.expression.print(output); + output.print(":"); + self._do_print_body(output); + }); + + /* -----[ exceptions ]----- */ + DEFPRINT(AST_Try, function(self, output){ + output.print("try"); + output.space(); + print_bracketed(self.body, output); + if (self.bcatch) { output.space(); - output.print(self.operator); + self.bcatch.print(output); + } + if (self.bfinally) { output.space(); - self.right.print(output); + self.bfinally.print(output); + } + }); + DEFPRINT(AST_Catch, function(self, output){ + output.print("catch"); + output.space(); + output.with_parens(function(){ + self.argname.print(output); }); - DEFPRINT(AST_Conditional, function(self, output) { - self.condition.print(output); - output.space(); - output.print("?"); + output.space(); + print_bracketed(self.body, output); + }); + DEFPRINT(AST_Finally, function(self, output){ + output.print("finally"); + output.space(); + print_bracketed(self.body, output); + }); + + /* -----[ var/const ]----- */ + AST_Definitions.DEFMETHOD("_do_print", function(output, kind){ + output.print(kind); + output.space(); + this.definitions.forEach(function(def, i){ + if (i) output.comma(); + def.print(output); + }); + var p = output.parent(); + var in_for = p instanceof AST_For || p instanceof AST_ForIn; + var avoid_semicolon = in_for && p.init === this; + if (!avoid_semicolon) + output.semicolon(); + }); + DEFPRINT(AST_Var, function(self, output){ + self._do_print(output, "var"); + }); + DEFPRINT(AST_Const, function(self, output){ + self._do_print(output, "const"); + }); + + function parenthesize_for_noin(node, output, noin) { + if (!noin) node.print(output); + else try { + // need to take some precautions here: + // https://github.com/mishoo/UglifyJS2/issues/60 + node.walk(new TreeWalker(function(node){ + if (node instanceof AST_Binary && node.operator == "in") + throw output; + })); + node.print(output); + } catch(ex) { + if (ex !== output) throw ex; + node.print(output, true); + } + }; + + DEFPRINT(AST_VarDef, function(self, output){ + self.name.print(output); + if (self.value) { output.space(); - self.consequent.print(output); + output.print("="); output.space(); - output.colon(); - self.alternative.print(output); - }); - DEFPRINT(AST_Array, function(self, output) { - output.with_square(function() { - var a = self.elements, len = a.length; - if (len > 0) output.space(); - a.forEach(function(exp, i) { - if (i) output.comma(); - exp.print(output); - if (i === len - 1 && exp instanceof AST_Hole) output.comma(); - }); - if (len > 0) output.space(); + var p = output.parent(1); + var noin = p instanceof AST_For || p instanceof AST_ForIn; + parenthesize_for_noin(self.value, output, noin); + } + }); + + /* -----[ other expressions ]----- */ + DEFPRINT(AST_Call, function(self, output){ + self.expression.print(output); + if (self instanceof AST_New && no_constructor_parens(self, output)) + return; + output.with_parens(function(){ + self.args.forEach(function(expr, i){ + if (i) output.comma(); + expr.print(output); }); }); - DEFPRINT(AST_Object, function(self, output) { - if (self.properties.length > 0) output.with_block(function() { - self.properties.forEach(function(prop, i) { - if (i) { - output.print(","); - output.newline(); - } - output.indent(); - prop.print(output); - }); + }); + DEFPRINT(AST_New, function(self, output){ + output.print("new"); + output.space(); + AST_Call.prototype._codegen(self, output); + }); + + AST_Seq.DEFMETHOD("_do_print", function(output){ + this.car.print(output); + if (this.cdr) { + output.comma(); + if (output.should_break()) { output.newline(); - }); else output.print("{}"); - }); - DEFPRINT(AST_ObjectKeyVal, function(self, output) { - var key = self.key; - if (output.option("quote_keys")) { - output.print_string(key + ""); - } else if ((typeof key == "number" || !output.option("beautify") && +key + "" == key) && parseFloat(key) >= 0) { - output.print(make_num(key)); - } else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) { - output.print_name(key); - } else { - output.print_string(key); + output.indent(); } - output.colon(); - self.value.print(output); - }); - DEFPRINT(AST_ObjectSetter, function(self, output) { - output.print("set"); - self.value._do_print(output, true); - }); - DEFPRINT(AST_ObjectGetter, function(self, output) { - output.print("get"); - self.value._do_print(output, true); - }); - DEFPRINT(AST_Symbol, function(self, output) { - var def = self.definition(); - output.print_name(def ? def.mangled_name || def.name : self.name); - }); - DEFPRINT(AST_Undefined, function(self, output) { - output.print("void 0"); - }); - DEFPRINT(AST_Hole, noop); - DEFPRINT(AST_Infinity, function(self, output) { - output.print("1/0"); - }); - DEFPRINT(AST_NaN, function(self, output) { - output.print("0/0"); - }); - DEFPRINT(AST_This, function(self, output) { - output.print("this"); - }); - DEFPRINT(AST_Constant, function(self, output) { - output.print(self.getValue()); - }); - DEFPRINT(AST_String, function(self, output) { - output.print_string(self.getValue()); - }); - DEFPRINT(AST_Number, function(self, output) { - output.print(make_num(self.getValue())); - }); - DEFPRINT(AST_RegExp, function(self, output) { - var str = self.getValue().toString(); - if (output.option("ascii_only")) str = output.to_ascii(str); - output.print(str); - var p = output.parent(); - if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self) output.print(" "); + this.cdr.print(output); + } + }); + DEFPRINT(AST_Seq, function(self, output){ + self._do_print(output); + // var p = output.parent(); + // if (p instanceof AST_Statement) { + // output.with_indent(output.next_indent(), function(){ + // self._do_print(output); + // }); + // } else { + // self._do_print(output); + // } + }); + DEFPRINT(AST_Dot, function(self, output){ + var expr = self.expression; + expr.print(output); + if (expr instanceof AST_Number && expr.getValue() >= 0) { + if (!/[xa-f.]/i.test(output.last())) { + output.print("."); + } + } + output.print("."); + // the name after dot would be mapped about here. + output.add_mapping(self.end); + output.print_name(self.property); + }); + DEFPRINT(AST_Sub, function(self, output){ + self.expression.print(output); + output.print("["); + self.property.print(output); + output.print("]"); + }); + DEFPRINT(AST_UnaryPrefix, function(self, output){ + var op = self.operator; + output.print(op); + if (/^[a-z]/i.test(op)) + output.space(); + self.expression.print(output); + }); + DEFPRINT(AST_UnaryPostfix, function(self, output){ + self.expression.print(output); + output.print(self.operator); + }); + DEFPRINT(AST_Binary, function(self, output){ + self.left.print(output); + output.space(); + output.print(self.operator); + if (self.operator == "<" + && self.right instanceof AST_UnaryPrefix + && self.right.operator == "!" + && self.right.expression instanceof AST_UnaryPrefix + && self.right.expression.operator == "--") { + // space is mandatory to avoid outputting ' is a single-line comment + index += 3; + skipSingleLineComment(3); + } else { + break; + } + } else if (ch === 0x3C) { // U+003C is '<' + if (source.slice(index + 1, index + 4) === '!--') { + ++index; // `<` + ++index; // `!` + ++index; // `-` + ++index; // `-` + skipSingleLineComment(4); + } else { + break; + } } else { break; } @@ -429,291 +531,316 @@ parseStatement: true, parseSourceElement: true */ return String.fromCharCode(code); } - function scanIdentifier() { - var ch, start, id, restore; + function getEscapedIdentifier() { + var ch, id; - ch = source[index]; - if (!isIdentifierStart(ch)) { - return; - } + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); - start = index; - if (ch === '\\') { - ++index; - if (source[index] !== 'u') { - return; + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + if (source.charCodeAt(index) !== 0x75) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } ++index; - restore = index; ch = scanHexEscape('u'); - if (ch) { - if (ch === '\\' || !isIdentifierStart(ch)) { - return; - } - id = ch; - } else { - index = restore; - id = 'u'; + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - } else { - id = source[index++]; + id = ch; } while (index < length) { - ch = source[index]; + ch = source.charCodeAt(index); if (!isIdentifierPart(ch)) { break; } - if (ch === '\\') { - ++index; - if (source[index] !== 'u') { - return; + ++index; + id += String.fromCharCode(ch); + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 0x75) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } ++index; - restore = index; ch = scanHexEscape('u'); - if (ch) { - if (ch === '\\' || !isIdentifierPart(ch)) { - return; - } - id += ch; - } else { - index = restore; - id += 'u'; + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - } else { - id += source[index++]; + id += ch; } } - // There is no keyword or literal with only one character. - // Thus, it must be an identifier. - if (id.length === 1) { - return { - type: Token.Identifier, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + return id; + } - if (isKeyword(id)) { - return { - type: Token.Keyword, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 0x5C) { + // Blackslash (U+005C) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } } - // 7.8.1 Null Literals + return source.slice(start, index); + } - if (id === 'null') { - return { - type: Token.NullLiteral, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + function scanIdentifier() { + var start, id, type; - // 7.8.2 Boolean Literals + start = index; - if (id === 'true' || id === 'false') { - return { - type: Token.BooleanLiteral, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + // Backslash (U+005C) starts an escaped character. + id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; } return { - type: Token.Identifier, + type: type, value: id, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } + // 7.7 Punctuators function scanPunctuator() { var start = index, + code = source.charCodeAt(index), + code2, ch1 = source[index], ch2, ch3, ch4; - // Check for most common single-character punctuators. + switch (code) { - if (ch1 === ';' || ch1 === '{' || ch1 === '}') { + // Check for most common single-character punctuators. + case 0x2E: // . dot + case 0x28: // ( open bracket + case 0x29: // ) close bracket + case 0x3B: // ; semicolon + case 0x2C: // , comma + case 0x7B: // { open curly brace + case 0x7D: // } close curly brace + case 0x5B: // [ + case 0x5D: // ] + case 0x3A: // : + case 0x3F: // ? + case 0x7E: // ~ ++index; + if (extra.tokenize) { + if (code === 0x28) { + extra.openParenToken = extra.tokens.length; + } else if (code === 0x7B) { + extra.openCurlyToken = extra.tokens.length; + } + } return { type: Token.Punctuator, - value: ch1, + value: String.fromCharCode(code), lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; - } - if (ch1 === ',' || ch1 === '(' || ch1 === ')') { - ++index; - return { - type: Token.Punctuator, - value: ch1, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + default: + code2 = source.charCodeAt(index + 1); + + // '=' (U+003D) marks an assignment or comparison operator. + if (code2 === 0x3D) { + switch (code) { + case 0x2B: // + + case 0x2D: // - + case 0x2F: // / + case 0x3C: // < + case 0x3E: // > + case 0x5E: // ^ + case 0x7C: // | + case 0x25: // % + case 0x26: // & + case 0x2A: // * + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + + case 0x21: // ! + case 0x3D: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 0x3D) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + } } - // Dot (.) can also start a floating-point number, hence the need - // to check the next character. + // 4-character punctuator: >>>= - ch2 = source[index + 1]; - if (ch1 === '.' && !isDecimalDigit(ch2)) { + ch4 = source.substr(index, 4); + + if (ch4 === '>>>=') { + index += 4; return { type: Token.Punctuator, - value: source[index++], + value: ch4, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - // Peek more characters. - - ch3 = source[index + 2]; - ch4 = source[index + 3]; - - // 4-character punctuator: >>>= - - if (ch1 === '>' && ch2 === '>' && ch3 === '>') { - if (ch4 === '=') { - index += 4; - return { - type: Token.Punctuator, - value: '>>>=', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } - } - // 3-character punctuators: === !== >>> <<= >>= - if (ch1 === '=' && ch2 === '=' && ch3 === '=') { + ch3 = ch4.substr(0, 3); + + if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { index += 3; return { type: Token.Punctuator, - value: '===', + value: ch3, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - if (ch1 === '!' && ch2 === '=' && ch3 === '=') { - index += 3; + // Other 2-character punctuators: ++ -- << >> && || + ch2 = ch3.substr(0, 2); + + if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { + index += 2; return { type: Token.Punctuator, - value: '!==', + value: ch2, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - if (ch1 === '>' && ch2 === '>' && ch3 === '>') { - index += 3; + // 1-character punctuators: < > = ! + - * % & | ^ / + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; return { type: Token.Punctuator, - value: '>>>', + value: ch1, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - if (ch1 === '<' && ch2 === '<' && ch3 === '=') { - index += 3; - return { - type: Token.Punctuator, - value: '<<=', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } - if (ch1 === '>' && ch2 === '>' && ch3 === '=') { - index += 3; - return { - type: Token.Punctuator, - value: '>>=', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + // 7.8.3 Numeric Literals - // 2-character punctuators: <= >= == != ++ -- << >> && || - // += -= *= %= &= |= ^= /= + function scanHexLiteral(start) { + var number = ''; - if (ch2 === '=') { - if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { - index += 2; - return { - type: Token.Punctuator, - value: ch1 + ch2, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + while (index < length) { + if (!isHexDigit(source[index])) { + break; } + number += source[index++]; } - if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { - if ('+-<>&|'.indexOf(ch2) >= 0) { - index += 2; - return { - type: Token.Punctuator, - value: ch1 + ch2, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + if (number.length === 0) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - // The remaining 1-character punctuators. - - if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) { - return { - type: Token.Punctuator, - value: source[index++], - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } + + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; } - // 7.8.3 Numeric Literals + function scanOctalLiteral(start) { + var number = '0' + source[index++]; + while (index < length) { + if (!isOctalDigit(source[index])) { + break; + } + number += source[index++]; + } + + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: true, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } function scanNumericLiteral() { var number, start, ch; ch = source[index]; - assert(isDecimalDigit(ch) || (ch === '.'), + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), 'Numeric literal must start with a decimal digit or a decimal point'); start = index; @@ -726,83 +853,31 @@ parseStatement: true, parseSourceElement: true */ // Octal number starts with '0'. if (number === '0') { if (ch === 'x' || ch === 'X') { - number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isHexDigit(ch)) { - break; - } - number += source[index++]; - } - - if (number.length <= 2) { - // only 0x - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch)) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - return { - type: Token.NumericLiteral, - value: parseInt(number, 16), - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } else if (isOctalDigit(ch)) { - number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isOctalDigit(ch)) { - break; - } - number += source[index++]; - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch) || isDecimalDigit(ch)) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - return { - type: Token.NumericLiteral, - value: parseInt(number, 8), - octal: true, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + ++index; + return scanHexLiteral(start); + } + if (isOctalDigit(ch)) { + return scanOctalLiteral(start); } // decimal number starts with '0' such as '09' is illegal. - if (isDecimalDigit(ch)) { + if (ch && isDecimalDigit(ch.charCodeAt(0))) { throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } } - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } + while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } + ch = source[index]; } if (ch === '.') { number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } + while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } + ch = source[index]; } if (ch === 'e' || ch === 'E') { @@ -812,31 +887,17 @@ parseStatement: true, parseSourceElement: true */ if (ch === '+' || ch === '-') { number += source[index++]; } - - ch = source[index]; - if (isDecimalDigit(ch)) { - number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } } else { - ch = 'character ' + ch; - if (index >= length) { - ch = ''; - } throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } } - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch)) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } return { @@ -844,14 +905,17 @@ parseStatement: true, parseSourceElement: true */ value: parseFloat(number), lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } // 7.8.4 String Literals function scanStringLiteral() { - var str = '', quote, start, ch, code, unescaped, restore, octal = false; + var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart; + startLineNumber = lineNumber; + startLineStart = lineStart; quote = source[index]; assert((quote === '\'' || quote === '"'), @@ -868,17 +932,8 @@ parseStatement: true, parseSourceElement: true */ break; } else if (ch === '\\') { ch = source[index++]; - if (!isLineTerminator(ch)) { + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { switch (ch) { - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; case 'u': case 'x': restore = index; @@ -890,6 +945,15 @@ parseStatement: true, parseSourceElement: true */ str += ch; } break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; case 'b': str += '\b'; break; @@ -932,8 +996,9 @@ parseStatement: true, parseSourceElement: true */ if (ch === '\r' && source[index] === '\n') { ++index; } + lineStart = index; } - } else if (isLineTerminator(ch)) { + } else if (isLineTerminator(ch.charCodeAt(0))) { break; } else { str += ch; @@ -948,33 +1013,46 @@ parseStatement: true, parseSourceElement: true */ type: Token.StringLiteral, value: str, octal: octal, + startLineNumber: startLineNumber, + startLineStart: startLineStart, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - function scanRegExp() { - var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + function testRegExp(pattern, flags) { + var value; + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + return value; + } - buffer = null; - skipComment(); + function scanRegExpBody() { + var ch, str, classMarker, terminated, body; - start = index; ch = source[index]; assert(ch === '/', 'Regular expression literal must start with a slash'); str = source[index++]; + classMarker = false; + terminated = false; while (index < length) { ch = source[index++]; str += ch; if (ch === '\\') { ch = source[index++]; // ECMA-262 7.8.5 - if (isLineTerminator(ch)) { + if (isLineTerminator(ch.charCodeAt(0))) { throwError({}, Messages.UnterminatedRegExp); } str += ch; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); } else if (classMarker) { if (ch === ']') { classMarker = false; @@ -985,8 +1063,6 @@ parseStatement: true, parseSourceElement: true */ break; } else if (ch === '[') { classMarker = true; - } else if (isLineTerminator(ch)) { - throwError({}, Messages.UnterminatedRegExp); } } } @@ -996,12 +1072,21 @@ parseStatement: true, parseSourceElement: true */ } // Exclude leading and trailing slash. - pattern = str.substr(1, str.length - 2); + body = str.substr(1, str.length - 2); + return { + value: body, + literal: str + }; + } + + function scanRegExpFlags() { + var ch, str, flags, restore; + str = ''; flags = ''; while (index < length) { ch = source[index]; - if (!isIdentifierPart(ch)) { + if (!isIdentifierPart(ch.charCodeAt(0))) { break; } @@ -1014,8 +1099,7 @@ parseStatement: true, parseSourceElement: true */ ch = scanHexEscape('u'); if (ch) { flags += ch; - str += '\\u'; - for (; restore < index; ++restore) { + for (str += '\\u'; restore < index; ++restore) { str += source[restore]; } } else { @@ -1023,8 +1107,10 @@ parseStatement: true, parseSourceElement: true */ flags += 'u'; str += '\\u'; } + throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); } else { str += '\\'; + throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); } } else { flags += ch; @@ -1032,17 +1118,82 @@ parseStatement: true, parseSourceElement: true */ } } - try { - value = new RegExp(pattern, flags); - } catch (e) { - throwError({}, Messages.InvalidRegExp); + return { + value: flags, + literal: str + }; + } + + function scanRegExp() { + var start, body, flags, pattern, value; + + lookahead = null; + skipComment(); + start = index; + + body = scanRegExpBody(); + flags = scanRegExpFlags(); + value = testRegExp(body.value, flags.value); + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; } return { - literal: str, + literal: body.literal + flags.literal, value: value, - range: [start, index] + start: start, + end: index + }; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = scanRegExp(); + loc.end = { + line: lineNumber, + column: index - lineStart }; + + /* istanbul ignore next */ + if (!extra.tokenize) { + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + } + + return regex; } function isIdentifierName(token) { @@ -1052,8 +1203,71 @@ parseStatement: true, parseSourceElement: true */ token.type === Token.NullLiteral; } + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return collectRegex(); + } + if (prevToken.type === 'Punctuator') { + if (prevToken.value === ']') { + return scanPunctuator(); + } + if (prevToken.value === ')') { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === 'Keyword' && + (checkToken.value === 'if' || + checkToken.value === 'while' || + checkToken.value === 'for' || + checkToken.value === 'with')) { + return collectRegex(); + } + return scanPunctuator(); + } + if (prevToken.value === '}') { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return collectRegex(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return collectRegex(); + } + return collectRegex(); + } + if (prevToken.type === 'Keyword') { + return collectRegex(); + } + return scanPunctuator(); + } + function advance() { - var ch, token; + var ch; skipComment(); @@ -1062,85 +1276,545 @@ parseStatement: true, parseSourceElement: true */ type: Token.EOF, lineNumber: lineNumber, lineStart: lineStart, - range: [index, index] + start: index, + end: index }; } - token = scanPunctuator(); - if (typeof token !== 'undefined') { - return token; + ch = source.charCodeAt(index); + + if (isIdentifierStart(ch)) { + return scanIdentifier(); } - ch = source[index]; + // Very common: ( and ) and ; + if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { + return scanPunctuator(); + } - if (ch === '\'' || ch === '"') { + // String literal starts with single quote (U+0027) or double quote (U+0022). + if (ch === 0x27 || ch === 0x22) { return scanStringLiteral(); } - if (ch === '.' || isDecimalDigit(ch)) { + + // Dot (.) U+002E can also start a floating-point number, hence the need + // to check the next character. + if (ch === 0x2E) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { return scanNumericLiteral(); } - token = scanIdentifier(); - if (typeof token !== 'undefined') { - return token; + // Slash (/) U+002F can also start a regex. + if (extra.tokenize && ch === 0x2F) { + return advanceSlash(); } - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + return scanPunctuator(); + } + + function collectToken() { + var loc, token, range, value; + + skipComment(); + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + + if (token.type !== Token.EOF) { + value = source.slice(token.start, token.end); + extra.tokens.push({ + type: TokenName[token.type], + value: value, + range: [token.start, token.end], + loc: loc + }); + } + + return token; } function lex() { var token; - if (buffer) { - index = buffer.range[1]; - lineNumber = buffer.lineNumber; - lineStart = buffer.lineStart; - token = buffer; - buffer = null; - return token; - } + token = lookahead; + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; - buffer = null; - return advance(); + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); + + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; + + return token; } - function lookahead() { + function peek() { var pos, line, start; - if (buffer !== null) { - return buffer; - } - pos = index; line = lineNumber; start = lineStart; - buffer = advance(); + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); index = pos; lineNumber = line; lineStart = start; + } - return buffer; + function Position(line, column) { + this.line = line; + this.column = column; } - // Return true if there is a line terminator before the next token. + function SourceLocation(startLine, startColumn, line, column) { + this.start = new Position(startLine, startColumn); + this.end = new Position(line, column); + } - function peekLineTerminator() { - var pos, line, start, found; + SyntaxTreeDelegate = { - pos = index; - line = lineNumber; - start = lineStart; - skipComment(); - found = lineNumber !== line; - index = pos; - lineNumber = line; - lineStart = start; + name: 'SyntaxTree', - return found; - } + processComment: function (node) { + var lastChild, trailingComments; - // Throw an exception + if (node.type === Syntax.Program) { + if (node.body.length > 0) { + return; + } + } + + if (extra.trailingComments.length > 0) { + if (extra.trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.trailingComments; + extra.trailingComments = []; + } else { + extra.trailingComments.length = 0; + } + } else { + if (extra.bottomRightStack.length > 0 && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + } + } + + // Eating the stack. + while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { + lastChild = extra.bottomRightStack.pop(); + } + + if (lastChild) { + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = lastChild.leadingComments; + delete lastChild.leadingComments; + } + } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = extra.leadingComments; + extra.leadingComments = []; + } + + + if (trailingComments) { + node.trailingComments = trailingComments; + } + + extra.bottomRightStack.push(node); + }, + + markEnd: function (node, startToken) { + if (extra.range) { + node.range = [startToken.start, index]; + } + if (extra.loc) { + node.loc = new SourceLocation( + startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber, + startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart), + lineNumber, + index - lineStart + ); + this.postProcess(node); + } + + if (extra.attachComment) { + this.processComment(node); + } + return node; + }, + + postProcess: function (node) { + if (extra.source) { + node.loc.source = extra.source; + } + return node; + }, + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : + Syntax.BinaryExpression; + return { + type: type, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createFunctionExpression: function (id, params, defaults, body) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: source.slice(token.start, token.end) + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument, + prefix: true + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + } + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; + } + + // Throw an exception function throwError(token, messageFormat) { var error, @@ -1148,15 +1822,16 @@ parseStatement: true, parseSourceElement: true */ msg = messageFormat.replace( /%(\d)/g, function (whole, index) { - return args[index] || ''; + assert(index < args.length, 'Message reference must be in range'); + return args[index]; } ); if (typeof token.lineNumber === 'number') { error = new Error('Line ' + token.lineNumber + ': ' + msg); - error.index = token.range[0]; + error.index = token.start; error.lineNumber = token.lineNumber; - error.column = token.range[0] - lineStart + 1; + error.column = token.start - lineStart + 1; } else { error = new Error('Line ' + lineNumber + ': ' + msg); error.index = index; @@ -1164,6 +1839,7 @@ parseStatement: true, parseSourceElement: true */ error.column = index - lineStart + 1; } + error.description = msg; throw error; } @@ -1236,26 +1912,24 @@ parseStatement: true, parseSourceElement: true */ // Return true if the next token matches the specified punctuator. function match(value) { - var token = lookahead(); - return token.type === Token.Punctuator && token.value === value; + return lookahead.type === Token.Punctuator && lookahead.value === value; } // Return true if the next token matches the specified keyword function matchKeyword(keyword) { - var token = lookahead(); - return token.type === Token.Keyword && token.value === keyword; + return lookahead.type === Token.Keyword && lookahead.value === keyword; } // Return true if the next token is an assignment operator function matchAssign() { - var token = lookahead(), - op = token.value; + var op; - if (token.type !== Token.Punctuator) { + if (lookahead.type !== Token.Punctuator) { return false; } + op = lookahead.value; return op === '=' || op === '*=' || op === '/=' || @@ -1271,10 +1945,10 @@ parseStatement: true, parseSourceElement: true */ } function consumeSemicolon() { - var token, line; + var line; - // Catch the very common case first. - if (source[index] === ';') { + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B || match(';')) { lex(); return; } @@ -1285,14 +1959,8 @@ parseStatement: true, parseSourceElement: true */ return; } - if (match(';')) { - lex(); - return; - } - - token = lookahead(); - if (token.type !== Token.EOF && !match('}')) { - throwUnexpected(token); + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); } } @@ -1305,8 +1973,9 @@ parseStatement: true, parseSourceElement: true */ // 11.1.4 Array Initialiser function parseArrayInitialiser() { - var elements = []; + var elements = [], startToken; + startToken = lookahead; expect('['); while (!match(']')) { @@ -1322,40 +1991,31 @@ parseStatement: true, parseSourceElement: true */ } } - expect(']'); + lex(); - return { - type: Syntax.ArrayExpression, - elements: elements - }; + return delegate.markEnd(delegate.createArrayExpression(elements), startToken); } // 11.1.5 Object Initialiser function parsePropertyFunction(param, first) { - var previousStrict, body; + var previousStrict, body, startToken; previousStrict = strict; + startToken = lookahead; body = parseFunctionSourceElements(); if (first && strict && isRestrictedWord(param[0].name)) { throwErrorTolerant(first, Messages.StrictParamName); } strict = previousStrict; - - return { - type: Syntax.FunctionExpression, - id: null, - params: param, - defaults: [], - body: body, - rest: null, - generator: false, - expression: false - }; + return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken); } function parseObjectPropertyKey() { - var token = lex(); + var token, startToken; + + startToken = lookahead; + token = lex(); // Note: This function is called only from parseObjectProperty(), where // EOF and Punctuator tokens are already filtered out. @@ -1364,19 +2024,17 @@ parseStatement: true, parseSourceElement: true */ if (strict && token.octal) { throwErrorTolerant(token, Messages.StrictOctalLiteral); } - return createLiteral(token); + return delegate.markEnd(delegate.createLiteral(token), startToken); } - return { - type: Syntax.Identifier, - name: token.value - }; + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); } function parseObjectProperty() { - var token, key, id, param; + var token, key, id, value, param, startToken; - token = lookahead(); + token = lookahead; + startToken = lookahead; if (token.type === Token.Identifier) { @@ -1388,60 +2046,42 @@ parseStatement: true, parseSourceElement: true */ key = parseObjectPropertyKey(); expect('('); expect(')'); - return { - type: Syntax.Property, - key: key, - value: parsePropertyFunction([]), - kind: 'get' - }; - } else if (token.value === 'set' && !match(':')) { + value = parsePropertyFunction([]); + return delegate.markEnd(delegate.createProperty('get', key, value), startToken); + } + if (token.value === 'set' && !match(':')) { key = parseObjectPropertyKey(); expect('('); - token = lookahead(); + token = lookahead; if (token.type !== Token.Identifier) { expect(')'); throwErrorTolerant(token, Messages.UnexpectedToken, token.value); - return { - type: Syntax.Property, - key: key, - value: parsePropertyFunction([]), - kind: 'set' - }; + value = parsePropertyFunction([]); } else { param = [ parseVariableIdentifier() ]; expect(')'); - return { - type: Syntax.Property, - key: key, - value: parsePropertyFunction(param, token), - kind: 'set' - }; + value = parsePropertyFunction(param, token); } - } else { - expect(':'); - return { - type: Syntax.Property, - key: id, - value: parseAssignmentExpression(), - kind: 'init' - }; + return delegate.markEnd(delegate.createProperty('set', key, value), startToken); } - } else if (token.type === Token.EOF || token.type === Token.Punctuator) { + expect(':'); + value = parseAssignmentExpression(); + return delegate.markEnd(delegate.createProperty('init', id, value), startToken); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { throwUnexpected(token); } else { key = parseObjectPropertyKey(); expect(':'); - return { - type: Syntax.Property, - key: key, - value: parseAssignmentExpression(), - kind: 'init' - }; + value = parseAssignmentExpression(); + return delegate.markEnd(delegate.createProperty('init', key, value), startToken); } } function parseObjectInitialiser() { - var properties = [], property, name, kind, map = {}, toString = String; + var properties = [], property, name, key, kind, map = {}, toString = String, startToken; + + startToken = lookahead; expect('{'); @@ -1454,8 +2094,10 @@ parseStatement: true, parseSourceElement: true */ name = toString(property.key.value); } kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; - if (Object.prototype.hasOwnProperty.call(map, name)) { - if (map[name] === PropertyKind.Data) { + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { if (strict && kind === PropertyKind.Data) { throwErrorTolerant({}, Messages.StrictDuplicateProperty); } else if (kind !== PropertyKind.Data) { @@ -1464,13 +2106,13 @@ parseStatement: true, parseSourceElement: true */ } else { if (kind === PropertyKind.Data) { throwErrorTolerant({}, Messages.AccessorDataProperty); - } else if (map[name] & kind) { + } else if (map[key] & kind) { throwErrorTolerant({}, Messages.AccessorGetSet); } } - map[name] |= kind; + map[key] |= kind; } else { - map[name] = kind; + map[key] = kind; } properties.push(property); @@ -1482,10 +2124,7 @@ parseStatement: true, parseSourceElement: true */ expect('}'); - return { - type: Syntax.ObjectExpression, - properties: properties - }; + return delegate.markEnd(delegate.createObjectExpression(properties), startToken); } // 11.1.6 The Grouping Operator @@ -1506,65 +2145,60 @@ parseStatement: true, parseSourceElement: true */ // 11.1 Primary Expressions function parsePrimaryExpression() { - var token = lookahead(), - type = token.type; + var type, token, expr, startToken; - if (type === Token.Identifier) { - return { - type: Syntax.Identifier, - name: lex().value - }; + if (match('(')) { + return parseGroupExpression(); } - if (type === Token.StringLiteral || type === Token.NumericLiteral) { - if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); - } - return createLiteral(lex()); + if (match('[')) { + return parseArrayInitialiser(); } - if (type === Token.Keyword) { - if (matchKeyword('this')) { - lex(); - return { - type: Syntax.ThisExpression - }; - } + if (match('{')) { + return parseObjectInitialiser(); + } + type = lookahead.type; + startToken = lookahead; + + if (type === Token.Identifier) { + expr = delegate.createIdentifier(lex().value); + } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + expr = delegate.createLiteral(lex()); + } else if (type === Token.Keyword) { if (matchKeyword('function')) { return parseFunctionExpression(); } - } - - if (type === Token.BooleanLiteral) { - lex(); + if (matchKeyword('this')) { + lex(); + expr = delegate.createThisExpression(); + } else { + throwUnexpected(lex()); + } + } else if (type === Token.BooleanLiteral) { + token = lex(); token.value = (token.value === 'true'); - return createLiteral(token); - } - - if (type === Token.NullLiteral) { - lex(); + expr = delegate.createLiteral(token); + } else if (type === Token.NullLiteral) { + token = lex(); token.value = null; - return createLiteral(token); - } - - if (match('[')) { - return parseArrayInitialiser(); - } - - if (match('{')) { - return parseObjectInitialiser(); - } - - if (match('(')) { - return parseGroupExpression(); - } - - if (match('/') || match('/=')) { - return createLiteral(scanRegExp()); + expr = delegate.createLiteral(token); + } else if (match('/') || match('/=')) { + if (typeof extra.tokens !== 'undefined') { + expr = delegate.createLiteral(collectRegex()); + } else { + expr = delegate.createLiteral(scanRegExp()); + } + peek(); + } else { + throwUnexpected(lex()); } - return throwUnexpected(lex()); + return delegate.markEnd(expr, startToken); } // 11.2 Left-Hand-Side Expressions @@ -1590,16 +2224,16 @@ parseStatement: true, parseSourceElement: true */ } function parseNonComputedProperty() { - var token = lex(); + var token, startToken; + + startToken = lookahead; + token = lex(); if (!isIdentifierName(token)) { throwUnexpected(token); } - return { - type: Syntax.Identifier, - name: token.value - }; + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); } function parseNonComputedMember() { @@ -1621,77 +2255,63 @@ parseStatement: true, parseSourceElement: true */ } function parseNewExpression() { - var expr; + var callee, args, startToken; + startToken = lookahead; expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; - expr = { - type: Syntax.NewExpression, - callee: parseLeftHandSideExpression(), - 'arguments': [] - }; - - if (match('(')) { - expr['arguments'] = parseArguments(); - } - - return expr; + return delegate.markEnd(delegate.createNewExpression(callee, args), startToken); } function parseLeftHandSideExpressionAllowCall() { - var expr; + var previousAllowIn, expr, args, property, startToken; + + startToken = lookahead; + previousAllowIn = state.allowIn; + state.allowIn = true; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + state.allowIn = previousAllowIn; - while (match('.') || match('[') || match('(')) { - if (match('(')) { - expr = { - type: Syntax.CallExpression, - callee: expr, - 'arguments': parseArguments() - }; + for (;;) { + if (match('.')) { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + } else if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); } else if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; + break; } + delegate.markEnd(expr, startToken); } return expr; } - function parseLeftHandSideExpression() { - var expr; + var previousAllowIn, expr, property, startToken; + + startToken = lookahead; + previousAllowIn = state.allowIn; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + state.allowIn = previousAllowIn; while (match('.') || match('[')) { if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); } + delegate.markEnd(expr, startToken); } return expr; @@ -1700,28 +2320,24 @@ parseStatement: true, parseSourceElement: true */ // 11.3 Postfix Expressions function parsePostfixExpression() { - var expr = parseLeftHandSideExpressionAllowCall(), token; + var expr, token, startToken = lookahead; - token = lookahead(); - if (token.type !== Token.Punctuator) { - return expr; - } + expr = parseLeftHandSideExpressionAllowCall(); - if ((match('++') || match('--')) && !peekLineTerminator()) { - // 11.3.1, 11.3.2 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPostfix); - } - if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } + if (lookahead.type === Token.Punctuator) { + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } - expr = { - type: Syntax.UpdateExpression, - operator: lex().value, - argument: expr, - prefix: false - }; + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken); + } } return expr; @@ -1730,14 +2346,12 @@ parseStatement: true, parseSourceElement: true */ // 11.4 Unary Operators function parseUnaryExpression() { - var token, expr; - - token = lookahead(); - if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { - return parsePostfixExpression(); - } + var token, expr, startToken; - if (match('++') || match('--')) { + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + expr = parsePostfixExpression(); + } else if (match('++') || match('--')) { + startToken = lookahead; token = lex(); expr = parseUnaryExpression(); // 11.4.4, 11.4.5 @@ -1749,221 +2363,174 @@ parseStatement: true, parseSourceElement: true */ throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } - expr = { - type: Syntax.UpdateExpression, - operator: token.value, - argument: expr, - prefix: true - }; - return expr; - } - - if (match('+') || match('-') || match('~') || match('!')) { - expr = { - type: Syntax.UnaryExpression, - operator: lex().value, - argument: parseUnaryExpression(), - prefix: true - }; - return expr; - } - - if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { - expr = { - type: Syntax.UnaryExpression, - operator: lex().value, - argument: parseUnaryExpression(), - prefix: true - }; + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + } else if (match('+') || match('-') || match('~') || match('!')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { throwErrorTolerant({}, Messages.StrictDelete); } - return expr; - } - - return parsePostfixExpression(); - } - - // 11.5 Multiplicative Operators - - function parseMultiplicativeExpression() { - var expr = parseUnaryExpression(); - - while (match('*') || match('/') || match('%')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseUnaryExpression() - }; + } else { + expr = parsePostfixExpression(); } return expr; } - // 11.6 Additive Operators - - function parseAdditiveExpression() { - var expr = parseMultiplicativeExpression(); + function binaryPrecedence(token, allowIn) { + var prec = 0; - while (match('+') || match('-')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseMultiplicativeExpression() - }; + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; } - return expr; - } - - // 11.7 Bitwise Shift Operators + switch (token.value) { + case '||': + prec = 1; + break; - function parseShiftExpression() { - var expr = parseAdditiveExpression(); + case '&&': + prec = 2; + break; - while (match('<<') || match('>>') || match('>>>')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseAdditiveExpression() - }; - } + case '|': + prec = 3; + break; - return expr; - } - // 11.8 Relational Operators + case '^': + prec = 4; + break; - function parseRelationalExpression() { - var expr, previousAllowIn; + case '&': + prec = 5; + break; - previousAllowIn = state.allowIn; - state.allowIn = true; + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; - expr = parseShiftExpression(); + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; - while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseShiftExpression() - }; - } + case 'in': + prec = allowIn ? 7 : 0; + break; - state.allowIn = previousAllowIn; - return expr; - } + case '<<': + case '>>': + case '>>>': + prec = 8; + break; - // 11.9 Equality Operators + case '+': + case '-': + prec = 9; + break; - function parseEqualityExpression() { - var expr = parseRelationalExpression(); + case '*': + case '/': + case '%': + prec = 11; + break; - while (match('==') || match('!=') || match('===') || match('!==')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseRelationalExpression() - }; + default: + break; } - return expr; + return prec; } + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators - function parseBitwiseANDExpression() { - var expr = parseEqualityExpression(); - - while (match('&')) { - lex(); - expr = { - type: Syntax.BinaryExpression, - operator: '&', - left: expr, - right: parseEqualityExpression() - }; - } - - return expr; - } + function parseBinaryExpression() { + var marker, markers, expr, token, prec, stack, right, operator, left, i; - function parseBitwiseXORExpression() { - var expr = parseBitwiseANDExpression(); + marker = lookahead; + left = parseUnaryExpression(); - while (match('^')) { - lex(); - expr = { - type: Syntax.BinaryExpression, - operator: '^', - left: expr, - right: parseBitwiseANDExpression() - }; + token = lookahead; + prec = binaryPrecedence(token, state.allowIn); + if (prec === 0) { + return left; } + token.prec = prec; + lex(); - return expr; - } - - function parseBitwiseORExpression() { - var expr = parseBitwiseXORExpression(); - - while (match('|')) { - lex(); - expr = { - type: Syntax.BinaryExpression, - operator: '|', - left: expr, - right: parseBitwiseXORExpression() - }; - } + markers = [marker, lookahead]; + right = parseUnaryExpression(); - return expr; - } + stack = [left, token, right]; - // 11.11 Binary Logical Operators + while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { - function parseLogicalANDExpression() { - var expr = parseBitwiseORExpression(); + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + expr = delegate.createBinaryExpression(operator, left, right); + markers.pop(); + marker = markers[markers.length - 1]; + delegate.markEnd(expr, marker); + stack.push(expr); + } - while (match('&&')) { - lex(); - expr = { - type: Syntax.LogicalExpression, - operator: '&&', - left: expr, - right: parseBitwiseORExpression() - }; + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + markers.push(lookahead); + expr = parseUnaryExpression(); + stack.push(expr); } - return expr; - } - - function parseLogicalORExpression() { - var expr = parseLogicalANDExpression(); - - while (match('||')) { - lex(); - expr = { - type: Syntax.LogicalExpression, - operator: '||', - left: expr, - right: parseLogicalANDExpression() - }; + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + markers.pop(); + while (i > 1) { + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + marker = markers.pop(); + delegate.markEnd(expr, marker); } return expr; } + // 11.12 Conditional Operator function parseConditionalExpression() { - var expr, previousAllowIn, consequent; + var expr, previousAllowIn, consequent, alternate, startToken; - expr = parseLogicalORExpression(); + startToken = lookahead; + + expr = parseBinaryExpression(); if (match('?')) { lex(); @@ -1972,13 +2539,10 @@ parseStatement: true, parseSourceElement: true */ consequent = parseAssignmentExpression(); state.allowIn = previousAllowIn; expect(':'); + alternate = parseAssignmentExpression(); - expr = { - type: Syntax.ConditionalExpression, - test: expr, - consequent: consequent, - alternate: parseAssignmentExpression() - }; + expr = delegate.createConditionalExpression(expr, consequent, alternate); + delegate.markEnd(expr, startToken); } return expr; @@ -1987,43 +2551,41 @@ parseStatement: true, parseSourceElement: true */ // 11.13 Assignment Operators function parseAssignmentExpression() { - var token, expr; + var token, left, right, node, startToken; - token = lookahead(); - expr = parseConditionalExpression(); + token = lookahead; + startToken = lookahead; + + node = left = parseConditionalExpression(); if (matchAssign()) { // LeftHandSideExpression - if (!isLeftHandSide(expr)) { + if (!isLeftHandSide(left)) { throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } // 11.13.1 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { throwErrorTolerant(token, Messages.StrictLHSAssignment); } - expr = { - type: Syntax.AssignmentExpression, - operator: lex().value, - left: expr, - right: parseAssignmentExpression() - }; + token = lex(); + right = parseAssignmentExpression(); + node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken); } - return expr; + return node; } // 11.14 Comma Operator function parseExpression() { - var expr = parseAssignmentExpression(); + var expr, startToken = lookahead; + + expr = parseAssignmentExpression(); if (match(',')) { - expr = { - type: Syntax.SequenceExpression, - expressions: [ expr ] - }; + expr = delegate.createSequenceExpression([ expr ]); while (index < length) { if (!match(',')) { @@ -2033,7 +2595,9 @@ parseStatement: true, parseSourceElement: true */ expr.expressions.push(parseAssignmentExpression()); } + delegate.markEnd(expr, startToken); } + return expr; } @@ -2058,38 +2622,38 @@ parseStatement: true, parseSourceElement: true */ } function parseBlock() { - var block; + var block, startToken; + startToken = lookahead; expect('{'); block = parseStatementList(); expect('}'); - return { - type: Syntax.BlockStatement, - body: block - }; + return delegate.markEnd(delegate.createBlockStatement(block), startToken); } // 12.2 Variable Statement function parseVariableIdentifier() { - var token = lex(); + var token, startToken; + + startToken = lookahead; + token = lex(); if (token.type !== Token.Identifier) { throwUnexpected(token); } - return { - type: Syntax.Identifier, - name: token.value - }; + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); } function parseVariableDeclaration(kind) { - var id = parseVariableIdentifier(), - init = null; + var init = null, id, startToken; + + startToken = lookahead; + id = parseVariableIdentifier(); // 12.2.1 if (strict && isRestrictedWord(id.name)) { @@ -2104,11 +2668,7 @@ parseStatement: true, parseSourceElement: true */ init = parseAssignmentExpression(); } - return { - type: Syntax.VariableDeclarator, - id: id, - init: init - }; + return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken); } function parseVariableDeclarationList(kind) { @@ -2134,11 +2694,7 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: 'var' - }; + return delegate.createVariableDeclaration(declarations, 'var'); } // kind may be `const` or `let` @@ -2146,7 +2702,9 @@ parseStatement: true, parseSourceElement: true */ // see http://wiki.ecmascript.org/doku.php?id=harmony:const // and http://wiki.ecmascript.org/doku.php?id=harmony:let function parseConstLetDeclaration(kind) { - var declarations; + var declarations, startToken; + + startToken = lookahead; expectKeyword(kind); @@ -2154,34 +2712,22 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: kind - }; + return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken); } // 12.3 Empty Statement function parseEmptyStatement() { expect(';'); - - return { - type: Syntax.EmptyStatement - }; + return delegate.createEmptyStatement(); } // 12.4 Expression Statement function parseExpressionStatement() { var expr = parseExpression(); - consumeSemicolon(); - - return { - type: Syntax.ExpressionStatement, - expression: expr - }; + return delegate.createExpressionStatement(expr); } // 12.5 If statement @@ -2206,12 +2752,7 @@ parseStatement: true, parseSourceElement: true */ alternate = null; } - return { - type: Syntax.IfStatement, - test: test, - consequent: consequent, - alternate: alternate - }; + return delegate.createIfStatement(test, consequent, alternate); } // 12.6 Iteration Statements @@ -2240,11 +2781,7 @@ parseStatement: true, parseSourceElement: true */ lex(); } - return { - type: Syntax.DoWhileStatement, - body: body, - test: test - }; + return delegate.createDoWhileStatement(body, test); } function parseWhileStatement() { @@ -2265,21 +2802,17 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; - return { - type: Syntax.WhileStatement, - test: test, - body: body - }; + return delegate.createWhileStatement(test, body); } function parseForVariableDeclaration() { - var token = lex(); + var token, declarations, startToken; - return { - type: Syntax.VariableDeclaration, - declarations: parseVariableDeclarationList(), - kind: token.value - }; + startToken = lookahead; + token = lex(); + declarations = parseVariableDeclarationList(); + + return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken); } function parseForStatement() { @@ -2349,44 +2882,27 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; - if (typeof left === 'undefined') { - return { - type: Syntax.ForStatement, - init: init, - test: test, - update: update, - body: body - }; - } - - return { - type: Syntax.ForInStatement, - left: left, - right: right, - body: body, - each: false - }; + return (typeof left === 'undefined') ? + delegate.createForStatement(init, test, update, body) : + delegate.createForInStatement(left, right, body); } // 12.7 The continue statement function parseContinueStatement() { - var token, label = null; + var label = null, key; expectKeyword('continue'); // Optimize the most common form: 'continue;'. - if (source[index] === ';') { + if (source.charCodeAt(index) === 0x3B) { lex(); if (!state.inIteration) { throwError({}, Messages.IllegalContinue); } - return { - type: Syntax.ContinueStatement, - label: null - }; + return delegate.createContinueStatement(null); } if (peekLineTerminator()) { @@ -2394,17 +2910,14 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalContinue); } - return { - type: Syntax.ContinueStatement, - label: null - }; + return delegate.createContinueStatement(null); } - token = lookahead(); - if (token.type === Token.Identifier) { + if (lookahead.type === Token.Identifier) { label = parseVariableIdentifier(); - if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError({}, Messages.UnknownLabel, label.name); } } @@ -2415,31 +2928,25 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalContinue); } - return { - type: Syntax.ContinueStatement, - label: label - }; + return delegate.createContinueStatement(label); } // 12.8 The break statement function parseBreakStatement() { - var token, label = null; + var label = null, key; expectKeyword('break'); - // Optimize the most common form: 'break;'. - if (source[index] === ';') { + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B) { lex(); if (!(state.inIteration || state.inSwitch)) { throwError({}, Messages.IllegalBreak); } - return { - type: Syntax.BreakStatement, - label: null - }; + return delegate.createBreakStatement(null); } if (peekLineTerminator()) { @@ -2447,17 +2954,14 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalBreak); } - return { - type: Syntax.BreakStatement, - label: null - }; + return delegate.createBreakStatement(null); } - token = lookahead(); - if (token.type === Token.Identifier) { + if (lookahead.type === Token.Identifier) { label = parseVariableIdentifier(); - if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError({}, Messages.UnknownLabel, label.name); } } @@ -2468,16 +2972,13 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalBreak); } - return { - type: Syntax.BreakStatement, - label: label - }; + return delegate.createBreakStatement(label); } // 12.9 The return statement function parseReturnStatement() { - var token, argument = null; + var argument = null; expectKeyword('return'); @@ -2486,37 +2987,27 @@ parseStatement: true, parseSourceElement: true */ } // 'return' followed by a space and an identifier is very common. - if (source[index] === ' ') { - if (isIdentifierStart(source[index + 1])) { + if (source.charCodeAt(index) === 0x20) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { argument = parseExpression(); consumeSemicolon(); - return { - type: Syntax.ReturnStatement, - argument: argument - }; + return delegate.createReturnStatement(argument); } } if (peekLineTerminator()) { - return { - type: Syntax.ReturnStatement, - argument: null - }; + return delegate.createReturnStatement(null); } if (!match(';')) { - token = lookahead(); - if (!match('}') && token.type !== Token.EOF) { + if (!match('}') && lookahead.type !== Token.EOF) { argument = parseExpression(); } } consumeSemicolon(); - return { - type: Syntax.ReturnStatement, - argument: argument - }; + return delegate.createReturnStatement(argument); } // 12.10 The with statement @@ -2525,6 +3016,8 @@ parseStatement: true, parseSourceElement: true */ var object, body; if (strict) { + // TODO(ikarienator): Should we update the test cases instead? + skipComment(); throwErrorTolerant({}, Messages.StrictModeWith); } @@ -2538,20 +3031,15 @@ parseStatement: true, parseSourceElement: true */ body = parseStatement(); - return { - type: Syntax.WithStatement, - object: object, - body: body - }; + return delegate.createWithStatement(object, body); } // 12.10 The swith statement function parseSwitchCase() { - var test, - consequent = [], - statement; + var test, consequent = [], statement, startToken; + startToken = lookahead; if (matchKeyword('default')) { lex(); test = null; @@ -2566,17 +3054,10 @@ parseStatement: true, parseSourceElement: true */ break; } statement = parseStatement(); - if (typeof statement === 'undefined') { - break; - } consequent.push(statement); } - return { - type: Syntax.SwitchCase, - test: test, - consequent: consequent - }; + return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken); } function parseSwitchStatement() { @@ -2596,11 +3077,7 @@ parseStatement: true, parseSourceElement: true */ if (match('}')) { lex(); - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; + return delegate.createSwitchStatement(discriminant, cases); } oldInSwitch = state.inSwitch; @@ -2625,11 +3102,7 @@ parseStatement: true, parseSourceElement: true */ expect('}'); - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; + return delegate.createSwitchStatement(discriminant, cases); } // 12.13 The throw statement @@ -2647,22 +3120,20 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.ThrowStatement, - argument: argument - }; + return delegate.createThrowStatement(argument); } // 12.14 The try statement function parseCatchClause() { - var param; + var param, body, startToken; + startToken = lookahead; expectKeyword('catch'); expect('('); if (match(')')) { - throwUnexpected(lookahead()); + throwUnexpected(lookahead); } param = parseVariableIdentifier(); @@ -2672,12 +3143,8 @@ parseStatement: true, parseSourceElement: true */ } expect(')'); - - return { - type: Syntax.CatchClause, - param: param, - body: parseBlock() - }; + body = parseBlock(); + return delegate.markEnd(delegate.createCatchClause(param, body), startToken); } function parseTryStatement() { @@ -2700,13 +3167,7 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.NoCatchOrFinally); } - return { - type: Syntax.TryStatement, - block: block, - guardedHandlers: [], - handlers: handlers, - finalizer: finalizer - }; + return delegate.createTryStatement(block, [], handlers, finalizer); } // 12.15 The debugger statement @@ -2716,65 +3177,69 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.DebuggerStatement - }; + return delegate.createDebuggerStatement(); } // 12 Statements function parseStatement() { - var token = lookahead(), + var type = lookahead.type, expr, - labeledBody; + labeledBody, + key, + startToken; - if (token.type === Token.EOF) { - throwUnexpected(token); + if (type === Token.EOF) { + throwUnexpected(lookahead); } - if (token.type === Token.Punctuator) { - switch (token.value) { + if (type === Token.Punctuator && lookahead.value === '{') { + return parseBlock(); + } + + startToken = lookahead; + + if (type === Token.Punctuator) { + switch (lookahead.value) { case ';': - return parseEmptyStatement(); - case '{': - return parseBlock(); + return delegate.markEnd(parseEmptyStatement(), startToken); case '(': - return parseExpressionStatement(); + return delegate.markEnd(parseExpressionStatement(), startToken); default: break; } } - if (token.type === Token.Keyword) { - switch (token.value) { + if (type === Token.Keyword) { + switch (lookahead.value) { case 'break': - return parseBreakStatement(); + return delegate.markEnd(parseBreakStatement(), startToken); case 'continue': - return parseContinueStatement(); + return delegate.markEnd(parseContinueStatement(), startToken); case 'debugger': - return parseDebuggerStatement(); + return delegate.markEnd(parseDebuggerStatement(), startToken); case 'do': - return parseDoWhileStatement(); + return delegate.markEnd(parseDoWhileStatement(), startToken); case 'for': - return parseForStatement(); + return delegate.markEnd(parseForStatement(), startToken); case 'function': - return parseFunctionDeclaration(); + return delegate.markEnd(parseFunctionDeclaration(), startToken); case 'if': - return parseIfStatement(); + return delegate.markEnd(parseIfStatement(), startToken); case 'return': - return parseReturnStatement(); + return delegate.markEnd(parseReturnStatement(), startToken); case 'switch': - return parseSwitchStatement(); + return delegate.markEnd(parseSwitchStatement(), startToken); case 'throw': - return parseThrowStatement(); + return delegate.markEnd(parseThrowStatement(), startToken); case 'try': - return parseTryStatement(); + return delegate.markEnd(parseTryStatement(), startToken); case 'var': - return parseVariableStatement(); + return delegate.markEnd(parseVariableStatement(), startToken); case 'while': - return parseWhileStatement(); + return delegate.markEnd(parseWhileStatement(), startToken); case 'with': - return parseWithStatement(); + return delegate.markEnd(parseWithStatement(), startToken); default: break; } @@ -2786,42 +3251,36 @@ parseStatement: true, parseSourceElement: true */ if ((expr.type === Syntax.Identifier) && match(':')) { lex(); - if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) { + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError({}, Messages.Redeclaration, 'Label', expr.name); } - state.labelSet[expr.name] = true; + state.labelSet[key] = true; labeledBody = parseStatement(); - delete state.labelSet[expr.name]; - - return { - type: Syntax.LabeledStatement, - label: expr, - body: labeledBody - }; + delete state.labelSet[key]; + return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken); } consumeSemicolon(); - return { - type: Syntax.ExpressionStatement, - expression: expr - }; + return delegate.markEnd(delegate.createExpressionStatement(expr), startToken); } // 13 Function Definition function parseFunctionSourceElements() { var sourceElement, sourceElements = [], token, directive, firstRestricted, - oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody; + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken; + startToken = lookahead; expect('{'); while (index < length) { - token = lookahead(); - if (token.type !== Token.StringLiteral) { + if (lookahead.type !== Token.StringLiteral) { break; } + token = lookahead; sourceElement = parseSourceElement(); sourceElements.push(sourceElement); @@ -2829,7 +3288,7 @@ parseStatement: true, parseSourceElement: true */ // this is not directive break; } - directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + directive = source.slice(token.start + 1, token.end - 1); if (directive === 'use strict') { strict = true; if (firstRestricted) { @@ -2870,45 +3329,25 @@ parseStatement: true, parseSourceElement: true */ state.inSwitch = oldInSwitch; state.inFunctionBody = oldInFunctionBody; - return { - type: Syntax.BlockStatement, - body: sourceElements - }; + return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken); } - function parseFunctionDeclaration() { - var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet; - - expectKeyword('function'); - token = lookahead(); - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - + function parseParams(firstRestricted) { + var param, params = [], token, stricted, paramSet, key, message; expect('('); if (!match(')')) { paramSet = {}; while (index < length) { - token = lookahead(); + token = lookahead; param = parseVariableIdentifier(); + key = '$' + token.value; if (strict) { if (isRestrictedWord(token.value)) { stricted = token; message = Messages.StrictParamName; } - if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + if (Object.prototype.hasOwnProperty.call(paramSet, key)) { stricted = token; message = Messages.StrictParamDupe; } @@ -2919,13 +3358,13 @@ parseStatement: true, parseSourceElement: true */ } else if (isStrictModeReservedWord(token.value)) { firstRestricted = token; message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { firstRestricted = token; message = Messages.StrictParamDupe; } } params.push(param); - paramSet[param.name] = true; + paramSet[key] = true; if (match(')')) { break; } @@ -2935,6 +3374,44 @@ parseStatement: true, parseSourceElement: true */ expect(')'); + return { + params: params, + stricted: stricted, + firstRestricted: firstRestricted, + message: message + }; + } + + function parseFunctionDeclaration() { + var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken; + + startToken = lookahead; + + expectKeyword('function'); + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { @@ -2945,25 +3422,17 @@ parseStatement: true, parseSourceElement: true */ } strict = previousStrict; - return { - type: Syntax.FunctionDeclaration, - id: id, - params: params, - defaults: [], - body: body, - rest: null, - generator: false, - expression: false - }; + return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken); } function parseFunctionExpression() { - var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet; + var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken; + startToken = lookahead; expectKeyword('function'); if (!match('(')) { - token = lookahead(); + token = lookahead; id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { @@ -2980,45 +3449,14 @@ parseStatement: true, parseSourceElement: true */ } } - expect('('); - - if (!match(')')) { - paramSet = {}; - while (index < length) { - token = lookahead(); - param = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - stricted = token; - message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { - stricted = token; - message = Messages.StrictParamDupe; - } - } else if (!firstRestricted) { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { - firstRestricted = token; - message = Messages.StrictParamDupe; - } - } - params.push(param); - paramSet[param.name] = true; - if (match(')')) { - break; - } - expect(','); - } + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; } - expect(')'); - previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { @@ -3029,28 +3467,17 @@ parseStatement: true, parseSourceElement: true */ } strict = previousStrict; - return { - type: Syntax.FunctionExpression, - id: id, - params: params, - defaults: [], - body: body, - rest: null, - generator: false, - expression: false - }; + return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken); } // 14 Program function parseSourceElement() { - var token = lookahead(); - - if (token.type === Token.Keyword) { - switch (token.value) { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { case 'const': case 'let': - return parseConstLetDeclaration(token.value); + return parseConstLetDeclaration(lookahead.value); case 'function': return parseFunctionDeclaration(); default: @@ -3058,7 +3485,7 @@ parseStatement: true, parseSourceElement: true */ } } - if (token.type !== Token.EOF) { + if (lookahead.type !== Token.EOF) { return parseStatement(); } } @@ -3067,7 +3494,7 @@ parseStatement: true, parseSourceElement: true */ var sourceElement, sourceElements = [], token, directive, firstRestricted; while (index < length) { - token = lookahead(); + token = lookahead; if (token.type !== Token.StringLiteral) { break; } @@ -3078,7 +3505,7 @@ parseStatement: true, parseSourceElement: true */ // this is not directive break; } - directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + directive = source.slice(token.start + 1, token.end - 1); if (directive === 'use strict') { strict = true; if (firstRestricted) { @@ -3093,6 +3520,7 @@ parseStatement: true, parseSourceElement: true */ while (index < length) { sourceElement = parseSourceElement(); + /* istanbul ignore if */ if (typeof sourceElement === 'undefined') { break; } @@ -3102,251 +3530,15 @@ parseStatement: true, parseSourceElement: true */ } function parseProgram() { - var program; - strict = false; - program = { - type: Syntax.Program, - body: parseSourceElements() - }; - return program; - } - - // The following functions are needed only when the option to preserve - // the comments is active. - - function addComment(type, value, start, end, loc) { - assert(typeof start === 'number', 'Comment must have valid position'); - - // Because the way the actual token is scanned, often the comments - // (if any) are skipped twice during the lexical analysis. - // Thus, we need to skip adding a comment if the comment array already - // handled it. - if (extra.comments.length > 0) { - if (extra.comments[extra.comments.length - 1].range[1] > start) { - return; - } - } - - extra.comments.push({ - type: type, - value: value, - range: [start, end], - loc: loc - }); - } - - function scanComment() { - var comment, ch, loc, start, blockComment, lineComment; - - comment = ''; - blockComment = false; - lineComment = false; - - while (index < length) { - ch = source[index]; - - if (lineComment) { - ch = source[index++]; - if (isLineTerminator(ch)) { - loc.end = { - line: lineNumber, - column: index - lineStart - 1 - }; - lineComment = false; - addComment('Line', comment, start, index - 1, loc); - if (ch === '\r' && source[index] === '\n') { - ++index; - } - ++lineNumber; - lineStart = index; - comment = ''; - } else if (index >= length) { - lineComment = false; - comment += ch; - loc.end = { - line: lineNumber, - column: length - lineStart - }; - addComment('Line', comment, start, length, loc); - } else { - comment += ch; - } - } else if (blockComment) { - if (isLineTerminator(ch)) { - if (ch === '\r' && source[index + 1] === '\n') { - ++index; - comment += '\r\n'; - } else { - comment += ch; - } - ++lineNumber; - ++index; - lineStart = index; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - ch = source[index++]; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - comment += ch; - if (ch === '*') { - ch = source[index]; - if (ch === '/') { - comment = comment.substr(0, comment.length - 1); - blockComment = false; - ++index; - loc.end = { - line: lineNumber, - column: index - lineStart - }; - addComment('Block', comment, start, index, loc); - comment = ''; - } - } - } - } else if (ch === '/') { - ch = source[index + 1]; - if (ch === '/') { - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - start = index; - index += 2; - lineComment = true; - if (index >= length) { - loc.end = { - line: lineNumber, - column: index - lineStart - }; - lineComment = false; - addComment('Line', comment, start, index, loc); - } - } else if (ch === '*') { - start = index; - index += 2; - blockComment = true; - loc = { - start: { - line: lineNumber, - column: index - lineStart - 2 - } - }; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - break; - } - } else if (isWhiteSpace(ch)) { - ++index; - } else if (isLineTerminator(ch)) { - ++index; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - ++lineNumber; - lineStart = index; - } else { - break; - } - } - } - - function filterCommentLocation() { - var i, entry, comment, comments = []; - - for (i = 0; i < extra.comments.length; ++i) { - entry = extra.comments[i]; - comment = { - type: entry.type, - value: entry.value - }; - if (extra.range) { - comment.range = entry.range; - } - if (extra.loc) { - comment.loc = entry.loc; - } - comments.push(comment); - } - - extra.comments = comments; - } - - function collectToken() { - var start, loc, token, range, value; + var body, startToken; skipComment(); - start = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - token = extra.advance(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - if (token.type !== Token.EOF) { - range = [token.range[0], token.range[1]]; - value = sliceSource(token.range[0], token.range[1]); - extra.tokens.push({ - type: TokenName[token.type], - value: value, - range: range, - loc: loc - }); - } - - return token; - } - - function collectRegex() { - var pos, loc, regex, token; - - skipComment(); - - pos = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - regex = extra.scanRegExp(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - // Pop the previous token, which is likely '/' or '/=' - if (extra.tokens.length > 0) { - token = extra.tokens[extra.tokens.length - 1]; - if (token.range[0] === pos && token.type === 'Punctuator') { - if (token.value === '/' || token.value === '/=') { - extra.tokens.pop(); - } - } - } - - extra.tokens.push({ - type: 'RegularExpression', - value: regex.literal, - range: [pos, index], - loc: loc - }); + peek(); + startToken = lookahead; + strict = false; - return regex; + body = parseSourceElements(); + return delegate.markEnd(delegate.createProgram(body), startToken); } function filterTokenLocation() { @@ -3370,431 +3562,92 @@ parseStatement: true, parseSourceElement: true */ extra.tokens = tokens; } - function createLiteral(token) { - return { - type: Syntax.Literal, - value: token.value - }; - } - - function createRawLiteral(token) { - return { - type: Syntax.Literal, - value: token.value, - raw: sliceSource(token.range[0], token.range[1]) - }; - } - - function createLocationMarker() { - var marker = {}; - - marker.range = [index, index]; - marker.loc = { - start: { - line: lineNumber, - column: index - lineStart - }, - end: { - line: lineNumber, - column: index - lineStart - } - }; - - marker.end = function () { - this.range[1] = index; - this.loc.end.line = lineNumber; - this.loc.end.column = index - lineStart; - }; + function tokenize(code, options) { + var toString, + token, + tokens; - marker.applyGroup = function (node) { - if (extra.range) { - node.groupRange = [this.range[0], this.range[1]]; - } - if (extra.loc) { - node.groupLoc = { - start: { - line: this.loc.start.line, - column: this.loc.start.column - }, - end: { - line: this.loc.end.line, - column: this.loc.end.column - } - }; - } - }; + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } - marker.apply = function (node) { - if (extra.range) { - node.range = [this.range[0], this.range[1]]; - } - if (extra.loc) { - node.loc = { - start: { - line: this.loc.start.line, - column: this.loc.start.column - }, - end: { - line: this.loc.end.line, - column: this.loc.end.column - } - }; - } + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1 }; - return marker; - } - - function trackGroupExpression() { - var marker, expr; - - skipComment(); - marker = createLocationMarker(); - expect('('); - - expr = parseExpression(); - - expect(')'); - - marker.end(); - marker.applyGroup(expr); - - return expr; - } - - function trackLeftHandSideExpression() { - var marker, expr; - - skipComment(); - marker = createLocationMarker(); - - expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - - while (match('.') || match('[')) { - if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; - marker.end(); - marker.apply(expr); - } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; - marker.end(); - marker.apply(expr); - } - } - - return expr; - } + extra = {}; - function trackLeftHandSideExpressionAllowCall() { - var marker, expr; + // Options matching. + options = options || {}; - skipComment(); - marker = createLocationMarker(); + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; - expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; - while (match('.') || match('[') || match('(')) { - if (match('(')) { - expr = { - type: Syntax.CallExpression, - callee: expr, - 'arguments': parseArguments() - }; - marker.end(); - marker.apply(expr); - } else if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; - marker.end(); - marker.apply(expr); - } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; - marker.end(); - marker.apply(expr); - } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; } - - return expr; - } - - function filterGroup(node) { - var n, i, entry; - - n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; - for (i in node) { - if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { - entry = node[i]; - if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { - n[i] = entry; - } else { - n[i] = filterGroup(entry); - } - } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; } - return n; - } - - function wrapTrackingFunction(range, loc) { - - return function (parseFunction) { - function isBinary(node) { - return node.type === Syntax.LogicalExpression || - node.type === Syntax.BinaryExpression; + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; } - function visit(node) { - var start, end; - - if (isBinary(node.left)) { - visit(node.left); - } - if (isBinary(node.right)) { - visit(node.right); - } - - if (range) { - if (node.left.groupRange || node.right.groupRange) { - start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; - end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; - node.range = [start, end]; - } else if (typeof node.range === 'undefined') { - start = node.left.range[0]; - end = node.right.range[1]; - node.range = [start, end]; - } - } - if (loc) { - if (node.left.groupLoc || node.right.groupLoc) { - start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; - end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; - node.loc = { - start: start, - end: end - }; - } else if (typeof node.loc === 'undefined') { - node.loc = { - start: node.left.loc.start, - end: node.right.loc.end - }; + token = lex(); + while (lookahead.type !== Token.EOF) { + try { + token = lex(); + } catch (lexError) { + token = lookahead; + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; } } } - return function () { - var marker, node; - - skipComment(); - - marker = createLocationMarker(); - node = parseFunction.apply(null, arguments); - marker.end(); - - if (range && typeof node.range === 'undefined') { - marker.apply(node); - } - - if (loc && typeof node.loc === 'undefined') { - marker.apply(node); - } - - if (isBinary(node)) { - visit(node); - } - - return node; - }; - }; - } - - function patch() { - - var wrapTracking; - - if (extra.comments) { - extra.skipComment = skipComment; - skipComment = scanComment; - } - - if (extra.raw) { - extra.createLiteral = createLiteral; - createLiteral = createRawLiteral; - } - - if (extra.range || extra.loc) { - - extra.parseGroupExpression = parseGroupExpression; - extra.parseLeftHandSideExpression = parseLeftHandSideExpression; - extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; - parseGroupExpression = trackGroupExpression; - parseLeftHandSideExpression = trackLeftHandSideExpression; - parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; - - wrapTracking = wrapTrackingFunction(extra.range, extra.loc); - - extra.parseAdditiveExpression = parseAdditiveExpression; - extra.parseAssignmentExpression = parseAssignmentExpression; - extra.parseBitwiseANDExpression = parseBitwiseANDExpression; - extra.parseBitwiseORExpression = parseBitwiseORExpression; - extra.parseBitwiseXORExpression = parseBitwiseXORExpression; - extra.parseBlock = parseBlock; - extra.parseFunctionSourceElements = parseFunctionSourceElements; - extra.parseCatchClause = parseCatchClause; - extra.parseComputedMember = parseComputedMember; - extra.parseConditionalExpression = parseConditionalExpression; - extra.parseConstLetDeclaration = parseConstLetDeclaration; - extra.parseEqualityExpression = parseEqualityExpression; - extra.parseExpression = parseExpression; - extra.parseForVariableDeclaration = parseForVariableDeclaration; - extra.parseFunctionDeclaration = parseFunctionDeclaration; - extra.parseFunctionExpression = parseFunctionExpression; - extra.parseLogicalANDExpression = parseLogicalANDExpression; - extra.parseLogicalORExpression = parseLogicalORExpression; - extra.parseMultiplicativeExpression = parseMultiplicativeExpression; - extra.parseNewExpression = parseNewExpression; - extra.parseNonComputedProperty = parseNonComputedProperty; - extra.parseObjectProperty = parseObjectProperty; - extra.parseObjectPropertyKey = parseObjectPropertyKey; - extra.parsePostfixExpression = parsePostfixExpression; - extra.parsePrimaryExpression = parsePrimaryExpression; - extra.parseProgram = parseProgram; - extra.parsePropertyFunction = parsePropertyFunction; - extra.parseRelationalExpression = parseRelationalExpression; - extra.parseStatement = parseStatement; - extra.parseShiftExpression = parseShiftExpression; - extra.parseSwitchCase = parseSwitchCase; - extra.parseUnaryExpression = parseUnaryExpression; - extra.parseVariableDeclaration = parseVariableDeclaration; - extra.parseVariableIdentifier = parseVariableIdentifier; - - parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression); - parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); - parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression); - parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression); - parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression); - parseBlock = wrapTracking(extra.parseBlock); - parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); - parseCatchClause = wrapTracking(extra.parseCatchClause); - parseComputedMember = wrapTracking(extra.parseComputedMember); - parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); - parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); - parseEqualityExpression = wrapTracking(extra.parseEqualityExpression); - parseExpression = wrapTracking(extra.parseExpression); - parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); - parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); - parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); - parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); - parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression); - parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression); - parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression); - parseNewExpression = wrapTracking(extra.parseNewExpression); - parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); - parseObjectProperty = wrapTracking(extra.parseObjectProperty); - parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); - parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); - parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); - parseProgram = wrapTracking(extra.parseProgram); - parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); - parseRelationalExpression = wrapTracking(extra.parseRelationalExpression); - parseStatement = wrapTracking(extra.parseStatement); - parseShiftExpression = wrapTracking(extra.parseShiftExpression); - parseSwitchCase = wrapTracking(extra.parseSwitchCase); - parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); - parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); - parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); - } - - if (typeof extra.tokens !== 'undefined') { - extra.advance = advance; - extra.scanRegExp = scanRegExp; - - advance = collectToken; - scanRegExp = collectRegex; - } - } - - function unpatch() { - if (typeof extra.skipComment === 'function') { - skipComment = extra.skipComment; - } - - if (extra.raw) { - createLiteral = extra.createLiteral; - } - - if (extra.range || extra.loc) { - parseAdditiveExpression = extra.parseAdditiveExpression; - parseAssignmentExpression = extra.parseAssignmentExpression; - parseBitwiseANDExpression = extra.parseBitwiseANDExpression; - parseBitwiseORExpression = extra.parseBitwiseORExpression; - parseBitwiseXORExpression = extra.parseBitwiseXORExpression; - parseBlock = extra.parseBlock; - parseFunctionSourceElements = extra.parseFunctionSourceElements; - parseCatchClause = extra.parseCatchClause; - parseComputedMember = extra.parseComputedMember; - parseConditionalExpression = extra.parseConditionalExpression; - parseConstLetDeclaration = extra.parseConstLetDeclaration; - parseEqualityExpression = extra.parseEqualityExpression; - parseExpression = extra.parseExpression; - parseForVariableDeclaration = extra.parseForVariableDeclaration; - parseFunctionDeclaration = extra.parseFunctionDeclaration; - parseFunctionExpression = extra.parseFunctionExpression; - parseGroupExpression = extra.parseGroupExpression; - parseLeftHandSideExpression = extra.parseLeftHandSideExpression; - parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; - parseLogicalANDExpression = extra.parseLogicalANDExpression; - parseLogicalORExpression = extra.parseLogicalORExpression; - parseMultiplicativeExpression = extra.parseMultiplicativeExpression; - parseNewExpression = extra.parseNewExpression; - parseNonComputedProperty = extra.parseNonComputedProperty; - parseObjectProperty = extra.parseObjectProperty; - parseObjectPropertyKey = extra.parseObjectPropertyKey; - parsePrimaryExpression = extra.parsePrimaryExpression; - parsePostfixExpression = extra.parsePostfixExpression; - parseProgram = extra.parseProgram; - parsePropertyFunction = extra.parsePropertyFunction; - parseRelationalExpression = extra.parseRelationalExpression; - parseStatement = extra.parseStatement; - parseShiftExpression = extra.parseShiftExpression; - parseSwitchCase = extra.parseSwitchCase; - parseUnaryExpression = extra.parseUnaryExpression; - parseVariableDeclaration = extra.parseVariableDeclaration; - parseVariableIdentifier = extra.parseVariableIdentifier; - } - - if (typeof extra.scanRegExp === 'function') { - advance = extra.advance; - scanRegExp = extra.scanRegExp; - } - } - - function stringToArray(str) { - var length = str.length, - result = [], - i; - for (i = 0; i < length; ++i) { - result[i] = str.charAt(i); - } - return result; + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; + } + return tokens; } function parse(code, options) { @@ -3805,25 +3658,32 @@ parseStatement: true, parseSourceElement: true */ code = toString(code); } + delegate = SyntaxTreeDelegate; source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; lineStart = 0; length = source.length; - buffer = null; + lookahead = null; state = { allowIn: true, labelSet: {}, inFunctionBody: false, inIteration: false, - inSwitch: false + inSwitch: false, + lastCommentStart: -1 }; extra = {}; if (typeof options !== 'undefined') { extra.range = (typeof options.range === 'boolean') && options.range; extra.loc = (typeof options.loc === 'boolean') && options.loc; - extra.raw = (typeof options.raw === 'boolean') && options.raw; + extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; + + if (extra.loc && options.source !== null && options.source !== undefined) { + extra.source = toString(options.source); + } + if (typeof options.tokens === 'boolean' && options.tokens) { extra.tokens = []; } @@ -3833,29 +3693,18 @@ parseStatement: true, parseSourceElement: true */ if (typeof options.tolerant === 'boolean' && options.tolerant) { extra.errors = []; } - } - - if (length > 0) { - if (typeof source[0] === 'undefined') { - // Try first to convert to a string. This is good as fast path - // for old IE which understands string indexing for string - // literals only and not for string object. - if (code instanceof String) { - source = code.valueOf(); - } - - // Force accessing the characters via an array. - if (typeof source[0] === 'undefined') { - source = stringToArray(code); - } + if (extra.attachComment) { + extra.range = true; + extra.comments = []; + extra.bottomRightStack = []; + extra.trailingComments = []; + extra.leadingComments = []; } } - patch(); try { program = parseProgram(); if (typeof extra.comments !== 'undefined') { - filterCommentLocation(); program.comments = extra.comments; } if (typeof extra.tokens !== 'undefined') { @@ -3865,25 +3714,24 @@ parseStatement: true, parseSourceElement: true */ if (typeof extra.errors !== 'undefined') { program.errors = extra.errors; } - if (extra.range || extra.loc) { - program.body = filterGroup(program.body); - } } catch (e) { throw e; } finally { - unpatch(); extra = {}; } return program; } - // Sync with package.json. - exports.version = '1.0.4'; + // Sync with *.json manifests. + exports.version = '1.2.2'; + + exports.tokenize = tokenize; exports.parse = parse; // Deep copy. + /* istanbul ignore next */ exports.Syntax = (function () { var name, types = {}; diff --git a/build/jslib/source-map/source-map-consumer.js b/build/jslib/source-map/source-map-consumer.js index 99f36c59..6d84d204 100644 --- a/build/jslib/source-map/source-map-consumer.js +++ b/build/jslib/source-map/source-map-consumer.js @@ -27,7 +27,7 @@ define(function (require, exports, module) { * - 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. + * - file: Optional. The generated file this source map is associated with. * * Here is an example source map, taken from the source map spec[0]: * @@ -311,7 +311,7 @@ define(function (require, exports, module) { "generatedColumn", util.compareByGeneratedPositions); - if (mapping) { + if (mapping && mapping.generatedLine === needle.generatedLine) { var source = util.getArg(mapping, 'source', null); if (source && this.sourceRoot) { source = util.join(this.sourceRoot, source); diff --git a/build/jslib/source-map/source-map-generator.js b/build/jslib/source-map/source-map-generator.js index 75c4c1ca..f0a315be 100644 --- a/build/jslib/source-map/source-map-generator.js +++ b/build/jslib/source-map/source-map-generator.js @@ -13,14 +13,17 @@ define(function (require, exports, module) { /** * 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: + * being built incrementally. You may 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. + * - sourceRoot: A root for all relative URLs in this source map. */ function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); + if (!aArgs) { + aArgs = {}; + } + this._file = util.getArg(aArgs, 'file', null); this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); this._sources = new ArraySet(); this._names = new ArraySet(); @@ -150,11 +153,23 @@ define(function (require, exports, module) { * @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 aSourceMapPath Optional. The dirname of the path to the source map + * to be applied. If relative, it is relative to the SourceMapConsumer. + * This parameter is needed when the two source maps aren't in the same + * directory, and the source map to be applied contains relative source + * paths. If so, those relative source paths need to be rewritten + * relative to the SourceMapGenerator. */ SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { // If aSourceFile is omitted, we will use the file property of the SourceMap if (!aSourceFile) { + if (!aSourceMapConsumer.file) { + throw new Error( + 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + + 'or the source map\'s "file" property. Both were omitted.' + ); + } aSourceFile = aSourceMapConsumer.file; } var sourceRoot = this._sourceRoot; @@ -177,10 +192,12 @@ define(function (require, exports, module) { }); if (original.source !== null) { // Copy mapping + mapping.source = original.source; + if (aSourceMapPath) { + mapping.source = util.join(aSourceMapPath, mapping.source) + } if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; + mapping.source = util.relative(sourceRoot, mapping.source); } mapping.originalLine = original.line; mapping.originalColumn = original.column; diff --git a/build/jslib/source-map/source-node.js b/build/jslib/source-map/source-node.js index 7a418170..b206c342 100644 --- a/build/jslib/source-map/source-node.js +++ b/build/jslib/source-map/source-node.js @@ -57,41 +57,16 @@ define(function (require, exports, module) { 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 { + if (lastMapping !== null) { // 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); + // Associate first line with "lastMapping" + addMappingWithCode(lastMapping, remainingLines.shift() + "\n"); + lastGeneratedLine++; + lastGeneratedColumn = 0; + // The remaining code is added without mapping } else { // There is no new line in between. // Associate the code between "lastGeneratedColumn" and @@ -103,14 +78,37 @@ define(function (require, exports, module) { lastGeneratedColumn); lastGeneratedColumn = mapping.generatedColumn; addMappingWithCode(lastMapping, code); + // No more remaining code, continue + lastMapping = mapping; + return; } } + // 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; + } 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")); + if (remainingLines.length > 0) { + if (lastMapping) { + // Associate the remaining code in the current line with "lastMapping" + var lastLine = remainingLines.shift(); + if (remainingLines.length > 0) lastLine += "\n"; + addMappingWithCode(lastMapping, lastLine); + } + // and add the remaining lines without any mapping + node.add(remainingLines.join("\n")); + } // Copy sourcesContent into SourceNode aSourceMapConsumer.sources.forEach(function (sourceFile) { @@ -348,10 +346,28 @@ define(function (require, exports, module) { lastOriginalSource = null; sourceMappingActive = false; } - chunk.split('').forEach(function (ch) { + chunk.split('').forEach(function (ch, idx, array) { if (ch === '\n') { generated.line++; generated.column = 0; + // Mappings end at eol + if (idx + 1 === array.length) { + lastOriginalSource = null; + sourceMappingActive = false; + } else if (sourceMappingActive) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } } else { generated.column++; } diff --git a/build/jslib/source-map/util.js b/build/jslib/source-map/util.js index 683c16e9..a4c53c22 100644 --- a/build/jslib/source-map/util.js +++ b/build/jslib/source-map/util.js @@ -28,8 +28,8 @@ define(function (require, exports, module) { } exports.getArg = getArg; - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - var dataUrlRegexp = /^data:.+\,.+/; + var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/; + var dataUrlRegexp = /^data:.+\,.+$/; function urlParse(aUrl) { var match = aUrl.match(urlRegexp); @@ -38,18 +38,22 @@ define(function (require, exports, module) { } return { scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] + auth: match[2], + host: match[3], + port: match[4], + path: match[5] }; } exports.urlParse = urlParse; function urlGenerate(aParsedUrl) { - var url = aParsedUrl.scheme + "://"; + var url = ''; + if (aParsedUrl.scheme) { + url += aParsedUrl.scheme + ':'; + } + url += '//'; if (aParsedUrl.auth) { - url += aParsedUrl.auth + "@" + url += aParsedUrl.auth + '@'; } if (aParsedUrl.host) { url += aParsedUrl.host; @@ -64,19 +68,112 @@ define(function (require, exports, module) { } exports.urlGenerate = urlGenerate; + /** + * Normalizes a path, or the path portion of a URL: + * + * - Replaces consequtive slashes with one slash. + * - Removes unnecessary '.' parts. + * - Removes unnecessary '/..' parts. + * + * Based on code in the Node.js 'path' core module. + * + * @param aPath The path or url to normalize. + */ + function normalize(aPath) { + var path = aPath; + var url = urlParse(aPath); + if (url) { + if (!url.path) { + return aPath; + } + path = url.path; + } + var isAbsolute = (path.charAt(0) === '/'); + + var parts = path.split(/\/+/); + for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { + part = parts[i]; + if (part === '.') { + parts.splice(i, 1); + } else if (part === '..') { + up++; + } else if (up > 0) { + if (part === '') { + // The first part is blank if the path is absolute. Trying to go + // above the root is a no-op. Therefore we can remove all '..' parts + // directly after the root. + parts.splice(i + 1, up); + up = 0; + } else { + parts.splice(i, 2); + up--; + } + } + } + path = parts.join('/'); + + if (path === '') { + path = isAbsolute ? '/' : '.'; + } + + if (url) { + url.path = path; + return urlGenerate(url); + } + return path; + } + exports.normalize = normalize; + + /** + * Joins two paths/URLs. + * + * @param aRoot The root path or URL. + * @param aPath The path or URL to be joined with the root. + * + * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a + * scheme-relative URL: Then the scheme of aRoot, if any, is prepended + * first. + * - Otherwise aPath is a path. If aRoot is a URL, then its path portion + * is updated with the result and aRoot is returned. Otherwise the result + * is returned. + * - If aPath is absolute, the result is aPath. + * - Otherwise the two paths are joined with a slash. + * - Joining for example 'http://' and 'www.example.com' is also supported. + */ function join(aRoot, aPath) { - var url; + var aPathUrl = urlParse(aPath); + var aRootUrl = urlParse(aRoot); + if (aRootUrl) { + aRoot = aRootUrl.path || '/'; + } + + // `join(foo, '//www.example.org')` + if (aPathUrl && !aPathUrl.scheme) { + if (aRootUrl) { + aPathUrl.scheme = aRootUrl.scheme; + } + return urlGenerate(aPathUrl); + } - if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + if (aPathUrl || aPath.match(dataUrlRegexp)) { return aPath; } - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); + // `join('http://', 'www.example.com')` + if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { + aRootUrl.host = aPath; + return urlGenerate(aRootUrl); } - return aRoot.replace(/\/$/, '') + '/' + aPath; + var joined = aPath.charAt(0) === '/' + ? aPath + : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); + + if (aRootUrl) { + aRootUrl.path = joined; + return urlGenerate(aRootUrl); + } + return joined; } exports.join = join; diff --git a/build/jslib/uglifyjs2.js b/build/jslib/uglifyjs2.js index 6201b8df..e11de335 100644 --- a/build/jslib/uglifyjs2.js +++ b/build/jslib/uglifyjs2.js @@ -3334,6 +3334,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){ node.mangled_name = name; return true; } + if (options.screw_ie8 && node instanceof AST_SymbolCatch) { + to_mangle.push(node.definition()); + return; + } }); this.walk(tw); to_mangle.forEach(function(def){ def.mangle(options) }); @@ -4895,6 +4899,7 @@ function Compressor(options, false_by_default) { loops : !false_by_default, unused : !false_by_default, hoist_funs : !false_by_default, + keep_fargs : false, hoist_vars : false, if_return : !false_by_default, join_vars : !false_by_default, @@ -5210,7 +5215,7 @@ merge(Compressor.prototype, { stat = stat.clone(); stat.condition = stat.condition.negate(compressor); stat.body = make_node(AST_BlockStatement, stat, { - body: ret + body: as_statement_array(stat.alternative).concat(ret) }); stat.alternative = make_node(AST_BlockStatement, stat, { body: body @@ -5878,18 +5883,20 @@ merge(Compressor.prototype, { var tt = new TreeTransformer( function before(node, descend, in_list) { if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { - for (var a = node.argnames, i = a.length; --i >= 0;) { - var sym = a[i]; - if (sym.unreferenced()) { - a.pop(); - compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", { - name : sym.name, - file : sym.start.file, - line : sym.start.line, - col : sym.start.col - }); + if (!compressor.option("keep_fargs")) { + for (var a = node.argnames, i = a.length; --i >= 0;) { + var sym = a[i]; + if (sym.unreferenced()) { + a.pop(); + compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", { + name : sym.name, + file : sym.start.file, + line : sym.start.line, + col : sym.start.col + }); + } + else break; } - else break; } } if (node instanceof AST_Defun && node !== self) { @@ -7130,6 +7137,19 @@ merge(Compressor.prototype, { return consequent; } } + // x?y?z:a:a --> x&&y?z:a + if (consequent instanceof AST_Conditional + && consequent.alternative.equivalent_to(alternative)) { + return make_node(AST_Conditional, self, { + condition: make_node(AST_Binary, self, { + left: self.condition, + operator: "&&", + right: consequent.condition + }), + consequent: consequent.consequent, + alternative: alternative + }); + } return self; }); @@ -7257,6 +7277,9 @@ function SourceMap(options) { line: orig_line, column: orig_col }); + if (info.source === null) { + return; + } source = info.source; orig_line = info.line; orig_col = info.column; @@ -7560,7 +7583,8 @@ exports.minify = function(files, options, name) { base54.reset(); // 1. parse - var toplevel = null; + var toplevel = null, + sourcesContent = {}; if (options.spidermonkey) { toplevel = AST_Node.from_mozilla_ast(files); @@ -7571,6 +7595,7 @@ exports.minify = function(files, options, name) { var code = options.fromString ? file : rjsFile.readFile(file, "utf8"); + sourcesContent[file] = code; toplevel = parse(code, { filename: options.fromString ? name : file, toplevel: toplevel @@ -7606,6 +7631,14 @@ exports.minify = function(files, options, name) { orig: inMap, root: options.sourceRoot }); + if (options.sourceMapIncludeSources) { + for (var file in sourcesContent) { + if (sourcesContent.hasOwnProperty(file)) { + options.source_map.get().setSourceContent(file, sourcesContent[file]); + } + } + } + } if (options.output) { merge(output, options.output); diff --git a/build/jslib/uglifyjs2/README.md b/build/jslib/uglifyjs2/README.md index bcb70e44..4c507a81 100644 --- a/build/jslib/uglifyjs2/README.md +++ b/build/jslib/uglifyjs2/README.md @@ -1,6 +1,6 @@ Sets up uglifyjs2 for use in the optimizer. -Current embedded version: 2.4.8, source-map 0.1.31 +Current embedded version: 2.4.13, source-map 0.1.33 Steps: diff --git a/build/jslib/x.js b/build/jslib/x.js index d369bab4..1651adb7 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -409,7 +409,7 @@ var requirejs, require, define, xpcUtil; } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.4.12, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.4.13, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); From 424ffd29432ad3de39bfbcae7695258db5e83110 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 19 May 2014 23:33:16 -0700 Subject: [PATCH 167/382] snapshot --- dist/r.js | 3937 +++++++++++++++++++++++++++-------------------------- 1 file changed, 1974 insertions(+), 1963 deletions(-) diff --git a/dist/r.js b/dist/r.js index 724497e0..43ad6b85 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Mon, 19 May 2014 19:09:30 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Tue, 20 May 2014 06:33:08 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Mon, 19 May 2014 19:09:30 GMT', + version = '2.1.11+ Tue, 20 May 2014 06:33:08 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -4494,6 +4494,9 @@ define('logger', ['env!env/print'], function (print) { //like Node's fs and path. /* + Copyright (C) 2013 Ariya Hidayat + Copyright (C) 2013 Thaddee Tyl + Copyright (C) 2013 Mathias Bynens Copyright (C) 2012 Ariya Hidayat Copyright (C) 2012 Mathias Bynens Copyright (C) 2012 Joost-Wim Boekesteijn @@ -4525,11 +4528,13 @@ define('logger', ['env!env/print'], function (print) { /*jslint bitwise:true plusplus:true */ /*global esprima:true, define:true, exports:true, window: true, -throwError: true, createLiteral: true, generateStatement: true, +throwErrorTolerant: true, +throwError: true, generateStatement: true, peek: true, parseAssignmentExpression: true, parseBlock: true, parseExpression: true, parseFunctionDeclaration: true, parseFunctionExpression: true, parseFunctionSourceElements: true, parseVariableIdentifier: true, parseLeftHandSideExpression: true, +parseUnaryExpression: true, parseStatement: true, parseSourceElement: true */ (function (root, factory) { @@ -4537,6 +4542,8 @@ parseStatement: true, parseSourceElement: true */ // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, // Rhino, and plain browser loading. + + /* istanbul ignore next */ if (typeof define === 'function' && define.amd) { define('esprima', ['exports'], factory); } else if (typeof exports !== 'undefined') { @@ -4549,17 +4556,20 @@ parseStatement: true, parseSourceElement: true */ var Token, TokenName, + FnExprTokens, Syntax, PropertyKind, Messages, Regex, + SyntaxTreeDelegate, source, strict, index, lineNumber, lineStart, length, - buffer, + delegate, + lookahead, state, extra; @@ -4571,7 +4581,8 @@ parseStatement: true, parseSourceElement: true */ NullLiteral: 5, NumericLiteral: 6, Punctuator: 7, - StringLiteral: 8 + StringLiteral: 8, + RegularExpression: 9 }; TokenName = {}; @@ -4583,6 +4594,18 @@ parseStatement: true, parseSourceElement: true */ TokenName[Token.NumericLiteral] = 'Numeric'; TokenName[Token.Punctuator] = 'Punctuator'; TokenName[Token.StringLiteral] = 'String'; + TokenName[Token.RegularExpression] = 'RegularExpression'; + + // A function following one of those tokens is an expression. + FnExprTokens = ['(', '{', '[', 'in', 'typeof', 'instanceof', 'new', + 'return', 'case', 'delete', 'throw', 'void', + // assignment operators + '=', '+=', '-=', '*=', '/=', '%=', '<<=', '>>=', '>>>=', + '&=', '|=', '^=', ',', + // binary/unary operators + '+', '-', '*', '/', '%', '++', '--', '<<', '>>', '>>>', '&', + '|', '^', '!', '~', '&&', '||', '?', ':', '===', '==', '>=', + '<=', '<', '>', '!=', '!==']; Syntax = { AssignmentExpression: 'AssignmentExpression', @@ -4672,8 +4695,8 @@ parseStatement: true, parseSourceElement: true */ // See also tools/generate-unicode-regex.py. Regex = { - NonAsciiIdentifierStart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]'), - NonAsciiIdentifierPart: new RegExp('[\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u309a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]') + NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), + NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') }; // Ensure the condition is true, otherwise throw an error. @@ -4682,23 +4705,14 @@ parseStatement: true, parseSourceElement: true */ // Do NOT use this to enforce a certain condition on any user input. function assert(condition, message) { + /* istanbul ignore if */ if (!condition) { throw new Error('ASSERT: ' + message); } } - function sliceSource(from, to) { - return source.slice(from, to); - } - - if (typeof 'esprima'[0] === 'undefined') { - sliceSource = function sliceArraySource(from, to) { - return source.slice(from, to).join(''); - }; - } - function isDecimalDigit(ch) { - return '0123456789'.indexOf(ch) >= 0; + return (ch >= 48 && ch <= 57); // 0..9 } function isHexDigit(ch) { @@ -4713,39 +4727,39 @@ parseStatement: true, parseSourceElement: true */ // 7.2 White Space function isWhiteSpace(ch) { - return (ch === ' ') || (ch === '\u0009') || (ch === '\u000B') || - (ch === '\u000C') || (ch === '\u00A0') || - (ch.charCodeAt(0) >= 0x1680 && - '\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\uFEFF'.indexOf(ch) >= 0); + return (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || + (ch >= 0x1680 && [0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF].indexOf(ch) >= 0); } // 7.3 Line Terminators function isLineTerminator(ch) { - return (ch === '\n' || ch === '\r' || ch === '\u2028' || ch === '\u2029'); + return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029); } // 7.6 Identifier Names and Identifiers function isIdentifierStart(ch) { - return (ch === '$') || (ch === '_') || (ch === '\\') || - (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierStart.test(ch)); + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))); } function isIdentifierPart(ch) { - return (ch === '$') || (ch === '_') || (ch === '\\') || - (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || - ((ch >= '0') && (ch <= '9')) || - ((ch.charCodeAt(0) >= 0x80) && Regex.NonAsciiIdentifierPart.test(ch)); + return (ch === 0x24) || (ch === 0x5F) || // $ (dollar) and _ (underscore) + (ch >= 0x41 && ch <= 0x5A) || // A..Z + (ch >= 0x61 && ch <= 0x7A) || // a..z + (ch >= 0x30 && ch <= 0x39) || // 0..9 + (ch === 0x5C) || // \ (backslash) + ((ch >= 0x80) && Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))); } // 7.6.1.2 Future Reserved Words function isFutureReservedWord(id) { switch (id) { - - // Future reserved words. case 'class': case 'enum': case 'export': @@ -4753,15 +4767,13 @@ parseStatement: true, parseSourceElement: true */ case 'import': case 'super': return true; + default: + return false; } - - return false; } function isStrictModeReservedWord(id) { switch (id) { - - // Strict Mode reserved words. case 'implements': case 'interface': case 'package': @@ -4772,9 +4784,9 @@ parseStatement: true, parseSourceElement: true */ case 'yield': case 'let': return true; + default: + return false; } - - return false; } function isRestrictedWord(id) { @@ -4784,125 +4796,215 @@ parseStatement: true, parseSourceElement: true */ // 7.6.1.1 Keywords function isKeyword(id) { - var keyword = false; + if (strict && isStrictModeReservedWord(id)) { + return true; + } + + // 'const' is specialized as Keyword in V8. + // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // Some others are from future reserved words. + switch (id.length) { case 2: - keyword = (id === 'if') || (id === 'in') || (id === 'do'); - break; + return (id === 'if') || (id === 'in') || (id === 'do'); case 3: - keyword = (id === 'var') || (id === 'for') || (id === 'new') || (id === 'try'); - break; + return (id === 'var') || (id === 'for') || (id === 'new') || + (id === 'try') || (id === 'let'); case 4: - keyword = (id === 'this') || (id === 'else') || (id === 'case') || (id === 'void') || (id === 'with'); - break; + return (id === 'this') || (id === 'else') || (id === 'case') || + (id === 'void') || (id === 'with') || (id === 'enum'); case 5: - keyword = (id === 'while') || (id === 'break') || (id === 'catch') || (id === 'throw'); - break; + return (id === 'while') || (id === 'break') || (id === 'catch') || + (id === 'throw') || (id === 'const') || (id === 'yield') || + (id === 'class') || (id === 'super'); case 6: - keyword = (id === 'return') || (id === 'typeof') || (id === 'delete') || (id === 'switch'); - break; + return (id === 'return') || (id === 'typeof') || (id === 'delete') || + (id === 'switch') || (id === 'export') || (id === 'import'); case 7: - keyword = (id === 'default') || (id === 'finally'); - break; + return (id === 'default') || (id === 'finally') || (id === 'extends'); case 8: - keyword = (id === 'function') || (id === 'continue') || (id === 'debugger'); - break; + return (id === 'function') || (id === 'continue') || (id === 'debugger'); case 10: - keyword = (id === 'instanceof'); - break; + return (id === 'instanceof'); + default: + return false; } + } - if (keyword) { - return true; - } + // 7.4 Comments - switch (id) { - // Future reserved words. - // 'const' is specialized as Keyword in V8. - case 'const': - return true; + function addComment(type, value, start, end, loc) { + var comment, attacher; - // For compatiblity to SpiderMonkey and ES.next - case 'yield': - case 'let': - return true; - } + assert(typeof start === 'number', 'Comment must have valid position'); - if (strict && isStrictModeReservedWord(id)) { - return true; + // Because the way the actual token is scanned, often the comments + // (if any) are skipped twice during the lexical analysis. + // Thus, we need to skip adding a comment if the comment array already + // handled it. + if (state.lastCommentStart >= start) { + return; } + state.lastCommentStart = start; - return isFutureReservedWord(id); + comment = { + type: type, + value: value + }; + if (extra.range) { + comment.range = [start, end]; + } + if (extra.loc) { + comment.loc = loc; + } + extra.comments.push(comment); + if (extra.attachComment) { + extra.leadingComments.push(comment); + extra.trailingComments.push(comment); + } } - // 7.4 Comments - - function skipComment() { - var ch, blockComment, lineComment; + function skipSingleLineComment(offset) { + var start, loc, ch, comment; - blockComment = false; - lineComment = false; + start = index - offset; + loc = { + start: { + line: lineNumber, + column: index - lineStart - offset + } + }; while (index < length) { - ch = source[index]; + ch = source.charCodeAt(index); + ++index; + if (isLineTerminator(ch)) { + if (extra.comments) { + comment = source.slice(start + offset, index - 1); + loc.end = { + line: lineNumber, + column: index - lineStart - 1 + }; + addComment('Line', comment, start, index - 1, loc); + } + if (ch === 13 && source.charCodeAt(index) === 10) { + ++index; + } + ++lineNumber; + lineStart = index; + return; + } + } - if (lineComment) { - ch = source[index++]; - if (isLineTerminator(ch)) { - lineComment = false; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - ++lineNumber; - lineStart = index; + if (extra.comments) { + comment = source.slice(start + offset, index); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Line', comment, start, index, loc); + } + } + + function skipMultiLineComment() { + var start, loc, ch, comment; + + if (extra.comments) { + start = index - 2; + loc = { + start: { + line: lineNumber, + column: index - lineStart - 2 } - } else if (blockComment) { - if (isLineTerminator(ch)) { - if (ch === '\r' && source[index + 1] === '\n') { - ++index; - } - ++lineNumber; + }; + } + + while (index < length) { + ch = source.charCodeAt(index); + if (isLineTerminator(ch)) { + if (ch === 0x0D && source.charCodeAt(index + 1) === 0x0A) { ++index; - lineStart = index; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - ch = source[index++]; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - if (ch === '*') { - ch = source[index]; - if (ch === '/') { - ++index; - blockComment = false; - } - } } - } else if (ch === '/') { - ch = source[index + 1]; - if (ch === '/') { - index += 2; - lineComment = true; - } else if (ch === '*') { - index += 2; - blockComment = true; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + ++lineNumber; + ++index; + lineStart = index; + if (index >= length) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + } else if (ch === 0x2A) { + // Block comment ends with '*/'. + if (source.charCodeAt(index + 1) === 0x2F) { + ++index; + ++index; + if (extra.comments) { + comment = source.slice(start + 2, index - 2); + loc.end = { + line: lineNumber, + column: index - lineStart + }; + addComment('Block', comment, start, index, loc); } - } else { - break; + return; } - } else if (isWhiteSpace(ch)) { + ++index; + } else { + ++index; + } + } + + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + function skipComment() { + var ch, start; + + start = (index === 0); + while (index < length) { + ch = source.charCodeAt(index); + + if (isWhiteSpace(ch)) { ++index; } else if (isLineTerminator(ch)) { ++index; - if (ch === '\r' && source[index] === '\n') { + if (ch === 0x0D && source.charCodeAt(index) === 0x0A) { ++index; } ++lineNumber; lineStart = index; + start = true; + } else if (ch === 0x2F) { // U+002F is '/' + ch = source.charCodeAt(index + 1); + if (ch === 0x2F) { + ++index; + ++index; + skipSingleLineComment(2); + start = true; + } else if (ch === 0x2A) { // U+002A is '*' + ++index; + ++index; + skipMultiLineComment(); + } else { + break; + } + } else if (start && ch === 0x2D) { // U+002D is '-' + // U+003E is '>' + if ((source.charCodeAt(index + 1) === 0x2D) && (source.charCodeAt(index + 2) === 0x3E)) { + // '-->' is a single-line comment + index += 3; + skipSingleLineComment(3); + } else { + break; + } + } else if (ch === 0x3C) { // U+003C is '<' + if (source.slice(index + 1, index + 4) === '!--') { + ++index; // `<` + ++index; // `!` + ++index; // `-` + ++index; // `-` + skipSingleLineComment(4); + } else { + break; + } } else { break; } @@ -4924,291 +5026,316 @@ parseStatement: true, parseSourceElement: true */ return String.fromCharCode(code); } - function scanIdentifier() { - var ch, start, id, restore; + function getEscapedIdentifier() { + var ch, id; - ch = source[index]; - if (!isIdentifierStart(ch)) { - return; - } + ch = source.charCodeAt(index++); + id = String.fromCharCode(ch); - start = index; - if (ch === '\\') { - ++index; - if (source[index] !== 'u') { - return; + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + if (source.charCodeAt(index) !== 0x75) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } ++index; - restore = index; ch = scanHexEscape('u'); - if (ch) { - if (ch === '\\' || !isIdentifierStart(ch)) { - return; - } - id = ch; - } else { - index = restore; - id = 'u'; + if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - } else { - id = source[index++]; + id = ch; } while (index < length) { - ch = source[index]; + ch = source.charCodeAt(index); if (!isIdentifierPart(ch)) { break; } - if (ch === '\\') { - ++index; - if (source[index] !== 'u') { - return; + ++index; + id += String.fromCharCode(ch); + + // '\u' (U+005C, U+0075) denotes an escaped character. + if (ch === 0x5C) { + id = id.substr(0, id.length - 1); + if (source.charCodeAt(index) !== 0x75) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } ++index; - restore = index; ch = scanHexEscape('u'); - if (ch) { - if (ch === '\\' || !isIdentifierPart(ch)) { - return; - } - id += ch; - } else { - index = restore; - id += 'u'; + if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - } else { - id += source[index++]; + id += ch; } } - // There is no keyword or literal with only one character. - // Thus, it must be an identifier. - if (id.length === 1) { - return { - type: Token.Identifier, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + return id; + } - if (isKeyword(id)) { - return { - type: Token.Keyword, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + function getIdentifier() { + var start, ch; + + start = index++; + while (index < length) { + ch = source.charCodeAt(index); + if (ch === 0x5C) { + // Blackslash (U+005C) marks Unicode escape sequence. + index = start; + return getEscapedIdentifier(); + } + if (isIdentifierPart(ch)) { + ++index; + } else { + break; + } } - // 7.8.1 Null Literals + return source.slice(start, index); + } - if (id === 'null') { - return { - type: Token.NullLiteral, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + function scanIdentifier() { + var start, id, type; - // 7.8.2 Boolean Literals + start = index; - if (id === 'true' || id === 'false') { - return { - type: Token.BooleanLiteral, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + // Backslash (U+005C) starts an escaped character. + id = (source.charCodeAt(index) === 0x5C) ? getEscapedIdentifier() : getIdentifier(); + + // There is no keyword or literal with only one character. + // Thus, it must be an identifier. + if (id.length === 1) { + type = Token.Identifier; + } else if (isKeyword(id)) { + type = Token.Keyword; + } else if (id === 'null') { + type = Token.NullLiteral; + } else if (id === 'true' || id === 'false') { + type = Token.BooleanLiteral; + } else { + type = Token.Identifier; } return { - type: Token.Identifier, + type: type, value: id, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } + // 7.7 Punctuators function scanPunctuator() { var start = index, + code = source.charCodeAt(index), + code2, ch1 = source[index], ch2, ch3, ch4; - // Check for most common single-character punctuators. + switch (code) { - if (ch1 === ';' || ch1 === '{' || ch1 === '}') { + // Check for most common single-character punctuators. + case 0x2E: // . dot + case 0x28: // ( open bracket + case 0x29: // ) close bracket + case 0x3B: // ; semicolon + case 0x2C: // , comma + case 0x7B: // { open curly brace + case 0x7D: // } close curly brace + case 0x5B: // [ + case 0x5D: // ] + case 0x3A: // : + case 0x3F: // ? + case 0x7E: // ~ ++index; + if (extra.tokenize) { + if (code === 0x28) { + extra.openParenToken = extra.tokens.length; + } else if (code === 0x7B) { + extra.openCurlyToken = extra.tokens.length; + } + } return { type: Token.Punctuator, - value: ch1, + value: String.fromCharCode(code), lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; + + default: + code2 = source.charCodeAt(index + 1); + + // '=' (U+003D) marks an assignment or comparison operator. + if (code2 === 0x3D) { + switch (code) { + case 0x2B: // + + case 0x2D: // - + case 0x2F: // / + case 0x3C: // < + case 0x3E: // > + case 0x5E: // ^ + case 0x7C: // | + case 0x25: // % + case 0x26: // & + case 0x2A: // * + index += 2; + return { + type: Token.Punctuator, + value: String.fromCharCode(code) + String.fromCharCode(code2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + + case 0x21: // ! + case 0x3D: // = + index += 2; + + // !== and === + if (source.charCodeAt(index) === 0x3D) { + ++index; + } + return { + type: Token.Punctuator, + value: source.slice(start, index), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + } } - if (ch1 === ',' || ch1 === '(' || ch1 === ')') { - ++index; + // 4-character punctuator: >>>= + + ch4 = source.substr(index, 4); + + if (ch4 === '>>>=') { + index += 4; return { type: Token.Punctuator, - value: ch1, + value: ch4, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - // Dot (.) can also start a floating-point number, hence the need - // to check the next character. + // 3-character punctuators: === !== >>> <<= >>= - ch2 = source[index + 1]; - if (ch1 === '.' && !isDecimalDigit(ch2)) { + ch3 = ch4.substr(0, 3); + + if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { + index += 3; return { type: Token.Punctuator, - value: source[index++], + value: ch3, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - // Peek more characters. - - ch3 = source[index + 2]; - ch4 = source[index + 3]; - - // 4-character punctuator: >>>= - - if (ch1 === '>' && ch2 === '>' && ch3 === '>') { - if (ch4 === '=') { - index += 4; - return { - type: Token.Punctuator, - value: '>>>=', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } - } - - // 3-character punctuators: === !== >>> <<= >>= + // Other 2-character punctuators: ++ -- << >> && || + ch2 = ch3.substr(0, 2); - if (ch1 === '=' && ch2 === '=' && ch3 === '=') { - index += 3; + if ((ch1 === ch2[1] && ('+-<>&|'.indexOf(ch1) >= 0)) || ch2 === '=>') { + index += 2; return { type: Token.Punctuator, - value: '===', + value: ch2, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - if (ch1 === '!' && ch2 === '=' && ch3 === '=') { - index += 3; + // 1-character punctuators: < > = ! + - * % & | ^ / + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { + ++index; return { type: Token.Punctuator, - value: '!==', + value: ch1, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - if (ch1 === '>' && ch2 === '>' && ch3 === '>') { - index += 3; - return { - type: Token.Punctuator, - value: '>>>', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + } + + // 7.8.3 Numeric Literals + + function scanHexLiteral(start) { + var number = ''; + + while (index < length) { + if (!isHexDigit(source[index])) { + break; + } + number += source[index++]; } - if (ch1 === '<' && ch2 === '<' && ch3 === '=') { - index += 3; - return { - type: Token.Punctuator, - value: '<<=', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + if (number.length === 0) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - if (ch1 === '>' && ch2 === '>' && ch3 === '=') { - index += 3; - return { - type: Token.Punctuator, - value: '>>=', - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - // 2-character punctuators: <= >= == != ++ -- << >> && || - // += -= *= %= &= |= ^= /= + return { + type: Token.NumericLiteral, + value: parseInt('0x' + number, 16), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } - if (ch2 === '=') { - if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { - index += 2; - return { - type: Token.Punctuator, - value: ch1 + ch2, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + function scanOctalLiteral(start) { + var number = '0' + source[index++]; + while (index < length) { + if (!isOctalDigit(source[index])) { + break; } + number += source[index++]; } - if (ch1 === ch2 && ('+-<>&|'.indexOf(ch1) >= 0)) { - if ('+-<>&|'.indexOf(ch2) >= 0) { - index += 2; - return { - type: Token.Punctuator, - value: ch1 + ch2, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } - // The remaining 1-character punctuators. - - if ('[]<>+-*%&|^!~?:=/'.indexOf(ch1) >= 0) { - return { - type: Token.Punctuator, - value: source[index++], - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } + return { + type: Token.NumericLiteral, + value: parseInt(number, 8), + octal: true, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; } - // 7.8.3 Numeric Literals - function scanNumericLiteral() { var number, start, ch; ch = source[index]; - assert(isDecimalDigit(ch) || (ch === '.'), + assert(isDecimalDigit(ch.charCodeAt(0)) || (ch === '.'), 'Numeric literal must start with a decimal digit or a decimal point'); start = index; @@ -5221,83 +5348,31 @@ parseStatement: true, parseSourceElement: true */ // Octal number starts with '0'. if (number === '0') { if (ch === 'x' || ch === 'X') { - number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isHexDigit(ch)) { - break; - } - number += source[index++]; - } - - if (number.length <= 2) { - // only 0x - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch)) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - return { - type: Token.NumericLiteral, - value: parseInt(number, 16), - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; - } else if (isOctalDigit(ch)) { - number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isOctalDigit(ch)) { - break; - } - number += source[index++]; - } - - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch) || isDecimalDigit(ch)) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - return { - type: Token.NumericLiteral, - value: parseInt(number, 8), - octal: true, - lineNumber: lineNumber, - lineStart: lineStart, - range: [start, index] - }; + ++index; + return scanHexLiteral(start); + } + if (isOctalDigit(ch)) { + return scanOctalLiteral(start); } // decimal number starts with '0' such as '09' is illegal. - if (isDecimalDigit(ch)) { + if (ch && isDecimalDigit(ch.charCodeAt(0))) { throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } } - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } + while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } + ch = source[index]; } if (ch === '.') { number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } + while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } + ch = source[index]; } if (ch === 'e' || ch === 'E') { @@ -5307,31 +5382,17 @@ parseStatement: true, parseSourceElement: true */ if (ch === '+' || ch === '-') { number += source[index++]; } - - ch = source[index]; - if (isDecimalDigit(ch)) { - number += source[index++]; - while (index < length) { - ch = source[index]; - if (!isDecimalDigit(ch)) { - break; - } + if (isDecimalDigit(source.charCodeAt(index))) { + while (isDecimalDigit(source.charCodeAt(index))) { number += source[index++]; } } else { - ch = 'character ' + ch; - if (index >= length) { - ch = ''; - } throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } } - if (index < length) { - ch = source[index]; - if (isIdentifierStart(ch)) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } + if (isIdentifierStart(source.charCodeAt(index))) { + throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); } return { @@ -5339,14 +5400,17 @@ parseStatement: true, parseSourceElement: true */ value: parseFloat(number), lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } // 7.8.4 String Literals function scanStringLiteral() { - var str = '', quote, start, ch, code, unescaped, restore, octal = false; + var str = '', quote, start, ch, code, unescaped, restore, octal = false, startLineNumber, startLineStart; + startLineNumber = lineNumber; + startLineStart = lineStart; quote = source[index]; assert((quote === '\'' || quote === '"'), @@ -5363,17 +5427,8 @@ parseStatement: true, parseSourceElement: true */ break; } else if (ch === '\\') { ch = source[index++]; - if (!isLineTerminator(ch)) { + if (!ch || !isLineTerminator(ch.charCodeAt(0))) { switch (ch) { - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; case 'u': case 'x': restore = index; @@ -5385,6 +5440,15 @@ parseStatement: true, parseSourceElement: true */ str += ch; } break; + case 'n': + str += '\n'; + break; + case 'r': + str += '\r'; + break; + case 't': + str += '\t'; + break; case 'b': str += '\b'; break; @@ -5427,8 +5491,9 @@ parseStatement: true, parseSourceElement: true */ if (ch === '\r' && source[index] === '\n') { ++index; } + lineStart = index; } - } else if (isLineTerminator(ch)) { + } else if (isLineTerminator(ch.charCodeAt(0))) { break; } else { str += ch; @@ -5443,33 +5508,46 @@ parseStatement: true, parseSourceElement: true */ type: Token.StringLiteral, value: str, octal: octal, + startLineNumber: startLineNumber, + startLineStart: startLineStart, lineNumber: lineNumber, lineStart: lineStart, - range: [start, index] + start: start, + end: index }; } - function scanRegExp() { - var str, ch, start, pattern, flags, value, classMarker = false, restore, terminated = false; + function testRegExp(pattern, flags) { + var value; + try { + value = new RegExp(pattern, flags); + } catch (e) { + throwError({}, Messages.InvalidRegExp); + } + return value; + } - buffer = null; - skipComment(); + function scanRegExpBody() { + var ch, str, classMarker, terminated, body; - start = index; ch = source[index]; assert(ch === '/', 'Regular expression literal must start with a slash'); str = source[index++]; + classMarker = false; + terminated = false; while (index < length) { ch = source[index++]; str += ch; if (ch === '\\') { ch = source[index++]; // ECMA-262 7.8.5 - if (isLineTerminator(ch)) { + if (isLineTerminator(ch.charCodeAt(0))) { throwError({}, Messages.UnterminatedRegExp); } str += ch; + } else if (isLineTerminator(ch.charCodeAt(0))) { + throwError({}, Messages.UnterminatedRegExp); } else if (classMarker) { if (ch === ']') { classMarker = false; @@ -5480,8 +5558,6 @@ parseStatement: true, parseSourceElement: true */ break; } else if (ch === '[') { classMarker = true; - } else if (isLineTerminator(ch)) { - throwError({}, Messages.UnterminatedRegExp); } } } @@ -5491,12 +5567,21 @@ parseStatement: true, parseSourceElement: true */ } // Exclude leading and trailing slash. - pattern = str.substr(1, str.length - 2); + body = str.substr(1, str.length - 2); + return { + value: body, + literal: str + }; + } + + function scanRegExpFlags() { + var ch, str, flags, restore; + str = ''; flags = ''; while (index < length) { ch = source[index]; - if (!isIdentifierPart(ch)) { + if (!isIdentifierPart(ch.charCodeAt(0))) { break; } @@ -5509,8 +5594,7 @@ parseStatement: true, parseSourceElement: true */ ch = scanHexEscape('u'); if (ch) { flags += ch; - str += '\\u'; - for (; restore < index; ++restore) { + for (str += '\\u'; restore < index; ++restore) { str += source[restore]; } } else { @@ -5518,8 +5602,10 @@ parseStatement: true, parseSourceElement: true */ flags += 'u'; str += '\\u'; } + throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); } else { str += '\\'; + throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); } } else { flags += ch; @@ -5527,17 +5613,82 @@ parseStatement: true, parseSourceElement: true */ } } - try { - value = new RegExp(pattern, flags); - } catch (e) { - throwError({}, Messages.InvalidRegExp); + return { + value: flags, + literal: str + }; + } + + function scanRegExp() { + var start, body, flags, pattern, value; + + lookahead = null; + skipComment(); + start = index; + + body = scanRegExpBody(); + flags = scanRegExpFlags(); + value = testRegExp(body.value, flags.value); + + if (extra.tokenize) { + return { + type: Token.RegularExpression, + value: value, + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; } return { - literal: str, + literal: body.literal + flags.literal, value: value, - range: [start, index] + start: start, + end: index + }; + } + + function collectRegex() { + var pos, loc, regex, token; + + skipComment(); + + pos = index; + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + regex = scanRegExp(); + loc.end = { + line: lineNumber, + column: index - lineStart }; + + /* istanbul ignore next */ + if (!extra.tokenize) { + // Pop the previous token, which is likely '/' or '/=' + if (extra.tokens.length > 0) { + token = extra.tokens[extra.tokens.length - 1]; + if (token.range[0] === pos && token.type === 'Punctuator') { + if (token.value === '/' || token.value === '/=') { + extra.tokens.pop(); + } + } + } + + extra.tokens.push({ + type: 'RegularExpression', + value: regex.literal, + range: [pos, index], + loc: loc + }); + } + + return regex; } function isIdentifierName(token) { @@ -5547,8 +5698,71 @@ parseStatement: true, parseSourceElement: true */ token.type === Token.NullLiteral; } + function advanceSlash() { + var prevToken, + checkToken; + // Using the following algorithm: + // https://github.com/mozilla/sweet.js/wiki/design + prevToken = extra.tokens[extra.tokens.length - 1]; + if (!prevToken) { + // Nothing before that: it cannot be a division. + return collectRegex(); + } + if (prevToken.type === 'Punctuator') { + if (prevToken.value === ']') { + return scanPunctuator(); + } + if (prevToken.value === ')') { + checkToken = extra.tokens[extra.openParenToken - 1]; + if (checkToken && + checkToken.type === 'Keyword' && + (checkToken.value === 'if' || + checkToken.value === 'while' || + checkToken.value === 'for' || + checkToken.value === 'with')) { + return collectRegex(); + } + return scanPunctuator(); + } + if (prevToken.value === '}') { + // Dividing a function by anything makes little sense, + // but we have to check for that. + if (extra.tokens[extra.openCurlyToken - 3] && + extra.tokens[extra.openCurlyToken - 3].type === 'Keyword') { + // Anonymous function. + checkToken = extra.tokens[extra.openCurlyToken - 4]; + if (!checkToken) { + return scanPunctuator(); + } + } else if (extra.tokens[extra.openCurlyToken - 4] && + extra.tokens[extra.openCurlyToken - 4].type === 'Keyword') { + // Named function. + checkToken = extra.tokens[extra.openCurlyToken - 5]; + if (!checkToken) { + return collectRegex(); + } + } else { + return scanPunctuator(); + } + // checkToken determines whether the function is + // a declaration or an expression. + if (FnExprTokens.indexOf(checkToken.value) >= 0) { + // It is an expression. + return scanPunctuator(); + } + // It is a declaration. + return collectRegex(); + } + return collectRegex(); + } + if (prevToken.type === 'Keyword') { + return collectRegex(); + } + return scanPunctuator(); + } + function advance() { - var ch, token; + var ch; skipComment(); @@ -5557,82 +5771,542 @@ parseStatement: true, parseSourceElement: true */ type: Token.EOF, lineNumber: lineNumber, lineStart: lineStart, - range: [index, index] + start: index, + end: index }; } - token = scanPunctuator(); - if (typeof token !== 'undefined') { - return token; + ch = source.charCodeAt(index); + + if (isIdentifierStart(ch)) { + return scanIdentifier(); } - ch = source[index]; + // Very common: ( and ) and ; + if (ch === 0x28 || ch === 0x29 || ch === 0x3B) { + return scanPunctuator(); + } - if (ch === '\'' || ch === '"') { + // String literal starts with single quote (U+0027) or double quote (U+0022). + if (ch === 0x27 || ch === 0x22) { return scanStringLiteral(); } - if (ch === '.' || isDecimalDigit(ch)) { + + // Dot (.) U+002E can also start a floating-point number, hence the need + // to check the next character. + if (ch === 0x2E) { + if (isDecimalDigit(source.charCodeAt(index + 1))) { + return scanNumericLiteral(); + } + return scanPunctuator(); + } + + if (isDecimalDigit(ch)) { return scanNumericLiteral(); } - token = scanIdentifier(); - if (typeof token !== 'undefined') { - return token; + // Slash (/) U+002F can also start a regex. + if (extra.tokenize && ch === 0x2F) { + return advanceSlash(); } - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + return scanPunctuator(); } - function lex() { - var token; + function collectToken() { + var loc, token, range, value; + + skipComment(); + loc = { + start: { + line: lineNumber, + column: index - lineStart + } + }; + + token = advance(); + loc.end = { + line: lineNumber, + column: index - lineStart + }; - if (buffer) { - index = buffer.range[1]; - lineNumber = buffer.lineNumber; - lineStart = buffer.lineStart; - token = buffer; - buffer = null; - return token; + if (token.type !== Token.EOF) { + value = source.slice(token.start, token.end); + extra.tokens.push({ + type: TokenName[token.type], + value: value, + range: [token.start, token.end], + loc: loc + }); } - buffer = null; - return advance(); + return token; } - function lookahead() { - var pos, line, start; + function lex() { + var token; - if (buffer !== null) { - return buffer; - } + token = lookahead; + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; - pos = index; - line = lineNumber; - start = lineStart; - buffer = advance(); - index = pos; - lineNumber = line; - lineStart = start; + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); - return buffer; - } + index = token.end; + lineNumber = token.lineNumber; + lineStart = token.lineStart; - // Return true if there is a line terminator before the next token. + return token; + } - function peekLineTerminator() { - var pos, line, start, found; + function peek() { + var pos, line, start; pos = index; line = lineNumber; start = lineStart; - skipComment(); - found = lineNumber !== line; + lookahead = (typeof extra.tokens !== 'undefined') ? collectToken() : advance(); index = pos; lineNumber = line; lineStart = start; + } - return found; + function Position(line, column) { + this.line = line; + this.column = column; + } + + function SourceLocation(startLine, startColumn, line, column) { + this.start = new Position(startLine, startColumn); + this.end = new Position(line, column); + } + + SyntaxTreeDelegate = { + + name: 'SyntaxTree', + + processComment: function (node) { + var lastChild, trailingComments; + + if (node.type === Syntax.Program) { + if (node.body.length > 0) { + return; + } + } + + if (extra.trailingComments.length > 0) { + if (extra.trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.trailingComments; + extra.trailingComments = []; + } else { + extra.trailingComments.length = 0; + } + } else { + if (extra.bottomRightStack.length > 0 && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && + extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { + trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + } + } + + // Eating the stack. + while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { + lastChild = extra.bottomRightStack.pop(); + } + + if (lastChild) { + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = lastChild.leadingComments; + delete lastChild.leadingComments; + } + } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { + node.leadingComments = extra.leadingComments; + extra.leadingComments = []; + } + + + if (trailingComments) { + node.trailingComments = trailingComments; + } + + extra.bottomRightStack.push(node); + }, + + markEnd: function (node, startToken) { + if (extra.range) { + node.range = [startToken.start, index]; + } + if (extra.loc) { + node.loc = new SourceLocation( + startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber, + startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart), + lineNumber, + index - lineStart + ); + this.postProcess(node); + } + + if (extra.attachComment) { + this.processComment(node); + } + return node; + }, + + postProcess: function (node) { + if (extra.source) { + node.loc.source = extra.source; + } + return node; + }, + + createArrayExpression: function (elements) { + return { + type: Syntax.ArrayExpression, + elements: elements + }; + }, + + createAssignmentExpression: function (operator, left, right) { + return { + type: Syntax.AssignmentExpression, + operator: operator, + left: left, + right: right + }; + }, + + createBinaryExpression: function (operator, left, right) { + var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : + Syntax.BinaryExpression; + return { + type: type, + operator: operator, + left: left, + right: right + }; + }, + + createBlockStatement: function (body) { + return { + type: Syntax.BlockStatement, + body: body + }; + }, + + createBreakStatement: function (label) { + return { + type: Syntax.BreakStatement, + label: label + }; + }, + + createCallExpression: function (callee, args) { + return { + type: Syntax.CallExpression, + callee: callee, + 'arguments': args + }; + }, + + createCatchClause: function (param, body) { + return { + type: Syntax.CatchClause, + param: param, + body: body + }; + }, + + createConditionalExpression: function (test, consequent, alternate) { + return { + type: Syntax.ConditionalExpression, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createContinueStatement: function (label) { + return { + type: Syntax.ContinueStatement, + label: label + }; + }, + + createDebuggerStatement: function () { + return { + type: Syntax.DebuggerStatement + }; + }, + + createDoWhileStatement: function (body, test) { + return { + type: Syntax.DoWhileStatement, + body: body, + test: test + }; + }, + + createEmptyStatement: function () { + return { + type: Syntax.EmptyStatement + }; + }, + + createExpressionStatement: function (expression) { + return { + type: Syntax.ExpressionStatement, + expression: expression + }; + }, + + createForStatement: function (init, test, update, body) { + return { + type: Syntax.ForStatement, + init: init, + test: test, + update: update, + body: body + }; + }, + + createForInStatement: function (left, right, body) { + return { + type: Syntax.ForInStatement, + left: left, + right: right, + body: body, + each: false + }; + }, + + createFunctionDeclaration: function (id, params, defaults, body) { + return { + type: Syntax.FunctionDeclaration, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createFunctionExpression: function (id, params, defaults, body) { + return { + type: Syntax.FunctionExpression, + id: id, + params: params, + defaults: defaults, + body: body, + rest: null, + generator: false, + expression: false + }; + }, + + createIdentifier: function (name) { + return { + type: Syntax.Identifier, + name: name + }; + }, + + createIfStatement: function (test, consequent, alternate) { + return { + type: Syntax.IfStatement, + test: test, + consequent: consequent, + alternate: alternate + }; + }, + + createLabeledStatement: function (label, body) { + return { + type: Syntax.LabeledStatement, + label: label, + body: body + }; + }, + + createLiteral: function (token) { + return { + type: Syntax.Literal, + value: token.value, + raw: source.slice(token.start, token.end) + }; + }, + + createMemberExpression: function (accessor, object, property) { + return { + type: Syntax.MemberExpression, + computed: accessor === '[', + object: object, + property: property + }; + }, + + createNewExpression: function (callee, args) { + return { + type: Syntax.NewExpression, + callee: callee, + 'arguments': args + }; + }, + + createObjectExpression: function (properties) { + return { + type: Syntax.ObjectExpression, + properties: properties + }; + }, + + createPostfixExpression: function (operator, argument) { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: false + }; + }, + + createProgram: function (body) { + return { + type: Syntax.Program, + body: body + }; + }, + + createProperty: function (kind, key, value) { + return { + type: Syntax.Property, + key: key, + value: value, + kind: kind + }; + }, + + createReturnStatement: function (argument) { + return { + type: Syntax.ReturnStatement, + argument: argument + }; + }, + + createSequenceExpression: function (expressions) { + return { + type: Syntax.SequenceExpression, + expressions: expressions + }; + }, + + createSwitchCase: function (test, consequent) { + return { + type: Syntax.SwitchCase, + test: test, + consequent: consequent + }; + }, + + createSwitchStatement: function (discriminant, cases) { + return { + type: Syntax.SwitchStatement, + discriminant: discriminant, + cases: cases + }; + }, + + createThisExpression: function () { + return { + type: Syntax.ThisExpression + }; + }, + + createThrowStatement: function (argument) { + return { + type: Syntax.ThrowStatement, + argument: argument + }; + }, + + createTryStatement: function (block, guardedHandlers, handlers, finalizer) { + return { + type: Syntax.TryStatement, + block: block, + guardedHandlers: guardedHandlers, + handlers: handlers, + finalizer: finalizer + }; + }, + + createUnaryExpression: function (operator, argument) { + if (operator === '++' || operator === '--') { + return { + type: Syntax.UpdateExpression, + operator: operator, + argument: argument, + prefix: true + }; + } + return { + type: Syntax.UnaryExpression, + operator: operator, + argument: argument, + prefix: true + }; + }, + + createVariableDeclaration: function (declarations, kind) { + return { + type: Syntax.VariableDeclaration, + declarations: declarations, + kind: kind + }; + }, + + createVariableDeclarator: function (id, init) { + return { + type: Syntax.VariableDeclarator, + id: id, + init: init + }; + }, + + createWhileStatement: function (test, body) { + return { + type: Syntax.WhileStatement, + test: test, + body: body + }; + }, + + createWithStatement: function (object, body) { + return { + type: Syntax.WithStatement, + object: object, + body: body + }; + } + }; + + // Return true if there is a line terminator before the next token. + + function peekLineTerminator() { + var pos, line, start, found; + + pos = index; + line = lineNumber; + start = lineStart; + skipComment(); + found = lineNumber !== line; + index = pos; + lineNumber = line; + lineStart = start; + + return found; } // Throw an exception @@ -5643,15 +6317,16 @@ parseStatement: true, parseSourceElement: true */ msg = messageFormat.replace( /%(\d)/g, function (whole, index) { - return args[index] || ''; + assert(index < args.length, 'Message reference must be in range'); + return args[index]; } ); if (typeof token.lineNumber === 'number') { error = new Error('Line ' + token.lineNumber + ': ' + msg); - error.index = token.range[0]; + error.index = token.start; error.lineNumber = token.lineNumber; - error.column = token.range[0] - lineStart + 1; + error.column = token.start - lineStart + 1; } else { error = new Error('Line ' + lineNumber + ': ' + msg); error.index = index; @@ -5659,6 +6334,7 @@ parseStatement: true, parseSourceElement: true */ error.column = index - lineStart + 1; } + error.description = msg; throw error; } @@ -5731,26 +6407,24 @@ parseStatement: true, parseSourceElement: true */ // Return true if the next token matches the specified punctuator. function match(value) { - var token = lookahead(); - return token.type === Token.Punctuator && token.value === value; + return lookahead.type === Token.Punctuator && lookahead.value === value; } // Return true if the next token matches the specified keyword function matchKeyword(keyword) { - var token = lookahead(); - return token.type === Token.Keyword && token.value === keyword; + return lookahead.type === Token.Keyword && lookahead.value === keyword; } // Return true if the next token is an assignment operator function matchAssign() { - var token = lookahead(), - op = token.value; + var op; - if (token.type !== Token.Punctuator) { + if (lookahead.type !== Token.Punctuator) { return false; } + op = lookahead.value; return op === '=' || op === '*=' || op === '/=' || @@ -5766,10 +6440,10 @@ parseStatement: true, parseSourceElement: true */ } function consumeSemicolon() { - var token, line; + var line; - // Catch the very common case first. - if (source[index] === ';') { + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B || match(';')) { lex(); return; } @@ -5780,14 +6454,8 @@ parseStatement: true, parseSourceElement: true */ return; } - if (match(';')) { - lex(); - return; - } - - token = lookahead(); - if (token.type !== Token.EOF && !match('}')) { - throwUnexpected(token); + if (lookahead.type !== Token.EOF && !match('}')) { + throwUnexpected(lookahead); } } @@ -5800,8 +6468,9 @@ parseStatement: true, parseSourceElement: true */ // 11.1.4 Array Initialiser function parseArrayInitialiser() { - var elements = []; + var elements = [], startToken; + startToken = lookahead; expect('['); while (!match(']')) { @@ -5817,40 +6486,31 @@ parseStatement: true, parseSourceElement: true */ } } - expect(']'); + lex(); - return { - type: Syntax.ArrayExpression, - elements: elements - }; + return delegate.markEnd(delegate.createArrayExpression(elements), startToken); } // 11.1.5 Object Initialiser function parsePropertyFunction(param, first) { - var previousStrict, body; + var previousStrict, body, startToken; previousStrict = strict; + startToken = lookahead; body = parseFunctionSourceElements(); if (first && strict && isRestrictedWord(param[0].name)) { throwErrorTolerant(first, Messages.StrictParamName); } strict = previousStrict; - - return { - type: Syntax.FunctionExpression, - id: null, - params: param, - defaults: [], - body: body, - rest: null, - generator: false, - expression: false - }; + return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken); } function parseObjectPropertyKey() { - var token = lex(); + var token, startToken; + + startToken = lookahead; + token = lex(); // Note: This function is called only from parseObjectProperty(), where // EOF and Punctuator tokens are already filtered out. @@ -5859,19 +6519,17 @@ parseStatement: true, parseSourceElement: true */ if (strict && token.octal) { throwErrorTolerant(token, Messages.StrictOctalLiteral); } - return createLiteral(token); + return delegate.markEnd(delegate.createLiteral(token), startToken); } - return { - type: Syntax.Identifier, - name: token.value - }; + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); } function parseObjectProperty() { - var token, key, id, param; + var token, key, id, value, param, startToken; - token = lookahead(); + token = lookahead; + startToken = lookahead; if (token.type === Token.Identifier) { @@ -5883,60 +6541,42 @@ parseStatement: true, parseSourceElement: true */ key = parseObjectPropertyKey(); expect('('); expect(')'); - return { - type: Syntax.Property, - key: key, - value: parsePropertyFunction([]), - kind: 'get' - }; - } else if (token.value === 'set' && !match(':')) { + value = parsePropertyFunction([]); + return delegate.markEnd(delegate.createProperty('get', key, value), startToken); + } + if (token.value === 'set' && !match(':')) { key = parseObjectPropertyKey(); expect('('); - token = lookahead(); + token = lookahead; if (token.type !== Token.Identifier) { expect(')'); throwErrorTolerant(token, Messages.UnexpectedToken, token.value); - return { - type: Syntax.Property, - key: key, - value: parsePropertyFunction([]), - kind: 'set' - }; + value = parsePropertyFunction([]); } else { param = [ parseVariableIdentifier() ]; expect(')'); - return { - type: Syntax.Property, - key: key, - value: parsePropertyFunction(param, token), - kind: 'set' - }; + value = parsePropertyFunction(param, token); } - } else { - expect(':'); - return { - type: Syntax.Property, - key: id, - value: parseAssignmentExpression(), - kind: 'init' - }; + return delegate.markEnd(delegate.createProperty('set', key, value), startToken); } - } else if (token.type === Token.EOF || token.type === Token.Punctuator) { + expect(':'); + value = parseAssignmentExpression(); + return delegate.markEnd(delegate.createProperty('init', id, value), startToken); + } + if (token.type === Token.EOF || token.type === Token.Punctuator) { throwUnexpected(token); } else { key = parseObjectPropertyKey(); expect(':'); - return { - type: Syntax.Property, - key: key, - value: parseAssignmentExpression(), - kind: 'init' - }; + value = parseAssignmentExpression(); + return delegate.markEnd(delegate.createProperty('init', key, value), startToken); } } function parseObjectInitialiser() { - var properties = [], property, name, kind, map = {}, toString = String; + var properties = [], property, name, key, kind, map = {}, toString = String, startToken; + + startToken = lookahead; expect('{'); @@ -5949,8 +6589,10 @@ parseStatement: true, parseSourceElement: true */ name = toString(property.key.value); } kind = (property.kind === 'init') ? PropertyKind.Data : (property.kind === 'get') ? PropertyKind.Get : PropertyKind.Set; - if (Object.prototype.hasOwnProperty.call(map, name)) { - if (map[name] === PropertyKind.Data) { + + key = '$' + name; + if (Object.prototype.hasOwnProperty.call(map, key)) { + if (map[key] === PropertyKind.Data) { if (strict && kind === PropertyKind.Data) { throwErrorTolerant({}, Messages.StrictDuplicateProperty); } else if (kind !== PropertyKind.Data) { @@ -5959,13 +6601,13 @@ parseStatement: true, parseSourceElement: true */ } else { if (kind === PropertyKind.Data) { throwErrorTolerant({}, Messages.AccessorDataProperty); - } else if (map[name] & kind) { + } else if (map[key] & kind) { throwErrorTolerant({}, Messages.AccessorGetSet); } } - map[name] |= kind; + map[key] |= kind; } else { - map[name] = kind; + map[key] = kind; } properties.push(property); @@ -5977,10 +6619,7 @@ parseStatement: true, parseSourceElement: true */ expect('}'); - return { - type: Syntax.ObjectExpression, - properties: properties - }; + return delegate.markEnd(delegate.createObjectExpression(properties), startToken); } // 11.1.6 The Grouping Operator @@ -6001,46 +6640,10 @@ parseStatement: true, parseSourceElement: true */ // 11.1 Primary Expressions function parsePrimaryExpression() { - var token = lookahead(), - type = token.type; - - if (type === Token.Identifier) { - return { - type: Syntax.Identifier, - name: lex().value - }; - } - - if (type === Token.StringLiteral || type === Token.NumericLiteral) { - if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); - } - return createLiteral(lex()); - } - - if (type === Token.Keyword) { - if (matchKeyword('this')) { - lex(); - return { - type: Syntax.ThisExpression - }; - } + var type, token, expr, startToken; - if (matchKeyword('function')) { - return parseFunctionExpression(); - } - } - - if (type === Token.BooleanLiteral) { - lex(); - token.value = (token.value === 'true'); - return createLiteral(token); - } - - if (type === Token.NullLiteral) { - lex(); - token.value = null; - return createLiteral(token); + if (match('(')) { + return parseGroupExpression(); } if (match('[')) { @@ -6051,15 +6654,46 @@ parseStatement: true, parseSourceElement: true */ return parseObjectInitialiser(); } - if (match('(')) { - return parseGroupExpression(); - } + type = lookahead.type; + startToken = lookahead; - if (match('/') || match('/=')) { - return createLiteral(scanRegExp()); + if (type === Token.Identifier) { + expr = delegate.createIdentifier(lex().value); + } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { + if (strict && lookahead.octal) { + throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + } + expr = delegate.createLiteral(lex()); + } else if (type === Token.Keyword) { + if (matchKeyword('function')) { + return parseFunctionExpression(); + } + if (matchKeyword('this')) { + lex(); + expr = delegate.createThisExpression(); + } else { + throwUnexpected(lex()); + } + } else if (type === Token.BooleanLiteral) { + token = lex(); + token.value = (token.value === 'true'); + expr = delegate.createLiteral(token); + } else if (type === Token.NullLiteral) { + token = lex(); + token.value = null; + expr = delegate.createLiteral(token); + } else if (match('/') || match('/=')) { + if (typeof extra.tokens !== 'undefined') { + expr = delegate.createLiteral(collectRegex()); + } else { + expr = delegate.createLiteral(scanRegExp()); + } + peek(); + } else { + throwUnexpected(lex()); } - return throwUnexpected(lex()); + return delegate.markEnd(expr, startToken); } // 11.2 Left-Hand-Side Expressions @@ -6085,16 +6719,16 @@ parseStatement: true, parseSourceElement: true */ } function parseNonComputedProperty() { - var token = lex(); + var token, startToken; + + startToken = lookahead; + token = lex(); if (!isIdentifierName(token)) { throwUnexpected(token); } - return { - type: Syntax.Identifier, - name: token.value - }; + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); } function parseNonComputedMember() { @@ -6116,77 +6750,63 @@ parseStatement: true, parseSourceElement: true */ } function parseNewExpression() { - var expr; + var callee, args, startToken; + startToken = lookahead; expectKeyword('new'); + callee = parseLeftHandSideExpression(); + args = match('(') ? parseArguments() : []; - expr = { - type: Syntax.NewExpression, - callee: parseLeftHandSideExpression(), - 'arguments': [] - }; - - if (match('(')) { - expr['arguments'] = parseArguments(); - } - - return expr; + return delegate.markEnd(delegate.createNewExpression(callee, args), startToken); } function parseLeftHandSideExpressionAllowCall() { - var expr; + var previousAllowIn, expr, args, property, startToken; + + startToken = lookahead; + previousAllowIn = state.allowIn; + state.allowIn = true; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + state.allowIn = previousAllowIn; - while (match('.') || match('[') || match('(')) { - if (match('(')) { - expr = { - type: Syntax.CallExpression, - callee: expr, - 'arguments': parseArguments() - }; + for (;;) { + if (match('.')) { + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); + } else if (match('(')) { + args = parseArguments(); + expr = delegate.createCallExpression(expr, args); } else if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; + break; } + delegate.markEnd(expr, startToken); } return expr; } - function parseLeftHandSideExpression() { - var expr; + var previousAllowIn, expr, property, startToken; + startToken = lookahead; + + previousAllowIn = state.allowIn; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + state.allowIn = previousAllowIn; while (match('.') || match('[')) { if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; + property = parseComputedMember(); + expr = delegate.createMemberExpression('[', expr, property); } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; + property = parseNonComputedMember(); + expr = delegate.createMemberExpression('.', expr, property); } + delegate.markEnd(expr, startToken); } return expr; @@ -6195,28 +6815,24 @@ parseStatement: true, parseSourceElement: true */ // 11.3 Postfix Expressions function parsePostfixExpression() { - var expr = parseLeftHandSideExpressionAllowCall(), token; + var expr, token, startToken = lookahead; - token = lookahead(); - if (token.type !== Token.Punctuator) { - return expr; - } + expr = parseLeftHandSideExpressionAllowCall(); - if ((match('++') || match('--')) && !peekLineTerminator()) { - // 11.3.1, 11.3.2 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPostfix); - } - if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } + if (lookahead.type === Token.Punctuator) { + if ((match('++') || match('--')) && !peekLineTerminator()) { + // 11.3.1, 11.3.2 + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + throwErrorTolerant({}, Messages.StrictLHSPostfix); + } - expr = { - type: Syntax.UpdateExpression, - operator: lex().value, - argument: expr, - prefix: false - }; + if (!isLeftHandSide(expr)) { + throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + } + + token = lex(); + expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken); + } } return expr; @@ -6225,14 +6841,12 @@ parseStatement: true, parseSourceElement: true */ // 11.4 Unary Operators function parseUnaryExpression() { - var token, expr; - - token = lookahead(); - if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { - return parsePostfixExpression(); - } + var token, expr, startToken; - if (match('++') || match('--')) { + if (lookahead.type !== Token.Punctuator && lookahead.type !== Token.Keyword) { + expr = parsePostfixExpression(); + } else if (match('++') || match('--')) { + startToken = lookahead; token = lex(); expr = parseUnaryExpression(); // 11.4.4, 11.4.5 @@ -6244,221 +6858,174 @@ parseStatement: true, parseSourceElement: true */ throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } - expr = { - type: Syntax.UpdateExpression, - operator: token.value, - argument: expr, - prefix: true - }; - return expr; - } - - if (match('+') || match('-') || match('~') || match('!')) { - expr = { - type: Syntax.UnaryExpression, - operator: lex().value, - argument: parseUnaryExpression(), - prefix: true - }; - return expr; - } - - if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { - expr = { - type: Syntax.UnaryExpression, - operator: lex().value, - argument: parseUnaryExpression(), - prefix: true - }; + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + } else if (match('+') || match('-') || match('~') || match('!')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); + } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { + startToken = lookahead; + token = lex(); + expr = parseUnaryExpression(); + expr = delegate.createUnaryExpression(token.value, expr); + expr = delegate.markEnd(expr, startToken); if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { throwErrorTolerant({}, Messages.StrictDelete); } - return expr; - } - - return parsePostfixExpression(); - } - - // 11.5 Multiplicative Operators - - function parseMultiplicativeExpression() { - var expr = parseUnaryExpression(); - - while (match('*') || match('/') || match('%')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseUnaryExpression() - }; + } else { + expr = parsePostfixExpression(); } return expr; } - // 11.6 Additive Operators - - function parseAdditiveExpression() { - var expr = parseMultiplicativeExpression(); + function binaryPrecedence(token, allowIn) { + var prec = 0; - while (match('+') || match('-')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseMultiplicativeExpression() - }; + if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { + return 0; } - return expr; - } - - // 11.7 Bitwise Shift Operators + switch (token.value) { + case '||': + prec = 1; + break; - function parseShiftExpression() { - var expr = parseAdditiveExpression(); + case '&&': + prec = 2; + break; - while (match('<<') || match('>>') || match('>>>')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseAdditiveExpression() - }; - } + case '|': + prec = 3; + break; - return expr; - } - // 11.8 Relational Operators + case '^': + prec = 4; + break; - function parseRelationalExpression() { - var expr, previousAllowIn; + case '&': + prec = 5; + break; - previousAllowIn = state.allowIn; - state.allowIn = true; + case '==': + case '!=': + case '===': + case '!==': + prec = 6; + break; - expr = parseShiftExpression(); + case '<': + case '>': + case '<=': + case '>=': + case 'instanceof': + prec = 7; + break; - while (match('<') || match('>') || match('<=') || match('>=') || (previousAllowIn && matchKeyword('in')) || matchKeyword('instanceof')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseShiftExpression() - }; - } + case 'in': + prec = allowIn ? 7 : 0; + break; - state.allowIn = previousAllowIn; - return expr; - } + case '<<': + case '>>': + case '>>>': + prec = 8; + break; - // 11.9 Equality Operators + case '+': + case '-': + prec = 9; + break; - function parseEqualityExpression() { - var expr = parseRelationalExpression(); + case '*': + case '/': + case '%': + prec = 11; + break; - while (match('==') || match('!=') || match('===') || match('!==')) { - expr = { - type: Syntax.BinaryExpression, - operator: lex().value, - left: expr, - right: parseRelationalExpression() - }; + default: + break; } - return expr; + return prec; } + // 11.5 Multiplicative Operators + // 11.6 Additive Operators + // 11.7 Bitwise Shift Operators + // 11.8 Relational Operators + // 11.9 Equality Operators // 11.10 Binary Bitwise Operators + // 11.11 Binary Logical Operators - function parseBitwiseANDExpression() { - var expr = parseEqualityExpression(); - - while (match('&')) { - lex(); - expr = { - type: Syntax.BinaryExpression, - operator: '&', - left: expr, - right: parseEqualityExpression() - }; - } - - return expr; - } + function parseBinaryExpression() { + var marker, markers, expr, token, prec, stack, right, operator, left, i; - function parseBitwiseXORExpression() { - var expr = parseBitwiseANDExpression(); + marker = lookahead; + left = parseUnaryExpression(); - while (match('^')) { - lex(); - expr = { - type: Syntax.BinaryExpression, - operator: '^', - left: expr, - right: parseBitwiseANDExpression() - }; + token = lookahead; + prec = binaryPrecedence(token, state.allowIn); + if (prec === 0) { + return left; } + token.prec = prec; + lex(); - return expr; - } - - function parseBitwiseORExpression() { - var expr = parseBitwiseXORExpression(); + markers = [marker, lookahead]; + right = parseUnaryExpression(); - while (match('|')) { - lex(); - expr = { - type: Syntax.BinaryExpression, - operator: '|', - left: expr, - right: parseBitwiseXORExpression() - }; - } - - return expr; - } + stack = [left, token, right]; - // 11.11 Binary Logical Operators + while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { - function parseLogicalANDExpression() { - var expr = parseBitwiseORExpression(); + // Reduce: make a binary expression from the three topmost entries. + while ((stack.length > 2) && (prec <= stack[stack.length - 2].prec)) { + right = stack.pop(); + operator = stack.pop().value; + left = stack.pop(); + expr = delegate.createBinaryExpression(operator, left, right); + markers.pop(); + marker = markers[markers.length - 1]; + delegate.markEnd(expr, marker); + stack.push(expr); + } - while (match('&&')) { - lex(); - expr = { - type: Syntax.LogicalExpression, - operator: '&&', - left: expr, - right: parseBitwiseORExpression() - }; + // Shift. + token = lex(); + token.prec = prec; + stack.push(token); + markers.push(lookahead); + expr = parseUnaryExpression(); + stack.push(expr); } - return expr; - } - - function parseLogicalORExpression() { - var expr = parseLogicalANDExpression(); - - while (match('||')) { - lex(); - expr = { - type: Syntax.LogicalExpression, - operator: '||', - left: expr, - right: parseLogicalANDExpression() - }; + // Final reduce to clean-up the stack. + i = stack.length - 1; + expr = stack[i]; + markers.pop(); + while (i > 1) { + expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + i -= 2; + marker = markers.pop(); + delegate.markEnd(expr, marker); } return expr; } + // 11.12 Conditional Operator function parseConditionalExpression() { - var expr, previousAllowIn, consequent; + var expr, previousAllowIn, consequent, alternate, startToken; + + startToken = lookahead; - expr = parseLogicalORExpression(); + expr = parseBinaryExpression(); if (match('?')) { lex(); @@ -6467,13 +7034,10 @@ parseStatement: true, parseSourceElement: true */ consequent = parseAssignmentExpression(); state.allowIn = previousAllowIn; expect(':'); + alternate = parseAssignmentExpression(); - expr = { - type: Syntax.ConditionalExpression, - test: expr, - consequent: consequent, - alternate: parseAssignmentExpression() - }; + expr = delegate.createConditionalExpression(expr, consequent, alternate); + delegate.markEnd(expr, startToken); } return expr; @@ -6482,43 +7046,41 @@ parseStatement: true, parseSourceElement: true */ // 11.13 Assignment Operators function parseAssignmentExpression() { - var token, expr; + var token, left, right, node, startToken; + + token = lookahead; + startToken = lookahead; - token = lookahead(); - expr = parseConditionalExpression(); + node = left = parseConditionalExpression(); if (matchAssign()) { // LeftHandSideExpression - if (!isLeftHandSide(expr)) { + if (!isLeftHandSide(left)) { throwErrorTolerant({}, Messages.InvalidLHSInAssignment); } // 11.13.1 - if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { throwErrorTolerant(token, Messages.StrictLHSAssignment); } - expr = { - type: Syntax.AssignmentExpression, - operator: lex().value, - left: expr, - right: parseAssignmentExpression() - }; + token = lex(); + right = parseAssignmentExpression(); + node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken); } - return expr; + return node; } // 11.14 Comma Operator function parseExpression() { - var expr = parseAssignmentExpression(); + var expr, startToken = lookahead; + + expr = parseAssignmentExpression(); if (match(',')) { - expr = { - type: Syntax.SequenceExpression, - expressions: [ expr ] - }; + expr = delegate.createSequenceExpression([ expr ]); while (index < length) { if (!match(',')) { @@ -6528,7 +7090,9 @@ parseStatement: true, parseSourceElement: true */ expr.expressions.push(parseAssignmentExpression()); } + delegate.markEnd(expr, startToken); } + return expr; } @@ -6553,38 +7117,38 @@ parseStatement: true, parseSourceElement: true */ } function parseBlock() { - var block; + var block, startToken; + startToken = lookahead; expect('{'); block = parseStatementList(); expect('}'); - return { - type: Syntax.BlockStatement, - body: block - }; + return delegate.markEnd(delegate.createBlockStatement(block), startToken); } // 12.2 Variable Statement function parseVariableIdentifier() { - var token = lex(); + var token, startToken; + + startToken = lookahead; + token = lex(); if (token.type !== Token.Identifier) { throwUnexpected(token); } - return { - type: Syntax.Identifier, - name: token.value - }; + return delegate.markEnd(delegate.createIdentifier(token.value), startToken); } function parseVariableDeclaration(kind) { - var id = parseVariableIdentifier(), - init = null; + var init = null, id, startToken; + + startToken = lookahead; + id = parseVariableIdentifier(); // 12.2.1 if (strict && isRestrictedWord(id.name)) { @@ -6599,11 +7163,7 @@ parseStatement: true, parseSourceElement: true */ init = parseAssignmentExpression(); } - return { - type: Syntax.VariableDeclarator, - id: id, - init: init - }; + return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken); } function parseVariableDeclarationList(kind) { @@ -6629,11 +7189,7 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: 'var' - }; + return delegate.createVariableDeclaration(declarations, 'var'); } // kind may be `const` or `let` @@ -6641,7 +7197,9 @@ parseStatement: true, parseSourceElement: true */ // see http://wiki.ecmascript.org/doku.php?id=harmony:const // and http://wiki.ecmascript.org/doku.php?id=harmony:let function parseConstLetDeclaration(kind) { - var declarations; + var declarations, startToken; + + startToken = lookahead; expectKeyword(kind); @@ -6649,34 +7207,22 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: kind - }; + return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken); } // 12.3 Empty Statement function parseEmptyStatement() { expect(';'); - - return { - type: Syntax.EmptyStatement - }; + return delegate.createEmptyStatement(); } // 12.4 Expression Statement function parseExpressionStatement() { var expr = parseExpression(); - consumeSemicolon(); - - return { - type: Syntax.ExpressionStatement, - expression: expr - }; + return delegate.createExpressionStatement(expr); } // 12.5 If statement @@ -6701,12 +7247,7 @@ parseStatement: true, parseSourceElement: true */ alternate = null; } - return { - type: Syntax.IfStatement, - test: test, - consequent: consequent, - alternate: alternate - }; + return delegate.createIfStatement(test, consequent, alternate); } // 12.6 Iteration Statements @@ -6735,11 +7276,7 @@ parseStatement: true, parseSourceElement: true */ lex(); } - return { - type: Syntax.DoWhileStatement, - body: body, - test: test - }; + return delegate.createDoWhileStatement(body, test); } function parseWhileStatement() { @@ -6760,21 +7297,17 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; - return { - type: Syntax.WhileStatement, - test: test, - body: body - }; + return delegate.createWhileStatement(test, body); } function parseForVariableDeclaration() { - var token = lex(); + var token, declarations, startToken; - return { - type: Syntax.VariableDeclaration, - declarations: parseVariableDeclarationList(), - kind: token.value - }; + startToken = lookahead; + token = lex(); + declarations = parseVariableDeclarationList(); + + return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken); } function parseForStatement() { @@ -6844,44 +7377,27 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; - if (typeof left === 'undefined') { - return { - type: Syntax.ForStatement, - init: init, - test: test, - update: update, - body: body - }; - } - - return { - type: Syntax.ForInStatement, - left: left, - right: right, - body: body, - each: false - }; + return (typeof left === 'undefined') ? + delegate.createForStatement(init, test, update, body) : + delegate.createForInStatement(left, right, body); } // 12.7 The continue statement function parseContinueStatement() { - var token, label = null; + var label = null, key; expectKeyword('continue'); // Optimize the most common form: 'continue;'. - if (source[index] === ';') { + if (source.charCodeAt(index) === 0x3B) { lex(); if (!state.inIteration) { throwError({}, Messages.IllegalContinue); } - return { - type: Syntax.ContinueStatement, - label: null - }; + return delegate.createContinueStatement(null); } if (peekLineTerminator()) { @@ -6889,17 +7405,14 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalContinue); } - return { - type: Syntax.ContinueStatement, - label: null - }; + return delegate.createContinueStatement(null); } - token = lookahead(); - if (token.type === Token.Identifier) { + if (lookahead.type === Token.Identifier) { label = parseVariableIdentifier(); - if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError({}, Messages.UnknownLabel, label.name); } } @@ -6910,31 +7423,25 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalContinue); } - return { - type: Syntax.ContinueStatement, - label: label - }; + return delegate.createContinueStatement(label); } // 12.8 The break statement function parseBreakStatement() { - var token, label = null; + var label = null, key; expectKeyword('break'); - // Optimize the most common form: 'break;'. - if (source[index] === ';') { + // Catch the very common case first: immediately a semicolon (U+003B). + if (source.charCodeAt(index) === 0x3B) { lex(); if (!(state.inIteration || state.inSwitch)) { throwError({}, Messages.IllegalBreak); } - return { - type: Syntax.BreakStatement, - label: null - }; + return delegate.createBreakStatement(null); } if (peekLineTerminator()) { @@ -6942,17 +7449,14 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalBreak); } - return { - type: Syntax.BreakStatement, - label: null - }; + return delegate.createBreakStatement(null); } - token = lookahead(); - if (token.type === Token.Identifier) { + if (lookahead.type === Token.Identifier) { label = parseVariableIdentifier(); - if (!Object.prototype.hasOwnProperty.call(state.labelSet, label.name)) { + key = '$' + label.name; + if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError({}, Messages.UnknownLabel, label.name); } } @@ -6963,16 +7467,13 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.IllegalBreak); } - return { - type: Syntax.BreakStatement, - label: label - }; + return delegate.createBreakStatement(label); } // 12.9 The return statement function parseReturnStatement() { - var token, argument = null; + var argument = null; expectKeyword('return'); @@ -6981,37 +7482,27 @@ parseStatement: true, parseSourceElement: true */ } // 'return' followed by a space and an identifier is very common. - if (source[index] === ' ') { - if (isIdentifierStart(source[index + 1])) { + if (source.charCodeAt(index) === 0x20) { + if (isIdentifierStart(source.charCodeAt(index + 1))) { argument = parseExpression(); consumeSemicolon(); - return { - type: Syntax.ReturnStatement, - argument: argument - }; + return delegate.createReturnStatement(argument); } } if (peekLineTerminator()) { - return { - type: Syntax.ReturnStatement, - argument: null - }; + return delegate.createReturnStatement(null); } if (!match(';')) { - token = lookahead(); - if (!match('}') && token.type !== Token.EOF) { + if (!match('}') && lookahead.type !== Token.EOF) { argument = parseExpression(); } } consumeSemicolon(); - return { - type: Syntax.ReturnStatement, - argument: argument - }; + return delegate.createReturnStatement(argument); } // 12.10 The with statement @@ -7020,6 +7511,8 @@ parseStatement: true, parseSourceElement: true */ var object, body; if (strict) { + // TODO(ikarienator): Should we update the test cases instead? + skipComment(); throwErrorTolerant({}, Messages.StrictModeWith); } @@ -7033,20 +7526,15 @@ parseStatement: true, parseSourceElement: true */ body = parseStatement(); - return { - type: Syntax.WithStatement, - object: object, - body: body - }; + return delegate.createWithStatement(object, body); } // 12.10 The swith statement function parseSwitchCase() { - var test, - consequent = [], - statement; + var test, consequent = [], statement, startToken; + startToken = lookahead; if (matchKeyword('default')) { lex(); test = null; @@ -7061,17 +7549,10 @@ parseStatement: true, parseSourceElement: true */ break; } statement = parseStatement(); - if (typeof statement === 'undefined') { - break; - } consequent.push(statement); } - return { - type: Syntax.SwitchCase, - test: test, - consequent: consequent - }; + return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken); } function parseSwitchStatement() { @@ -7091,11 +7572,7 @@ parseStatement: true, parseSourceElement: true */ if (match('}')) { lex(); - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; + return delegate.createSwitchStatement(discriminant, cases); } oldInSwitch = state.inSwitch; @@ -7120,11 +7597,7 @@ parseStatement: true, parseSourceElement: true */ expect('}'); - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; + return delegate.createSwitchStatement(discriminant, cases); } // 12.13 The throw statement @@ -7142,22 +7615,20 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.ThrowStatement, - argument: argument - }; + return delegate.createThrowStatement(argument); } // 12.14 The try statement function parseCatchClause() { - var param; + var param, body, startToken; + startToken = lookahead; expectKeyword('catch'); expect('('); if (match(')')) { - throwUnexpected(lookahead()); + throwUnexpected(lookahead); } param = parseVariableIdentifier(); @@ -7167,12 +7638,8 @@ parseStatement: true, parseSourceElement: true */ } expect(')'); - - return { - type: Syntax.CatchClause, - param: param, - body: parseBlock() - }; + body = parseBlock(); + return delegate.markEnd(delegate.createCatchClause(param, body), startToken); } function parseTryStatement() { @@ -7195,13 +7662,7 @@ parseStatement: true, parseSourceElement: true */ throwError({}, Messages.NoCatchOrFinally); } - return { - type: Syntax.TryStatement, - block: block, - guardedHandlers: [], - handlers: handlers, - finalizer: finalizer - }; + return delegate.createTryStatement(block, [], handlers, finalizer); } // 12.15 The debugger statement @@ -7211,65 +7672,69 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return { - type: Syntax.DebuggerStatement - }; + return delegate.createDebuggerStatement(); } // 12 Statements function parseStatement() { - var token = lookahead(), + var type = lookahead.type, expr, - labeledBody; + labeledBody, + key, + startToken; - if (token.type === Token.EOF) { - throwUnexpected(token); + if (type === Token.EOF) { + throwUnexpected(lookahead); + } + + if (type === Token.Punctuator && lookahead.value === '{') { + return parseBlock(); } - if (token.type === Token.Punctuator) { - switch (token.value) { + startToken = lookahead; + + if (type === Token.Punctuator) { + switch (lookahead.value) { case ';': - return parseEmptyStatement(); - case '{': - return parseBlock(); + return delegate.markEnd(parseEmptyStatement(), startToken); case '(': - return parseExpressionStatement(); + return delegate.markEnd(parseExpressionStatement(), startToken); default: break; } } - if (token.type === Token.Keyword) { - switch (token.value) { + if (type === Token.Keyword) { + switch (lookahead.value) { case 'break': - return parseBreakStatement(); + return delegate.markEnd(parseBreakStatement(), startToken); case 'continue': - return parseContinueStatement(); + return delegate.markEnd(parseContinueStatement(), startToken); case 'debugger': - return parseDebuggerStatement(); + return delegate.markEnd(parseDebuggerStatement(), startToken); case 'do': - return parseDoWhileStatement(); + return delegate.markEnd(parseDoWhileStatement(), startToken); case 'for': - return parseForStatement(); + return delegate.markEnd(parseForStatement(), startToken); case 'function': - return parseFunctionDeclaration(); + return delegate.markEnd(parseFunctionDeclaration(), startToken); case 'if': - return parseIfStatement(); + return delegate.markEnd(parseIfStatement(), startToken); case 'return': - return parseReturnStatement(); + return delegate.markEnd(parseReturnStatement(), startToken); case 'switch': - return parseSwitchStatement(); + return delegate.markEnd(parseSwitchStatement(), startToken); case 'throw': - return parseThrowStatement(); + return delegate.markEnd(parseThrowStatement(), startToken); case 'try': - return parseTryStatement(); + return delegate.markEnd(parseTryStatement(), startToken); case 'var': - return parseVariableStatement(); + return delegate.markEnd(parseVariableStatement(), startToken); case 'while': - return parseWhileStatement(); + return delegate.markEnd(parseWhileStatement(), startToken); case 'with': - return parseWithStatement(); + return delegate.markEnd(parseWithStatement(), startToken); default: break; } @@ -7281,42 +7746,36 @@ parseStatement: true, parseSourceElement: true */ if ((expr.type === Syntax.Identifier) && match(':')) { lex(); - if (Object.prototype.hasOwnProperty.call(state.labelSet, expr.name)) { + key = '$' + expr.name; + if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { throwError({}, Messages.Redeclaration, 'Label', expr.name); } - state.labelSet[expr.name] = true; + state.labelSet[key] = true; labeledBody = parseStatement(); - delete state.labelSet[expr.name]; - - return { - type: Syntax.LabeledStatement, - label: expr, - body: labeledBody - }; + delete state.labelSet[key]; + return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken); } consumeSemicolon(); - return { - type: Syntax.ExpressionStatement, - expression: expr - }; + return delegate.markEnd(delegate.createExpressionStatement(expr), startToken); } // 13 Function Definition function parseFunctionSourceElements() { var sourceElement, sourceElements = [], token, directive, firstRestricted, - oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody; + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken; + startToken = lookahead; expect('{'); while (index < length) { - token = lookahead(); - if (token.type !== Token.StringLiteral) { + if (lookahead.type !== Token.StringLiteral) { break; } + token = lookahead; sourceElement = parseSourceElement(); sourceElements.push(sourceElement); @@ -7324,7 +7783,7 @@ parseStatement: true, parseSourceElement: true */ // this is not directive break; } - directive = sliceSource(token.range[0] + 1, token.range[1] - 1); + directive = source.slice(token.start + 1, token.end - 1); if (directive === 'use strict') { strict = true; if (firstRestricted) { @@ -7365,45 +7824,25 @@ parseStatement: true, parseSourceElement: true */ state.inSwitch = oldInSwitch; state.inFunctionBody = oldInFunctionBody; - return { - type: Syntax.BlockStatement, - body: sourceElements - }; + return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken); } - function parseFunctionDeclaration() { - var id, param, params = [], body, token, stricted, firstRestricted, message, previousStrict, paramSet; - - expectKeyword('function'); - token = lookahead(); - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - + function parseParams(firstRestricted) { + var param, params = [], token, stricted, paramSet, key, message; expect('('); if (!match(')')) { paramSet = {}; while (index < length) { - token = lookahead(); + token = lookahead; param = parseVariableIdentifier(); + key = '$' + token.value; if (strict) { if (isRestrictedWord(token.value)) { stricted = token; message = Messages.StrictParamName; } - if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + if (Object.prototype.hasOwnProperty.call(paramSet, key)) { stricted = token; message = Messages.StrictParamDupe; } @@ -7414,13 +7853,13 @@ parseStatement: true, parseSourceElement: true */ } else if (isStrictModeReservedWord(token.value)) { firstRestricted = token; message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { + } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { firstRestricted = token; message = Messages.StrictParamDupe; } } params.push(param); - paramSet[param.name] = true; + paramSet[key] = true; if (match(')')) { break; } @@ -7430,6 +7869,44 @@ parseStatement: true, parseSourceElement: true */ expect(')'); + return { + params: params, + stricted: stricted, + firstRestricted: firstRestricted, + message: message + }; + } + + function parseFunctionDeclaration() { + var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken; + + startToken = lookahead; + + expectKeyword('function'); + token = lookahead; + id = parseVariableIdentifier(); + if (strict) { + if (isRestrictedWord(token.value)) { + throwErrorTolerant(token, Messages.StrictFunctionName); + } + } else { + if (isRestrictedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictFunctionName; + } else if (isStrictModeReservedWord(token.value)) { + firstRestricted = token; + message = Messages.StrictReservedWord; + } + } + + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; + } + previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { @@ -7440,25 +7917,17 @@ parseStatement: true, parseSourceElement: true */ } strict = previousStrict; - return { - type: Syntax.FunctionDeclaration, - id: id, - params: params, - defaults: [], - body: body, - rest: null, - generator: false, - expression: false - }; + return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken); } function parseFunctionExpression() { - var token, id = null, stricted, firstRestricted, message, param, params = [], body, previousStrict, paramSet; + var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken; + startToken = lookahead; expectKeyword('function'); if (!match('(')) { - token = lookahead(); + token = lookahead; id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { @@ -7475,45 +7944,14 @@ parseStatement: true, parseSourceElement: true */ } } - expect('('); - - if (!match(')')) { - paramSet = {}; - while (index < length) { - token = lookahead(); - param = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - stricted = token; - message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { - stricted = token; - message = Messages.StrictParamDupe; - } - } else if (!firstRestricted) { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, token.value)) { - firstRestricted = token; - message = Messages.StrictParamDupe; - } - } - params.push(param); - paramSet[param.name] = true; - if (match(')')) { - break; - } - expect(','); - } + tmp = parseParams(firstRestricted); + params = tmp.params; + stricted = tmp.stricted; + firstRestricted = tmp.firstRestricted; + if (tmp.message) { + message = tmp.message; } - expect(')'); - previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { @@ -7524,28 +7962,17 @@ parseStatement: true, parseSourceElement: true */ } strict = previousStrict; - return { - type: Syntax.FunctionExpression, - id: id, - params: params, - defaults: [], - body: body, - rest: null, - generator: false, - expression: false - }; + return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken); } // 14 Program function parseSourceElement() { - var token = lookahead(); - - if (token.type === Token.Keyword) { - switch (token.value) { + if (lookahead.type === Token.Keyword) { + switch (lookahead.value) { case 'const': case 'let': - return parseConstLetDeclaration(token.value); + return parseConstLetDeclaration(lookahead.value); case 'function': return parseFunctionDeclaration(); default: @@ -7553,295 +7980,60 @@ parseStatement: true, parseSourceElement: true */ } } - if (token.type !== Token.EOF) { + if (lookahead.type !== Token.EOF) { return parseStatement(); } } - function parseSourceElements() { - var sourceElement, sourceElements = [], token, directive, firstRestricted; - - while (index < length) { - token = lookahead(); - if (token.type !== Token.StringLiteral) { - break; - } - - sourceElement = parseSourceElement(); - sourceElements.push(sourceElement); - if (sourceElement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = sliceSource(token.range[0] + 1, token.range[1] - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - while (index < length) { - sourceElement = parseSourceElement(); - if (typeof sourceElement === 'undefined') { - break; - } - sourceElements.push(sourceElement); - } - return sourceElements; - } - - function parseProgram() { - var program; - strict = false; - program = { - type: Syntax.Program, - body: parseSourceElements() - }; - return program; - } - - // The following functions are needed only when the option to preserve - // the comments is active. - - function addComment(type, value, start, end, loc) { - assert(typeof start === 'number', 'Comment must have valid position'); - - // Because the way the actual token is scanned, often the comments - // (if any) are skipped twice during the lexical analysis. - // Thus, we need to skip adding a comment if the comment array already - // handled it. - if (extra.comments.length > 0) { - if (extra.comments[extra.comments.length - 1].range[1] > start) { - return; - } - } - - extra.comments.push({ - type: type, - value: value, - range: [start, end], - loc: loc - }); - } - - function scanComment() { - var comment, ch, loc, start, blockComment, lineComment; - - comment = ''; - blockComment = false; - lineComment = false; - - while (index < length) { - ch = source[index]; - - if (lineComment) { - ch = source[index++]; - if (isLineTerminator(ch)) { - loc.end = { - line: lineNumber, - column: index - lineStart - 1 - }; - lineComment = false; - addComment('Line', comment, start, index - 1, loc); - if (ch === '\r' && source[index] === '\n') { - ++index; - } - ++lineNumber; - lineStart = index; - comment = ''; - } else if (index >= length) { - lineComment = false; - comment += ch; - loc.end = { - line: lineNumber, - column: length - lineStart - }; - addComment('Line', comment, start, length, loc); - } else { - comment += ch; - } - } else if (blockComment) { - if (isLineTerminator(ch)) { - if (ch === '\r' && source[index + 1] === '\n') { - ++index; - comment += '\r\n'; - } else { - comment += ch; - } - ++lineNumber; - ++index; - lineStart = index; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - ch = source[index++]; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - comment += ch; - if (ch === '*') { - ch = source[index]; - if (ch === '/') { - comment = comment.substr(0, comment.length - 1); - blockComment = false; - ++index; - loc.end = { - line: lineNumber, - column: index - lineStart - }; - addComment('Block', comment, start, index, loc); - comment = ''; - } - } - } - } else if (ch === '/') { - ch = source[index + 1]; - if (ch === '/') { - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - start = index; - index += 2; - lineComment = true; - if (index >= length) { - loc.end = { - line: lineNumber, - column: index - lineStart - }; - lineComment = false; - addComment('Line', comment, start, index, loc); - } - } else if (ch === '*') { - start = index; - index += 2; - blockComment = true; - loc = { - start: { - line: lineNumber, - column: index - lineStart - 2 - } - }; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - break; - } - } else if (isWhiteSpace(ch)) { - ++index; - } else if (isLineTerminator(ch)) { - ++index; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - ++lineNumber; - lineStart = index; - } else { - break; - } - } - } - - function filterCommentLocation() { - var i, entry, comment, comments = []; - - for (i = 0; i < extra.comments.length; ++i) { - entry = extra.comments[i]; - comment = { - type: entry.type, - value: entry.value - }; - if (extra.range) { - comment.range = entry.range; - } - if (extra.loc) { - comment.loc = entry.loc; - } - comments.push(comment); - } - - extra.comments = comments; - } - - function collectToken() { - var start, loc, token, range, value; - - skipComment(); - start = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart - } - }; - - token = extra.advance(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - - if (token.type !== Token.EOF) { - range = [token.range[0], token.range[1]]; - value = sliceSource(token.range[0], token.range[1]); - extra.tokens.push({ - type: TokenName[token.type], - value: value, - range: range, - loc: loc - }); - } - - return token; - } - - function collectRegex() { - var pos, loc, regex, token; - - skipComment(); + function parseSourceElements() { + var sourceElement, sourceElements = [], token, directive, firstRestricted; - pos = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart + while (index < length) { + token = lookahead; + if (token.type !== Token.StringLiteral) { + break; } - }; - - regex = extra.scanRegExp(); - loc.end = { - line: lineNumber, - column: index - lineStart - }; - // Pop the previous token, which is likely '/' or '/=' - if (extra.tokens.length > 0) { - token = extra.tokens[extra.tokens.length - 1]; - if (token.range[0] === pos && token.type === 'Punctuator') { - if (token.value === '/' || token.value === '/=') { - extra.tokens.pop(); + sourceElement = parseSourceElement(); + sourceElements.push(sourceElement); + if (sourceElement.expression.type !== Syntax.Literal) { + // this is not directive + break; + } + directive = source.slice(token.start + 1, token.end - 1); + if (directive === 'use strict') { + strict = true; + if (firstRestricted) { + throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + } + } else { + if (!firstRestricted && token.octal) { + firstRestricted = token; } } } - extra.tokens.push({ - type: 'RegularExpression', - value: regex.literal, - range: [pos, index], - loc: loc - }); + while (index < length) { + sourceElement = parseSourceElement(); + /* istanbul ignore if */ + if (typeof sourceElement === 'undefined') { + break; + } + sourceElements.push(sourceElement); + } + return sourceElements; + } - return regex; + function parseProgram() { + var body, startToken; + + skipComment(); + peek(); + startToken = lookahead; + strict = false; + + body = parseSourceElements(); + return delegate.markEnd(delegate.createProgram(body), startToken); } function filterTokenLocation() { @@ -7865,431 +8057,92 @@ parseStatement: true, parseSourceElement: true */ extra.tokens = tokens; } - function createLiteral(token) { - return { - type: Syntax.Literal, - value: token.value - }; - } - - function createRawLiteral(token) { - return { - type: Syntax.Literal, - value: token.value, - raw: sliceSource(token.range[0], token.range[1]) - }; - } - - function createLocationMarker() { - var marker = {}; - - marker.range = [index, index]; - marker.loc = { - start: { - line: lineNumber, - column: index - lineStart - }, - end: { - line: lineNumber, - column: index - lineStart - } - }; - - marker.end = function () { - this.range[1] = index; - this.loc.end.line = lineNumber; - this.loc.end.column = index - lineStart; - }; + function tokenize(code, options) { + var toString, + token, + tokens; - marker.applyGroup = function (node) { - if (extra.range) { - node.groupRange = [this.range[0], this.range[1]]; - } - if (extra.loc) { - node.groupLoc = { - start: { - line: this.loc.start.line, - column: this.loc.start.column - }, - end: { - line: this.loc.end.line, - column: this.loc.end.column - } - }; - } - }; + toString = String; + if (typeof code !== 'string' && !(code instanceof String)) { + code = toString(code); + } - marker.apply = function (node) { - if (extra.range) { - node.range = [this.range[0], this.range[1]]; - } - if (extra.loc) { - node.loc = { - start: { - line: this.loc.start.line, - column: this.loc.start.column - }, - end: { - line: this.loc.end.line, - column: this.loc.end.column - } - }; - } + delegate = SyntaxTreeDelegate; + source = code; + index = 0; + lineNumber = (source.length > 0) ? 1 : 0; + lineStart = 0; + length = source.length; + lookahead = null; + state = { + allowIn: true, + labelSet: {}, + inFunctionBody: false, + inIteration: false, + inSwitch: false, + lastCommentStart: -1 }; - return marker; - } - - function trackGroupExpression() { - var marker, expr; - - skipComment(); - marker = createLocationMarker(); - expect('('); - - expr = parseExpression(); - - expect(')'); - - marker.end(); - marker.applyGroup(expr); - - return expr; - } - - function trackLeftHandSideExpression() { - var marker, expr; - - skipComment(); - marker = createLocationMarker(); - - expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - - while (match('.') || match('[')) { - if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; - marker.end(); - marker.apply(expr); - } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; - marker.end(); - marker.apply(expr); - } - } - - return expr; - } + extra = {}; - function trackLeftHandSideExpressionAllowCall() { - var marker, expr; + // Options matching. + options = options || {}; - skipComment(); - marker = createLocationMarker(); + // Of course we collect tokens here. + options.tokens = true; + extra.tokens = []; + extra.tokenize = true; + // The following two fields are necessary to compute the Regex tokens. + extra.openParenToken = -1; + extra.openCurlyToken = -1; - expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); + extra.range = (typeof options.range === 'boolean') && options.range; + extra.loc = (typeof options.loc === 'boolean') && options.loc; - while (match('.') || match('[') || match('(')) { - if (match('(')) { - expr = { - type: Syntax.CallExpression, - callee: expr, - 'arguments': parseArguments() - }; - marker.end(); - marker.apply(expr); - } else if (match('[')) { - expr = { - type: Syntax.MemberExpression, - computed: true, - object: expr, - property: parseComputedMember() - }; - marker.end(); - marker.apply(expr); - } else { - expr = { - type: Syntax.MemberExpression, - computed: false, - object: expr, - property: parseNonComputedMember() - }; - marker.end(); - marker.apply(expr); - } + if (typeof options.comment === 'boolean' && options.comment) { + extra.comments = []; } - - return expr; - } - - function filterGroup(node) { - var n, i, entry; - - n = (Object.prototype.toString.apply(node) === '[object Array]') ? [] : {}; - for (i in node) { - if (node.hasOwnProperty(i) && i !== 'groupRange' && i !== 'groupLoc') { - entry = node[i]; - if (entry === null || typeof entry !== 'object' || entry instanceof RegExp) { - n[i] = entry; - } else { - n[i] = filterGroup(entry); - } - } + if (typeof options.tolerant === 'boolean' && options.tolerant) { + extra.errors = []; } - return n; - } - - function wrapTrackingFunction(range, loc) { - return function (parseFunction) { - - function isBinary(node) { - return node.type === Syntax.LogicalExpression || - node.type === Syntax.BinaryExpression; + try { + peek(); + if (lookahead.type === Token.EOF) { + return extra.tokens; } - function visit(node) { - var start, end; - - if (isBinary(node.left)) { - visit(node.left); - } - if (isBinary(node.right)) { - visit(node.right); - } - - if (range) { - if (node.left.groupRange || node.right.groupRange) { - start = node.left.groupRange ? node.left.groupRange[0] : node.left.range[0]; - end = node.right.groupRange ? node.right.groupRange[1] : node.right.range[1]; - node.range = [start, end]; - } else if (typeof node.range === 'undefined') { - start = node.left.range[0]; - end = node.right.range[1]; - node.range = [start, end]; - } - } - if (loc) { - if (node.left.groupLoc || node.right.groupLoc) { - start = node.left.groupLoc ? node.left.groupLoc.start : node.left.loc.start; - end = node.right.groupLoc ? node.right.groupLoc.end : node.right.loc.end; - node.loc = { - start: start, - end: end - }; - } else if (typeof node.loc === 'undefined') { - node.loc = { - start: node.left.loc.start, - end: node.right.loc.end - }; + token = lex(); + while (lookahead.type !== Token.EOF) { + try { + token = lex(); + } catch (lexError) { + token = lookahead; + if (extra.errors) { + extra.errors.push(lexError); + // We have to break on the first error + // to avoid infinite loops. + break; + } else { + throw lexError; } } } - return function () { - var marker, node; - - skipComment(); - - marker = createLocationMarker(); - node = parseFunction.apply(null, arguments); - marker.end(); - - if (range && typeof node.range === 'undefined') { - marker.apply(node); - } - - if (loc && typeof node.loc === 'undefined') { - marker.apply(node); - } - - if (isBinary(node)) { - visit(node); - } - - return node; - }; - }; - } - - function patch() { - - var wrapTracking; - - if (extra.comments) { - extra.skipComment = skipComment; - skipComment = scanComment; - } - - if (extra.raw) { - extra.createLiteral = createLiteral; - createLiteral = createRawLiteral; - } - - if (extra.range || extra.loc) { - - extra.parseGroupExpression = parseGroupExpression; - extra.parseLeftHandSideExpression = parseLeftHandSideExpression; - extra.parseLeftHandSideExpressionAllowCall = parseLeftHandSideExpressionAllowCall; - parseGroupExpression = trackGroupExpression; - parseLeftHandSideExpression = trackLeftHandSideExpression; - parseLeftHandSideExpressionAllowCall = trackLeftHandSideExpressionAllowCall; - - wrapTracking = wrapTrackingFunction(extra.range, extra.loc); - - extra.parseAdditiveExpression = parseAdditiveExpression; - extra.parseAssignmentExpression = parseAssignmentExpression; - extra.parseBitwiseANDExpression = parseBitwiseANDExpression; - extra.parseBitwiseORExpression = parseBitwiseORExpression; - extra.parseBitwiseXORExpression = parseBitwiseXORExpression; - extra.parseBlock = parseBlock; - extra.parseFunctionSourceElements = parseFunctionSourceElements; - extra.parseCatchClause = parseCatchClause; - extra.parseComputedMember = parseComputedMember; - extra.parseConditionalExpression = parseConditionalExpression; - extra.parseConstLetDeclaration = parseConstLetDeclaration; - extra.parseEqualityExpression = parseEqualityExpression; - extra.parseExpression = parseExpression; - extra.parseForVariableDeclaration = parseForVariableDeclaration; - extra.parseFunctionDeclaration = parseFunctionDeclaration; - extra.parseFunctionExpression = parseFunctionExpression; - extra.parseLogicalANDExpression = parseLogicalANDExpression; - extra.parseLogicalORExpression = parseLogicalORExpression; - extra.parseMultiplicativeExpression = parseMultiplicativeExpression; - extra.parseNewExpression = parseNewExpression; - extra.parseNonComputedProperty = parseNonComputedProperty; - extra.parseObjectProperty = parseObjectProperty; - extra.parseObjectPropertyKey = parseObjectPropertyKey; - extra.parsePostfixExpression = parsePostfixExpression; - extra.parsePrimaryExpression = parsePrimaryExpression; - extra.parseProgram = parseProgram; - extra.parsePropertyFunction = parsePropertyFunction; - extra.parseRelationalExpression = parseRelationalExpression; - extra.parseStatement = parseStatement; - extra.parseShiftExpression = parseShiftExpression; - extra.parseSwitchCase = parseSwitchCase; - extra.parseUnaryExpression = parseUnaryExpression; - extra.parseVariableDeclaration = parseVariableDeclaration; - extra.parseVariableIdentifier = parseVariableIdentifier; - - parseAdditiveExpression = wrapTracking(extra.parseAdditiveExpression); - parseAssignmentExpression = wrapTracking(extra.parseAssignmentExpression); - parseBitwiseANDExpression = wrapTracking(extra.parseBitwiseANDExpression); - parseBitwiseORExpression = wrapTracking(extra.parseBitwiseORExpression); - parseBitwiseXORExpression = wrapTracking(extra.parseBitwiseXORExpression); - parseBlock = wrapTracking(extra.parseBlock); - parseFunctionSourceElements = wrapTracking(extra.parseFunctionSourceElements); - parseCatchClause = wrapTracking(extra.parseCatchClause); - parseComputedMember = wrapTracking(extra.parseComputedMember); - parseConditionalExpression = wrapTracking(extra.parseConditionalExpression); - parseConstLetDeclaration = wrapTracking(extra.parseConstLetDeclaration); - parseEqualityExpression = wrapTracking(extra.parseEqualityExpression); - parseExpression = wrapTracking(extra.parseExpression); - parseForVariableDeclaration = wrapTracking(extra.parseForVariableDeclaration); - parseFunctionDeclaration = wrapTracking(extra.parseFunctionDeclaration); - parseFunctionExpression = wrapTracking(extra.parseFunctionExpression); - parseLeftHandSideExpression = wrapTracking(parseLeftHandSideExpression); - parseLogicalANDExpression = wrapTracking(extra.parseLogicalANDExpression); - parseLogicalORExpression = wrapTracking(extra.parseLogicalORExpression); - parseMultiplicativeExpression = wrapTracking(extra.parseMultiplicativeExpression); - parseNewExpression = wrapTracking(extra.parseNewExpression); - parseNonComputedProperty = wrapTracking(extra.parseNonComputedProperty); - parseObjectProperty = wrapTracking(extra.parseObjectProperty); - parseObjectPropertyKey = wrapTracking(extra.parseObjectPropertyKey); - parsePostfixExpression = wrapTracking(extra.parsePostfixExpression); - parsePrimaryExpression = wrapTracking(extra.parsePrimaryExpression); - parseProgram = wrapTracking(extra.parseProgram); - parsePropertyFunction = wrapTracking(extra.parsePropertyFunction); - parseRelationalExpression = wrapTracking(extra.parseRelationalExpression); - parseStatement = wrapTracking(extra.parseStatement); - parseShiftExpression = wrapTracking(extra.parseShiftExpression); - parseSwitchCase = wrapTracking(extra.parseSwitchCase); - parseUnaryExpression = wrapTracking(extra.parseUnaryExpression); - parseVariableDeclaration = wrapTracking(extra.parseVariableDeclaration); - parseVariableIdentifier = wrapTracking(extra.parseVariableIdentifier); - } - - if (typeof extra.tokens !== 'undefined') { - extra.advance = advance; - extra.scanRegExp = scanRegExp; - - advance = collectToken; - scanRegExp = collectRegex; - } - } - - function unpatch() { - if (typeof extra.skipComment === 'function') { - skipComment = extra.skipComment; - } - - if (extra.raw) { - createLiteral = extra.createLiteral; - } - - if (extra.range || extra.loc) { - parseAdditiveExpression = extra.parseAdditiveExpression; - parseAssignmentExpression = extra.parseAssignmentExpression; - parseBitwiseANDExpression = extra.parseBitwiseANDExpression; - parseBitwiseORExpression = extra.parseBitwiseORExpression; - parseBitwiseXORExpression = extra.parseBitwiseXORExpression; - parseBlock = extra.parseBlock; - parseFunctionSourceElements = extra.parseFunctionSourceElements; - parseCatchClause = extra.parseCatchClause; - parseComputedMember = extra.parseComputedMember; - parseConditionalExpression = extra.parseConditionalExpression; - parseConstLetDeclaration = extra.parseConstLetDeclaration; - parseEqualityExpression = extra.parseEqualityExpression; - parseExpression = extra.parseExpression; - parseForVariableDeclaration = extra.parseForVariableDeclaration; - parseFunctionDeclaration = extra.parseFunctionDeclaration; - parseFunctionExpression = extra.parseFunctionExpression; - parseGroupExpression = extra.parseGroupExpression; - parseLeftHandSideExpression = extra.parseLeftHandSideExpression; - parseLeftHandSideExpressionAllowCall = extra.parseLeftHandSideExpressionAllowCall; - parseLogicalANDExpression = extra.parseLogicalANDExpression; - parseLogicalORExpression = extra.parseLogicalORExpression; - parseMultiplicativeExpression = extra.parseMultiplicativeExpression; - parseNewExpression = extra.parseNewExpression; - parseNonComputedProperty = extra.parseNonComputedProperty; - parseObjectProperty = extra.parseObjectProperty; - parseObjectPropertyKey = extra.parseObjectPropertyKey; - parsePrimaryExpression = extra.parsePrimaryExpression; - parsePostfixExpression = extra.parsePostfixExpression; - parseProgram = extra.parseProgram; - parsePropertyFunction = extra.parsePropertyFunction; - parseRelationalExpression = extra.parseRelationalExpression; - parseStatement = extra.parseStatement; - parseShiftExpression = extra.parseShiftExpression; - parseSwitchCase = extra.parseSwitchCase; - parseUnaryExpression = extra.parseUnaryExpression; - parseVariableDeclaration = extra.parseVariableDeclaration; - parseVariableIdentifier = extra.parseVariableIdentifier; - } - - if (typeof extra.scanRegExp === 'function') { - advance = extra.advance; - scanRegExp = extra.scanRegExp; - } - } - - function stringToArray(str) { - var length = str.length, - result = [], - i; - for (i = 0; i < length; ++i) { - result[i] = str.charAt(i); + filterTokenLocation(); + tokens = extra.tokens; + if (typeof extra.comments !== 'undefined') { + tokens.comments = extra.comments; + } + if (typeof extra.errors !== 'undefined') { + tokens.errors = extra.errors; + } + } catch (e) { + throw e; + } finally { + extra = {}; } - return result; + return tokens; } function parse(code, options) { @@ -8300,25 +8153,32 @@ parseStatement: true, parseSourceElement: true */ code = toString(code); } + delegate = SyntaxTreeDelegate; source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; lineStart = 0; length = source.length; - buffer = null; + lookahead = null; state = { allowIn: true, labelSet: {}, inFunctionBody: false, inIteration: false, - inSwitch: false + inSwitch: false, + lastCommentStart: -1 }; extra = {}; if (typeof options !== 'undefined') { extra.range = (typeof options.range === 'boolean') && options.range; extra.loc = (typeof options.loc === 'boolean') && options.loc; - extra.raw = (typeof options.raw === 'boolean') && options.raw; + extra.attachComment = (typeof options.attachComment === 'boolean') && options.attachComment; + + if (extra.loc && options.source !== null && options.source !== undefined) { + extra.source = toString(options.source); + } + if (typeof options.tokens === 'boolean' && options.tokens) { extra.tokens = []; } @@ -8328,29 +8188,18 @@ parseStatement: true, parseSourceElement: true */ if (typeof options.tolerant === 'boolean' && options.tolerant) { extra.errors = []; } - } - - if (length > 0) { - if (typeof source[0] === 'undefined') { - // Try first to convert to a string. This is good as fast path - // for old IE which understands string indexing for string - // literals only and not for string object. - if (code instanceof String) { - source = code.valueOf(); - } - - // Force accessing the characters via an array. - if (typeof source[0] === 'undefined') { - source = stringToArray(code); - } + if (extra.attachComment) { + extra.range = true; + extra.comments = []; + extra.bottomRightStack = []; + extra.trailingComments = []; + extra.leadingComments = []; } } - patch(); try { program = parseProgram(); if (typeof extra.comments !== 'undefined') { - filterCommentLocation(); program.comments = extra.comments; } if (typeof extra.tokens !== 'undefined') { @@ -8360,25 +8209,24 @@ parseStatement: true, parseSourceElement: true */ if (typeof extra.errors !== 'undefined') { program.errors = extra.errors; } - if (extra.range || extra.loc) { - program.body = filterGroup(program.body); - } } catch (e) { throw e; } finally { - unpatch(); extra = {}; } return program; } - // Sync with package.json. - exports.version = '1.0.4'; + // Sync with *.json manifests. + exports.version = '1.2.2'; + + exports.tokenize = tokenize; exports.parse = parse; // Deep copy. + /* istanbul ignore next */ exports.Syntax = (function () { var name, types = {}; @@ -13616,7 +13464,7 @@ define('source-map/source-map-consumer', function (require, exports, module) { * - 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. + * - file: Optional. The generated file this source map is associated with. * * Here is an example source map, taken from the source map spec[0]: * @@ -13900,7 +13748,7 @@ define('source-map/source-map-consumer', function (require, exports, module) { "generatedColumn", util.compareByGeneratedPositions); - if (mapping) { + if (mapping && mapping.generatedLine === needle.generatedLine) { var source = util.getArg(mapping, 'source', null); if (source && this.sourceRoot) { source = util.join(this.sourceRoot, source); @@ -14078,14 +13926,17 @@ define('source-map/source-map-generator', function (require, exports, module) { /** * 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: + * being built incrementally. You may 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. + * - sourceRoot: A root for all relative URLs in this source map. */ function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); + if (!aArgs) { + aArgs = {}; + } + this._file = util.getArg(aArgs, 'file', null); this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); this._sources = new ArraySet(); this._names = new ArraySet(); @@ -14215,11 +14066,23 @@ define('source-map/source-map-generator', function (require, exports, module) { * @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 aSourceMapPath Optional. The dirname of the path to the source map + * to be applied. If relative, it is relative to the SourceMapConsumer. + * This parameter is needed when the two source maps aren't in the same + * directory, and the source map to be applied contains relative source + * paths. If so, those relative source paths need to be rewritten + * relative to the SourceMapGenerator. */ SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { // If aSourceFile is omitted, we will use the file property of the SourceMap if (!aSourceFile) { + if (!aSourceMapConsumer.file) { + throw new Error( + 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + + 'or the source map\'s "file" property. Both were omitted.' + ); + } aSourceFile = aSourceMapConsumer.file; } var sourceRoot = this._sourceRoot; @@ -14242,10 +14105,12 @@ define('source-map/source-map-generator', function (require, exports, module) { }); if (original.source !== null) { // Copy mapping + mapping.source = original.source; + if (aSourceMapPath) { + mapping.source = util.join(aSourceMapPath, mapping.source) + } if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; + mapping.source = util.relative(sourceRoot, mapping.source); } mapping.originalLine = original.line; mapping.originalColumn = original.column; @@ -14500,41 +14365,16 @@ define('source-map/source-node', function (require, exports, module) { 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 { + if (lastMapping !== null) { // 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); + // Associate first line with "lastMapping" + addMappingWithCode(lastMapping, remainingLines.shift() + "\n"); + lastGeneratedLine++; + lastGeneratedColumn = 0; + // The remaining code is added without mapping } else { // There is no new line in between. // Associate the code between "lastGeneratedColumn" and @@ -14546,14 +14386,37 @@ define('source-map/source-node', function (require, exports, module) { lastGeneratedColumn); lastGeneratedColumn = mapping.generatedColumn; addMappingWithCode(lastMapping, code); + // No more remaining code, continue + lastMapping = mapping; + return; } } + // 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; + } 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")); + if (remainingLines.length > 0) { + if (lastMapping) { + // Associate the remaining code in the current line with "lastMapping" + var lastLine = remainingLines.shift(); + if (remainingLines.length > 0) lastLine += "\n"; + addMappingWithCode(lastMapping, lastLine); + } + // and add the remaining lines without any mapping + node.add(remainingLines.join("\n")); + } // Copy sourcesContent into SourceNode aSourceMapConsumer.sources.forEach(function (sourceFile) { @@ -14791,10 +14654,28 @@ define('source-map/source-node', function (require, exports, module) { lastOriginalSource = null; sourceMappingActive = false; } - chunk.split('').forEach(function (ch) { + chunk.split('').forEach(function (ch, idx, array) { if (ch === '\n') { generated.line++; generated.column = 0; + // Mappings end at eol + if (idx + 1 === array.length) { + lastOriginalSource = null; + sourceMappingActive = false; + } else if (sourceMappingActive) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } } else { generated.column++; } @@ -14840,8 +14721,8 @@ define('source-map/util', function (require, exports, module) { } exports.getArg = getArg; - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - var dataUrlRegexp = /^data:.+\,.+/; + var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/; + var dataUrlRegexp = /^data:.+\,.+$/; function urlParse(aUrl) { var match = aUrl.match(urlRegexp); @@ -14850,18 +14731,22 @@ define('source-map/util', function (require, exports, module) { } return { scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] + auth: match[2], + host: match[3], + port: match[4], + path: match[5] }; } exports.urlParse = urlParse; function urlGenerate(aParsedUrl) { - var url = aParsedUrl.scheme + "://"; + var url = ''; + if (aParsedUrl.scheme) { + url += aParsedUrl.scheme + ':'; + } + url += '//'; if (aParsedUrl.auth) { - url += aParsedUrl.auth + "@" + url += aParsedUrl.auth + '@'; } if (aParsedUrl.host) { url += aParsedUrl.host; @@ -14876,19 +14761,112 @@ define('source-map/util', function (require, exports, module) { } exports.urlGenerate = urlGenerate; + /** + * Normalizes a path, or the path portion of a URL: + * + * - Replaces consequtive slashes with one slash. + * - Removes unnecessary '.' parts. + * - Removes unnecessary '/..' parts. + * + * Based on code in the Node.js 'path' core module. + * + * @param aPath The path or url to normalize. + */ + function normalize(aPath) { + var path = aPath; + var url = urlParse(aPath); + if (url) { + if (!url.path) { + return aPath; + } + path = url.path; + } + var isAbsolute = (path.charAt(0) === '/'); + + var parts = path.split(/\/+/); + for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { + part = parts[i]; + if (part === '.') { + parts.splice(i, 1); + } else if (part === '..') { + up++; + } else if (up > 0) { + if (part === '') { + // The first part is blank if the path is absolute. Trying to go + // above the root is a no-op. Therefore we can remove all '..' parts + // directly after the root. + parts.splice(i + 1, up); + up = 0; + } else { + parts.splice(i, 2); + up--; + } + } + } + path = parts.join('/'); + + if (path === '') { + path = isAbsolute ? '/' : '.'; + } + + if (url) { + url.path = path; + return urlGenerate(url); + } + return path; + } + exports.normalize = normalize; + + /** + * Joins two paths/URLs. + * + * @param aRoot The root path or URL. + * @param aPath The path or URL to be joined with the root. + * + * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a + * scheme-relative URL: Then the scheme of aRoot, if any, is prepended + * first. + * - Otherwise aPath is a path. If aRoot is a URL, then its path portion + * is updated with the result and aRoot is returned. Otherwise the result + * is returned. + * - If aPath is absolute, the result is aPath. + * - Otherwise the two paths are joined with a slash. + * - Joining for example 'http://' and 'www.example.com' is also supported. + */ function join(aRoot, aPath) { - var url; + var aPathUrl = urlParse(aPath); + var aRootUrl = urlParse(aRoot); + if (aRootUrl) { + aRoot = aRootUrl.path || '/'; + } + + // `join(foo, '//www.example.org')` + if (aPathUrl && !aPathUrl.scheme) { + if (aRootUrl) { + aPathUrl.scheme = aRootUrl.scheme; + } + return urlGenerate(aPathUrl); + } - if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + if (aPathUrl || aPath.match(dataUrlRegexp)) { return aPath; } - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); + // `join('http://', 'www.example.com')` + if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { + aRootUrl.host = aPath; + return urlGenerate(aRootUrl); } - return aRoot.replace(/\/$/, '') + '/' + aPath; + var joined = aPath.charAt(0) === '/' + ? aPath + : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); + + if (aRootUrl) { + aRootUrl.path = joined; + return urlGenerate(aRootUrl); + } + return joined; } exports.join = join; @@ -18362,6 +18340,10 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){ node.mangled_name = name; return true; } + if (options.screw_ie8 && node instanceof AST_SymbolCatch) { + to_mangle.push(node.definition()); + return; + } }); this.walk(tw); to_mangle.forEach(function(def){ def.mangle(options) }); @@ -19923,6 +19905,7 @@ function Compressor(options, false_by_default) { loops : !false_by_default, unused : !false_by_default, hoist_funs : !false_by_default, + keep_fargs : false, hoist_vars : false, if_return : !false_by_default, join_vars : !false_by_default, @@ -20238,7 +20221,7 @@ merge(Compressor.prototype, { stat = stat.clone(); stat.condition = stat.condition.negate(compressor); stat.body = make_node(AST_BlockStatement, stat, { - body: ret + body: as_statement_array(stat.alternative).concat(ret) }); stat.alternative = make_node(AST_BlockStatement, stat, { body: body @@ -20906,18 +20889,20 @@ merge(Compressor.prototype, { var tt = new TreeTransformer( function before(node, descend, in_list) { if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { - for (var a = node.argnames, i = a.length; --i >= 0;) { - var sym = a[i]; - if (sym.unreferenced()) { - a.pop(); - compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", { - name : sym.name, - file : sym.start.file, - line : sym.start.line, - col : sym.start.col - }); + if (!compressor.option("keep_fargs")) { + for (var a = node.argnames, i = a.length; --i >= 0;) { + var sym = a[i]; + if (sym.unreferenced()) { + a.pop(); + compressor.warn("Dropping unused function argument {name} [{file}:{line},{col}]", { + name : sym.name, + file : sym.start.file, + line : sym.start.line, + col : sym.start.col + }); + } + else break; } - else break; } } if (node instanceof AST_Defun && node !== self) { @@ -22158,6 +22143,19 @@ merge(Compressor.prototype, { return consequent; } } + // x?y?z:a:a --> x&&y?z:a + if (consequent instanceof AST_Conditional + && consequent.alternative.equivalent_to(alternative)) { + return make_node(AST_Conditional, self, { + condition: make_node(AST_Binary, self, { + left: self.condition, + operator: "&&", + right: consequent.condition + }), + consequent: consequent.consequent, + alternative: alternative + }); + } return self; }); @@ -22285,6 +22283,9 @@ function SourceMap(options) { line: orig_line, column: orig_col }); + if (info.source === null) { + return; + } source = info.source; orig_line = info.line; orig_col = info.column; @@ -22588,7 +22589,8 @@ exports.minify = function(files, options, name) { base54.reset(); // 1. parse - var toplevel = null; + var toplevel = null, + sourcesContent = {}; if (options.spidermonkey) { toplevel = AST_Node.from_mozilla_ast(files); @@ -22599,6 +22601,7 @@ exports.minify = function(files, options, name) { var code = options.fromString ? file : rjsFile.readFile(file, "utf8"); + sourcesContent[file] = code; toplevel = parse(code, { filename: options.fromString ? name : file, toplevel: toplevel @@ -22634,6 +22637,14 @@ exports.minify = function(files, options, name) { orig: inMap, root: options.sourceRoot }); + if (options.sourceMapIncludeSources) { + for (var file in sourcesContent) { + if (sourcesContent.hasOwnProperty(file)) { + options.source_map.get().setSourceContent(file, sourcesContent[file]); + } + } + } + } if (options.output) { merge(output, options.output); @@ -27783,7 +27794,7 @@ function (args, quit, logger, build) { } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.4.12, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.4.13, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); From ea1bb8c6e7886912554590714b5f562722a8bcdc Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 20 May 2014 21:34:52 -0700 Subject: [PATCH 168/382] Relates to #620: allow stdout config to be set in a build config file, add a test --- build/example.build.js | 6 +++--- build/jslib/build.js | 36 +++++++++++++++++---------------- build/tests/alln.sh | 8 +++++++- build/tests/lib/stdout/build.js | 6 ++++++ build/tests/lib/stdout/main.js | 1 + build/tests/lib/stdout/stdout | 1 + 6 files changed, 37 insertions(+), 21 deletions(-) create mode 100644 build/tests/lib/stdout/build.js create mode 100644 build/tests/lib/stdout/main.js create mode 100644 build/tests/lib/stdout/stdout diff --git a/build/example.build.js b/build/example.build.js index a1bac5f1..13e202e2 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -451,9 +451,9 @@ //to this function, sourceMapText, will be the text of the source map. }, - //By setting "out" to "stdout", the optimized output is written to STDOUT. - //This can be useful for integrating r.js with other commandline tools. - //In order to avoid additional output "logLevel: 4" should also be used. + //In 2.0.12+: by setting "out" to "stdout", the optimized output is written + //to STDOUT. This can be useful for integrating r.js with other commandline + //tools. In order to avoid additional output "logLevel: 4" should also be used. out: "stdout", //Wrap any build bundle in a start and end text specified by wrap. diff --git a/build/jslib/build.js b/build/jslib/build.js index e9ece625..c82fb16b 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -863,7 +863,8 @@ define(function (require) { } } - build.makeAbsObject(["out", "cssIn"], config, absFilePath); + build.makeAbsObject((config.out === "stdout" ? ["cssIn"] : ["out", "cssIn"]), + config, absFilePath); build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath); }; @@ -1022,22 +1023,6 @@ define(function (require) { config = {}, buildBaseConfig = makeBuildBaseConfig(); - //If out=stdout, write output to STDOUT instead of a file. - if (cfg.out && cfg.out === 'stdout') { - cfg.out = function (content) { - var e = env.get(); - if (e === 'rhino') { - var out = new java.io.PrintStream(java.lang.System.out, true, 'UTF-8'); - out.println(content); - } else if (e === 'node') { - process.stdout.setEncoding('utf8'); - process.stdout.write(content); - } else { - console.log(content); - } - } - } - //Make sure all paths are relative to current directory. absFilePath = file.absPath('.'); build.makeAbsConfig(cfg, absFilePath); @@ -1162,6 +1147,23 @@ define(function (require) { config.dirBaseUrl = endsWithSlash(config.dirBaseUrl); } + + //If out=stdout, write output to STDOUT instead of a file. + if (config.out && config.out === 'stdout') { + config.out = function (content) { + var e = env.get(); + if (e === 'rhino') { + var out = new java.io.PrintStream(java.lang.System.out, true, 'UTF-8'); + out.println(content); + } else if (e === 'node') { + process.stdout.setEncoding('utf8'); + process.stdout.write(content); + } else { + console.log(content); + } + } + } + //Check for errors in config if (config.main) { throw new Error('"main" passed as an option, but the ' + diff --git a/build/tests/alln.sh b/build/tests/alln.sh index f63adc2f..4552b580 100755 --- a/build/tests/alln.sh +++ b/build/tests/alln.sh @@ -13,6 +13,12 @@ rm -rf ./builds/ node nodeAll.js rm -rf ./builds/ -echo "\nRunning tests via bootstrap" +echo "Running tests via bootstrap" echo "==============================" node ../../r.js all.js + +echo "Testing stdout, result should be: define("main",{name:"main"});" +echo "==============================" +node ../../r.js -o lib/stdout/build.js + +echo "" diff --git a/build/tests/lib/stdout/build.js b/build/tests/lib/stdout/build.js new file mode 100644 index 00000000..c1808c4e --- /dev/null +++ b/build/tests/lib/stdout/build.js @@ -0,0 +1,6 @@ +{ + name: 'main', + out: 'stdout', + logLevel: 4 +} + diff --git a/build/tests/lib/stdout/main.js b/build/tests/lib/stdout/main.js new file mode 100644 index 00000000..790c8060 --- /dev/null +++ b/build/tests/lib/stdout/main.js @@ -0,0 +1 @@ +define({ name: 'main' }); diff --git a/build/tests/lib/stdout/stdout b/build/tests/lib/stdout/stdout new file mode 100644 index 00000000..0ea378ec --- /dev/null +++ b/build/tests/lib/stdout/stdout @@ -0,0 +1 @@ +define("main",{name:"main"}); \ No newline at end of file From f53afdc409553aed91b9dfbed02bc3036ee2348c Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 20 May 2014 21:35:13 -0700 Subject: [PATCH 169/382] snapshot --- dist/r.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 43ad6b85..13192e4a 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Tue, 20 May 2014 06:33:08 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Wed, 21 May 2014 04:35:07 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Tue, 20 May 2014 06:33:08 GMT', + version = '2.1.11+ Wed, 21 May 2014 04:35:07 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -26528,7 +26528,8 @@ define('build', function (require) { } } - build.makeAbsObject(["out", "cssIn"], config, absFilePath); + build.makeAbsObject((config.out === "stdout" ? ["cssIn"] : ["out", "cssIn"]), + config, absFilePath); build.makeAbsObject(["startFile", "endFile"], config.wrap, absFilePath); }; @@ -26811,6 +26812,23 @@ define('build', function (require) { config.dirBaseUrl = endsWithSlash(config.dirBaseUrl); } + + //If out=stdout, write output to STDOUT instead of a file. + if (config.out && config.out === 'stdout') { + config.out = function (content) { + var e = env.get(); + if (e === 'rhino') { + var out = new java.io.PrintStream(java.lang.System.out, true, 'UTF-8'); + out.println(content); + } else if (e === 'node') { + process.stdout.setEncoding('utf8'); + process.stdout.write(content); + } else { + console.log(content); + } + } + } + //Check for errors in config if (config.main) { throw new Error('"main" passed as an option, but the ' + From 8dd4896e5fa8ddc7abf62ab056293f9fdf0b0d0c Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 13:57:47 -0700 Subject: [PATCH 170/382] Fixes #642, do not print skip message for data: urls --- build/jslib/optimize.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index 93b34c35..0cbacf4f 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -55,8 +55,7 @@ function (lang, logger, envOptimize, file, parse, if (firstChar !== "/" && firstChar !== "#" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { //It is a relative URL, tack on the cssPrefix and path prefix urlMatch = cssPrefix + path + fixedUrlMatch; - - } else { + } else if (fixedUrlMatch.indexOf('data:') !== 0) { logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); } From ffd6ad4328390ae898eca29adf039b187ed8af39 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 13:58:06 -0700 Subject: [PATCH 171/382] snapshot --- dist/r.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index 13192e4a..2fb6b98a 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Wed, 21 May 2014 04:35:07 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Thu, 22 May 2014 20:57:57 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Wed, 21 May 2014 04:35:07 GMT', + version = '2.1.11+ Thu, 22 May 2014 20:57:57 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24612,8 +24612,7 @@ function (lang, logger, envOptimize, file, parse, if (firstChar !== "/" && firstChar !== "#" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { //It is a relative URL, tack on the cssPrefix and path prefix urlMatch = cssPrefix + path + fixedUrlMatch; - - } else { + } else if (fixedUrlMatch.indexOf('data:') !== 0) { logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); } From 74a856bee45a600449495967d5c9f83ab12534f9 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 14:11:40 -0700 Subject: [PATCH 172/382] Fixes #655, ignore custom protocols for urls --- build/jslib/optimize.js | 9 +++++---- build/tests/builds.js | 18 ++++++++++++++++++ .../lib/cssRelativeUrl/input/subfolder/sub.css | 4 ++++ .../lib/cssRelativeUrl/output/expected.css | 5 ++++- .../lib/cssRelativeUrl/output/main-built.css | 5 ++++- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/build/jslib/optimize.js b/build/jslib/optimize.js index 0cbacf4f..c7b23454 100644 --- a/build/jslib/optimize.js +++ b/build/jslib/optimize.js @@ -19,6 +19,7 @@ function (lang, logger, envOptimize, file, parse, cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig, cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g, cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g, + protocolRegExp = /^\w+:/, SourceMapGenerator = sourceMap.SourceMapGenerator, SourceMapConsumer =sourceMap.SourceMapConsumer; @@ -43,7 +44,7 @@ function (lang, logger, envOptimize, file, parse, function fixCssUrlPaths(fileName, path, contents, cssPrefix) { return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { - var colonIndex, firstChar, parts, i, + var firstChar, hasProtocol, parts, i, fixedUrlMatch = cleanCssUrlQuotes(urlMatch); fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); @@ -51,11 +52,11 @@ function (lang, logger, envOptimize, file, parse, //Only do the work for relative URLs. Skip things that start with / or #, or have //a protocol. firstChar = fixedUrlMatch.charAt(0); - colonIndex = fixedUrlMatch.indexOf(":"); - if (firstChar !== "/" && firstChar !== "#" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + hasProtocol = protocolRegExp.test(fixedUrlMatch); + if (firstChar !== "/" && firstChar !== "#" && !hasProtocol) { //It is a relative URL, tack on the cssPrefix and path prefix urlMatch = cssPrefix + path + fixedUrlMatch; - } else if (fixedUrlMatch.indexOf('data:') !== 0) { + } else if (!hasProtocol) { logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); } diff --git a/build/tests/builds.js b/build/tests/builds.js index c44322e3..3d9fa94a 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1008,6 +1008,24 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + doh.register("cssRelativeUrl", + [ + function cssRelativeUrl(t) { + file.deleteFile("lib/cssRelativeUrl/main-built.css"); + + build(["lib/cssRelativeUrl/build.js"]); + + t.is(nol(c("lib/cssRelativeUrl/output/expected.css")), + nol(c("lib/cssRelativeUrl/output/main-built.css"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + + doh.register("cssDuplicates", [ function cssDuplicates(t) { diff --git a/build/tests/lib/cssRelativeUrl/input/subfolder/sub.css b/build/tests/lib/cssRelativeUrl/input/subfolder/sub.css index 6426c8d2..d5e706dd 100644 --- a/build/tests/lib/cssRelativeUrl/input/subfolder/sub.css +++ b/build/tests/lib/cssRelativeUrl/input/subfolder/sub.css @@ -1,3 +1,7 @@ .test { background: url(test.png); } +.other { + background: url(about:blank); +} + diff --git a/build/tests/lib/cssRelativeUrl/output/expected.css b/build/tests/lib/cssRelativeUrl/output/expected.css index c901eb65..90bd94ad 100644 --- a/build/tests/lib/cssRelativeUrl/output/expected.css +++ b/build/tests/lib/cssRelativeUrl/output/expected.css @@ -1,3 +1,6 @@ .test { - background: url(../input/subfolder/test.png); + background: url(subfolder/test.png); +} +.other { + background: url(about:blank); } diff --git a/build/tests/lib/cssRelativeUrl/output/main-built.css b/build/tests/lib/cssRelativeUrl/output/main-built.css index c901eb65..90bd94ad 100644 --- a/build/tests/lib/cssRelativeUrl/output/main-built.css +++ b/build/tests/lib/cssRelativeUrl/output/main-built.css @@ -1,3 +1,6 @@ .test { - background: url(../input/subfolder/test.png); + background: url(subfolder/test.png); +} +.other { + background: url(about:blank); } From e54007172c6de6075d0ca9cb6a4180fd6115f987 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 14:11:56 -0700 Subject: [PATCH 173/382] snapshot --- dist/r.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dist/r.js b/dist/r.js index 2fb6b98a..e7b2b1ef 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Thu, 22 May 2014 20:57:57 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Thu, 22 May 2014 21:11:49 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Thu, 22 May 2014 20:57:57 GMT', + version = '2.1.11+ Thu, 22 May 2014 21:11:49 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -24576,6 +24576,7 @@ function (lang, logger, envOptimize, file, parse, cssImportRegExp = /\@import\s+(url\()?\s*([^);]+)\s*(\))?([\w, ]*)(;)?/ig, cssCommentImportRegExp = /\/\*[^\*]*@import[^\*]*\*\//g, cssUrlRegExp = /\url\(\s*([^\)]+)\s*\)?/g, + protocolRegExp = /^\w+:/, SourceMapGenerator = sourceMap.SourceMapGenerator, SourceMapConsumer =sourceMap.SourceMapConsumer; @@ -24600,7 +24601,7 @@ function (lang, logger, envOptimize, file, parse, function fixCssUrlPaths(fileName, path, contents, cssPrefix) { return contents.replace(cssUrlRegExp, function (fullMatch, urlMatch) { - var colonIndex, firstChar, parts, i, + var firstChar, hasProtocol, parts, i, fixedUrlMatch = cleanCssUrlQuotes(urlMatch); fixedUrlMatch = fixedUrlMatch.replace(lang.backSlashRegExp, "/"); @@ -24608,11 +24609,11 @@ function (lang, logger, envOptimize, file, parse, //Only do the work for relative URLs. Skip things that start with / or #, or have //a protocol. firstChar = fixedUrlMatch.charAt(0); - colonIndex = fixedUrlMatch.indexOf(":"); - if (firstChar !== "/" && firstChar !== "#" && (colonIndex === -1 || colonIndex > fixedUrlMatch.indexOf("/"))) { + hasProtocol = protocolRegExp.test(fixedUrlMatch); + if (firstChar !== "/" && firstChar !== "#" && !hasProtocol) { //It is a relative URL, tack on the cssPrefix and path prefix urlMatch = cssPrefix + path + fixedUrlMatch; - } else if (fixedUrlMatch.indexOf('data:') !== 0) { + } else if (!hasProtocol) { logger.trace(fileName + "\n URL not a relative URL, skipping: " + urlMatch); } From 9de38de104be7886de54b793ebf4c824226233f8 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 15:11:01 -0700 Subject: [PATCH 174/382] Fixes #658, make sure deps not traced until rawText is in play --- build/jslib/build.js | 22 ++++++++++++++++++---- build/tests/builds.js | 20 ++++++++++++++++++++ build/tests/lib/depsConfig/expected.js | 18 +++++++++--------- build/tests/lib/rawTextDeps/b.js | 4 ++++ build/tests/lib/rawTextDeps/build.js | 10 ++++++++++ build/tests/lib/rawTextDeps/built.js | 11 +++++++++++ build/tests/lib/rawTextDeps/expected.js | 11 +++++++++++ build/tests/lib/rawTextDeps/main.js | 4 ++++ 8 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 build/tests/lib/rawTextDeps/b.js create mode 100644 build/tests/lib/rawTextDeps/build.js create mode 100644 build/tests/lib/rawTextDeps/built.js create mode 100644 build/tests/lib/rawTextDeps/expected.js create mode 100644 build/tests/lib/rawTextDeps/main.js diff --git a/build/jslib/build.js b/build/jslib/build.js index c82fb16b..ff2c1a46 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -5,7 +5,7 @@ */ /*jslint plusplus: true, nomen: true, regexp: true */ -/*global define, requirejs */ +/*global define, requirejs, java, process, console */ define(function (require) { @@ -1161,7 +1161,7 @@ define(function (require) { } else { console.log(content); } - } + }; } //Check for errors in config @@ -1301,10 +1301,11 @@ define(function (require) { config.cssPrefix = ''; } - //Cycle through modules and combine any local stubModules with - //global values. + //Cycle through modules and normalize if (config.modules && config.modules.length) { config.modules.forEach(function (mod) { + + //Combine any local stubModules with global values. if (config.stubModules) { mod.stubModules = config.stubModules.concat(mod.stubModules || []); } @@ -1318,6 +1319,17 @@ define(function (require) { }); } + // Legacy command support, which allowed a single string ID + // for include. + if (typeof mod.include === 'string') { + mod.include = [mod.include]; + } + + //Add deps to each modules entry. + if (config.deps) { + mod.include = config.deps.concat(mod.include || []); + } + //Allow wrap config in overrides, but normalize it. if (mod.override) { normalizeWrapConfig(mod.override, absFilePath); @@ -1359,6 +1371,8 @@ define(function (require) { } //Remove things that may cause problems in the build. + //deps already merged above + delete config.deps; delete config.jQuery; delete config.enforceDefine; delete config.urlArgs; diff --git a/build/tests/builds.js b/build/tests/builds.js index 3d9fa94a..b69d9796 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2028,6 +2028,26 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan doh.run(); + // deps should be integrated into the build and not trigger + // loads before traceDependencies, where rawText comes into play. + // https://github.com/jrburke/r.js/issues/658 + doh.register("rawTextDeps", + [ + function rawTextDeps(t) { + file.deleteFile("lib/rawTextDeps/built.js"); + + build(["lib/rawTextDeps/build.js"]); + + t.is(nol(c("lib/rawTextDeps/expected.js")), + nol(c("lib/rawTextDeps/built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + //Make sure multiple named modules do not mess up toTransport //https://github.com/jrburke/r.js/issues/366 doh.register("iife", diff --git a/build/tests/lib/depsConfig/expected.js b/build/tests/lib/depsConfig/expected.js index 3121a0d5..9909e90e 100644 --- a/build/tests/lib/depsConfig/expected.js +++ b/build/tests/lib/depsConfig/expected.js @@ -1,12 +1,3 @@ - -define('a',{ - name: 'a' -}); - -define('b',{ - name: 'b' -}); - define('c',{ name: 'c' }); @@ -16,3 +7,12 @@ require(['c'], function (c) { define("main", function(){}); + +define('a',{ + name: 'a' +}); + +define('b',{ + name: 'b' +}); + diff --git a/build/tests/lib/rawTextDeps/b.js b/build/tests/lib/rawTextDeps/b.js new file mode 100644 index 00000000..b8bdcebb --- /dev/null +++ b/build/tests/lib/rawTextDeps/b.js @@ -0,0 +1,4 @@ +define({ + name: 'b' +}); + diff --git a/build/tests/lib/rawTextDeps/build.js b/build/tests/lib/rawTextDeps/build.js new file mode 100644 index 00000000..0691cc8b --- /dev/null +++ b/build/tests/lib/rawTextDeps/build.js @@ -0,0 +1,10 @@ +{ + baseUrl: '.', + rawText: { + 'a': 'define(["b"], function (b) {});' + }, + deps: ['a'], + name: 'main', + optimize: 'none', + out: 'built.js' +} diff --git a/build/tests/lib/rawTextDeps/built.js b/build/tests/lib/rawTextDeps/built.js new file mode 100644 index 00000000..a9ea1023 --- /dev/null +++ b/build/tests/lib/rawTextDeps/built.js @@ -0,0 +1,11 @@ +define('main',{ + name: 'main' +}); + + +define('b',{ + name: 'b' +}); + + +define('a',["b"], function (b) {}); diff --git a/build/tests/lib/rawTextDeps/expected.js b/build/tests/lib/rawTextDeps/expected.js new file mode 100644 index 00000000..a9ea1023 --- /dev/null +++ b/build/tests/lib/rawTextDeps/expected.js @@ -0,0 +1,11 @@ +define('main',{ + name: 'main' +}); + + +define('b',{ + name: 'b' +}); + + +define('a',["b"], function (b) {}); diff --git a/build/tests/lib/rawTextDeps/main.js b/build/tests/lib/rawTextDeps/main.js new file mode 100644 index 00000000..e0d41d3a --- /dev/null +++ b/build/tests/lib/rawTextDeps/main.js @@ -0,0 +1,4 @@ +define({ + name: 'main' +}); + From 87eabfc38d3744b851d402859788c1d441ff80db Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 15:11:18 -0700 Subject: [PATCH 175/382] snapshot --- dist/r.js | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/dist/r.js b/dist/r.js index e7b2b1ef..6f40ba77 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Thu, 22 May 2014 21:11:49 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Thu, 22 May 2014 22:11:06 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Thu, 22 May 2014 21:11:49 GMT', + version = '2.1.11+ Thu, 22 May 2014 22:11:06 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25670,7 +25670,7 @@ define('commonJs', ['env!env/file', 'parse'], function (file, parse) { */ /*jslint plusplus: true, nomen: true, regexp: true */ -/*global define, requirejs */ +/*global define, requirejs, java, process, console */ define('build', function (require) { @@ -26826,7 +26826,7 @@ define('build', function (require) { } else { console.log(content); } - } + }; } //Check for errors in config @@ -26966,10 +26966,11 @@ define('build', function (require) { config.cssPrefix = ''; } - //Cycle through modules and combine any local stubModules with - //global values. + //Cycle through modules and normalize if (config.modules && config.modules.length) { config.modules.forEach(function (mod) { + + //Combine any local stubModules with global values. if (config.stubModules) { mod.stubModules = config.stubModules.concat(mod.stubModules || []); } @@ -26983,6 +26984,17 @@ define('build', function (require) { }); } + // Legacy command support, which allowed a single string ID + // for include. + if (typeof mod.include === 'string') { + mod.include = [mod.include]; + } + + //Add deps to each modules entry. + if (config.deps) { + mod.include = config.deps.concat(mod.include || []); + } + //Allow wrap config in overrides, but normalize it. if (mod.override) { normalizeWrapConfig(mod.override, absFilePath); @@ -27024,6 +27036,8 @@ define('build', function (require) { } //Remove things that may cause problems in the build. + //deps already merged above + delete config.deps; delete config.jQuery; delete config.enforceDefine; delete config.urlArgs; From 7464fe4e748c8c9c2f0a25322652baf29c2dfeb6 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 22 May 2014 15:45:52 -0700 Subject: [PATCH 176/382] mention map config in the full set of build config --- build/example.build.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/example.build.js b/build/example.build.js index 13e202e2..9666bedf 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -48,6 +48,10 @@ "baz": "../another/path/baz" }, + //Sets up a map of module IDs to other module IDs. For more details, see + //the http://requirejs.org/docs/api.html#config-map docs. + map: {}, + //Configure CommonJS packages. See http://requirejs.org/docs/api.html#packages //for more information. packages: [], From 13b879315602e142751945e4ea19d1f04e78e415 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 10:47:54 -0700 Subject: [PATCH 177/382] Refs #658, maintain order of deps before name and include --- build/jslib/build.js | 18 ++++++++++++------ build/tests/lib/depsConfig/expected.js | 16 ++++++++-------- build/tests/lib/rawTextDeps/built.js | 10 +++++----- build/tests/lib/rawTextDeps/expected.js | 10 +++++----- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index ff2c1a46..d68b5128 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1325,11 +1325,6 @@ define(function (require) { mod.include = [mod.include]; } - //Add deps to each modules entry. - if (config.deps) { - mod.include = config.deps.concat(mod.include || []); - } - //Allow wrap config in overrides, but normalize it. if (mod.override) { normalizeWrapConfig(mod.override, absFilePath); @@ -1370,6 +1365,16 @@ define(function (require) { file.exclusionRegExp = config.dirExclusionRegExp; } + //Track the deps, but in a different key, so that they are not loaded + //as part of config seeding before all config is in play (#648). Was + //going to merge this in with "include", but include is added after + //the "name" target. To preserve what r.js has done previously, make + //sure "deps" comes before the "name". + if (config.deps) { + config._depsInclude = config.deps; + } + + //Remove things that may cause problems in the build. //deps already merged above delete config.deps; @@ -1449,7 +1454,8 @@ define(function (require) { logger.trace("\nTracing dependencies for: " + (module.name || (typeof module.out === 'function' ? 'FUNCTION' : module.out))); - include = module.name && !module.create ? [module.name] : []; + include = config._depsInclude || []; + include = include.concat(module.name && !module.create ? [module.name] : []); if (module.include) { include = include.concat(module.include); } diff --git a/build/tests/lib/depsConfig/expected.js b/build/tests/lib/depsConfig/expected.js index 9909e90e..b48ffeb3 100644 --- a/build/tests/lib/depsConfig/expected.js +++ b/build/tests/lib/depsConfig/expected.js @@ -1,3 +1,11 @@ +define('a',{ + name: 'a' +}); + +define('b',{ + name: 'b' +}); + define('c',{ name: 'c' }); @@ -8,11 +16,3 @@ require(['c'], function (c) { define("main", function(){}); -define('a',{ - name: 'a' -}); - -define('b',{ - name: 'b' -}); - diff --git a/build/tests/lib/rawTextDeps/built.js b/build/tests/lib/rawTextDeps/built.js index a9ea1023..d913bbb2 100644 --- a/build/tests/lib/rawTextDeps/built.js +++ b/build/tests/lib/rawTextDeps/built.js @@ -1,11 +1,11 @@ -define('main',{ - name: 'main' -}); - - define('b',{ name: 'b' }); define('a',["b"], function (b) {}); +define('main',{ + name: 'main' +}); + + diff --git a/build/tests/lib/rawTextDeps/expected.js b/build/tests/lib/rawTextDeps/expected.js index a9ea1023..d913bbb2 100644 --- a/build/tests/lib/rawTextDeps/expected.js +++ b/build/tests/lib/rawTextDeps/expected.js @@ -1,11 +1,11 @@ -define('main',{ - name: 'main' -}); - - define('b',{ name: 'b' }); define('a',["b"], function (b) {}); +define('main',{ + name: 'main' +}); + + From 08d6736e3eb18d2c7f2cd14ea21a8c7c52302df1 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 10:48:08 -0700 Subject: [PATCH 178/382] snapshot --- dist/r.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/dist/r.js b/dist/r.js index 6f40ba77..f78e9a87 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Thu, 22 May 2014 22:11:06 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Mon, 26 May 2014 17:47:59 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Thu, 22 May 2014 22:11:06 GMT', + version = '2.1.11+ Mon, 26 May 2014 17:47:59 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -26990,11 +26990,6 @@ define('build', function (require) { mod.include = [mod.include]; } - //Add deps to each modules entry. - if (config.deps) { - mod.include = config.deps.concat(mod.include || []); - } - //Allow wrap config in overrides, but normalize it. if (mod.override) { normalizeWrapConfig(mod.override, absFilePath); @@ -27035,6 +27030,16 @@ define('build', function (require) { file.exclusionRegExp = config.dirExclusionRegExp; } + //Track the deps, but in a different key, so that they are not loaded + //as part of config seeding before all config is in play (#648). Was + //going to merge this in with "include", but include is added after + //the "name" target. To preserve what r.js has done previously, make + //sure "deps" comes before the "name". + if (config.deps) { + config._depsInclude = config.deps; + } + + //Remove things that may cause problems in the build. //deps already merged above delete config.deps; @@ -27114,7 +27119,8 @@ define('build', function (require) { logger.trace("\nTracing dependencies for: " + (module.name || (typeof module.out === 'function' ? 'FUNCTION' : module.out))); - include = module.name && !module.create ? [module.name] : []; + include = config._depsInclude || []; + include = include.concat(module.name && !module.create ? [module.name] : []); if (module.include) { include = include.concat(module.include); } From 4c93b039eeb8801a66b37d7d6eb675d57074821e Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 11:40:46 -0700 Subject: [PATCH 179/382] Fixes #645, but in a very limited scope, just for map. Bigger change should be done in a dot or major release vs fix release --- .gitignore | 1 + build/jslib/build.js | 15 ++++++++++- build/jslib/lang.js | 25 ++++++++++++++++++ build/tests/builds.js | 18 +++++++++++++ build/tests/lib/mapConfigMix/a.js | 3 +++ build/tests/lib/mapConfigMix/b1.js | 3 +++ build/tests/lib/mapConfigMix/build.js | 7 ++++++ build/tests/lib/mapConfigMix/c2.js | 3 +++ build/tests/lib/mapConfigMix/config1.js | 7 ++++++ build/tests/lib/mapConfigMix/config2.js | 7 ++++++ build/tests/lib/mapConfigMix/expected.js | 32 ++++++++++++++++++++++++ 11 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 build/tests/lib/mapConfigMix/a.js create mode 100644 build/tests/lib/mapConfigMix/b1.js create mode 100644 build/tests/lib/mapConfigMix/build.js create mode 100644 build/tests/lib/mapConfigMix/c2.js create mode 100644 build/tests/lib/mapConfigMix/config1.js create mode 100644 build/tests/lib/mapConfigMix/config2.js create mode 100644 build/tests/lib/mapConfigMix/expected.js diff --git a/.gitignore b/.gitignore index 9b228bfa..55b3d721 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ build/tests/lib/mainConfigFile/basic/main-built.js build/tests/lib/mainConfigFile/first/main-built.js build/tests/lib/mainConfigFile/mergeConfig/main-built.js build/tests/lib/mainConfigBaseUrl/www-built +build/tests/lib/mapConfigMix/a-built.js build/tests/lib/moduleThenPlugin/built.js build/tests/lib/modulesExclude/built build/tests/lib/nameInsertion/built.js diff --git a/build/jslib/build.js b/build/jslib/build.js index d68b5128..6c6993e1 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -936,7 +936,20 @@ define(function (require) { if (typeof value === 'object' && value && !isArray && !lang.isFunction(value) && !lang.isRegExp(value)) { - target[prop] = lang.mixin({}, target[prop], value, true); + + // TODO: need to generalize this work, maybe also reuse + // the work done in requirejs configure, perhaps move to + // just a deep copy/merge overall. However, given the + // amount of observable change, wait for a dot release. + // This change is in relation to #645 + if (prop === 'map') { + if (!target.map) { + target.map = {}; + } + lang.deepMix(target.map, source.map); + } else { + target[prop] = lang.mixin({}, target[prop], value, true); + } } else if (isArray) { if (!skipArrays) { // Some config, like packages, are arrays. For those, diff --git a/build/jslib/lang.js b/build/jslib/lang.js index d174a9c9..c444ec92 100644 --- a/build/jslib/lang.js +++ b/build/jslib/lang.js @@ -88,6 +88,31 @@ define(function () { return dest; // Object }, + /** + * Does a deep mix of source into dest, where source values override + * dest values if a winner is needed. + * @param {Object} dest destination object that receives the mixed + * values. + * @param {Object} source source object contributing properties to mix + * in. + * @return {[Object]} returns dest object with the modification. + */ + deepMix: function(dest, source) { + lang.eachProp(source, function (value, prop) { + if (typeof value === 'object' && value && + !lang.isArray(value) && !lang.isFunction(value) && + !(value instanceof RegExp)) { + + if (!dest[prop]) { + dest[prop] = {}; + } + lang.deepMix(dest[prop], value); + } else { + dest[prop] = value; + } + }); + return dest; + }, /** * Does a type of deep copy. Do not give it anything fancy, best diff --git a/build/tests/builds.js b/build/tests/builds.js index b69d9796..94d32f07 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1416,6 +1416,24 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + + doh.register("mapConfigMix", + [ + function mapConfigMix(t) { + file.deleteFile("lib/mapConfigMix/a-built.js"); + + build(["lib/mapConfigMix/build.js"]); + + t.is(nol(c("lib/mapConfigMix/expected.js")), + nol(c("lib/mapConfigMix/a-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + //Tests https://github.com/jrburke/r.js/issues/165 insertRequire doh.register("insertRequire", [ diff --git a/build/tests/lib/mapConfigMix/a.js b/build/tests/lib/mapConfigMix/a.js new file mode 100644 index 00000000..07001da0 --- /dev/null +++ b/build/tests/lib/mapConfigMix/a.js @@ -0,0 +1,3 @@ +define(['b', 'c'], function(b, c) { + +}); diff --git a/build/tests/lib/mapConfigMix/b1.js b/build/tests/lib/mapConfigMix/b1.js new file mode 100644 index 00000000..3a0187df --- /dev/null +++ b/build/tests/lib/mapConfigMix/b1.js @@ -0,0 +1,3 @@ +define({ + name: 'b1' +}); diff --git a/build/tests/lib/mapConfigMix/build.js b/build/tests/lib/mapConfigMix/build.js new file mode 100644 index 00000000..75c9d487 --- /dev/null +++ b/build/tests/lib/mapConfigMix/build.js @@ -0,0 +1,7 @@ +{ + mainConfigFile: ['config1.js', 'config2.js'], + name: 'a', + include: ['config1', 'config2'], + optimize: 'none', + out: 'a-built.js' +} diff --git a/build/tests/lib/mapConfigMix/c2.js b/build/tests/lib/mapConfigMix/c2.js new file mode 100644 index 00000000..0c30af3d --- /dev/null +++ b/build/tests/lib/mapConfigMix/c2.js @@ -0,0 +1,3 @@ +define({ + name: 'c2' +}); diff --git a/build/tests/lib/mapConfigMix/config1.js b/build/tests/lib/mapConfigMix/config1.js new file mode 100644 index 00000000..3ac5b02b --- /dev/null +++ b/build/tests/lib/mapConfigMix/config1.js @@ -0,0 +1,7 @@ +requirejs.config({ + map: { + '*': { + 'b': 'b1' + } + } +}); diff --git a/build/tests/lib/mapConfigMix/config2.js b/build/tests/lib/mapConfigMix/config2.js new file mode 100644 index 00000000..34507b57 --- /dev/null +++ b/build/tests/lib/mapConfigMix/config2.js @@ -0,0 +1,7 @@ +requirejs.config({ + map: { + '*': { + 'c': 'c2' + } + } +}); diff --git a/build/tests/lib/mapConfigMix/expected.js b/build/tests/lib/mapConfigMix/expected.js new file mode 100644 index 00000000..7d6182c3 --- /dev/null +++ b/build/tests/lib/mapConfigMix/expected.js @@ -0,0 +1,32 @@ +define('b1',{ + name: 'b1' +}); + +define('c2',{ + name: 'c2' +}); + +define('a',['b', 'c'], function(b, c) { + +}); + +requirejs.config({ + map: { + '*': { + 'b': 'b1' + } + } +}); + +define("config1", function(){}); + +requirejs.config({ + map: { + '*': { + 'c': 'c2' + } + } +}); + +define("config2", function(){}); + From c4b48ede11c91624aeb78a7bcd6a0d8cff91087a Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 11:40:55 -0700 Subject: [PATCH 180/382] snapshot --- dist/r.js | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index f78e9a87..0206ca6d 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Mon, 26 May 2014 17:47:59 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Mon, 26 May 2014 18:40:49 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Mon, 26 May 2014 17:47:59 GMT', + version = '2.1.11+ Mon, 26 May 2014 18:40:49 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -2730,6 +2730,31 @@ define('lang', function () { return dest; // Object }, + /** + * Does a deep mix of source into dest, where source values override + * dest values if a winner is needed. + * @param {Object} dest destination object that receives the mixed + * values. + * @param {Object} source source object contributing properties to mix + * in. + * @return {[Object]} returns dest object with the modification. + */ + deepMix: function(dest, source) { + lang.eachProp(source, function (value, prop) { + if (typeof value === 'object' && value && + !lang.isArray(value) && !lang.isFunction(value) && + !(value instanceof RegExp)) { + + if (!dest[prop]) { + dest[prop] = {}; + } + lang.deepMix(dest[prop], value); + } else { + dest[prop] = value; + } + }); + return dest; + }, /** * Does a type of deep copy. Do not give it anything fancy, best @@ -26601,7 +26626,20 @@ define('build', function (require) { if (typeof value === 'object' && value && !isArray && !lang.isFunction(value) && !lang.isRegExp(value)) { - target[prop] = lang.mixin({}, target[prop], value, true); + + // TODO: need to generalize this work, maybe also reuse + // the work done in requirejs configure, perhaps move to + // just a deep copy/merge overall. However, given the + // amount of observable change, wait for a dot release. + // This change is in relation to #645 + if (prop === 'map') { + if (!target.map) { + target.map = {}; + } + lang.deepMix(target.map, source.map); + } else { + target[prop] = lang.mixin({}, target[prop], value, true); + } } else if (isArray) { if (!skipArrays) { // Some config, like packages, are arrays. For those, From fd09c0a12536904efd427e763c770dc6592c2eae Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 14:28:20 -0700 Subject: [PATCH 181/382] Fixes #648, dependencies of plugins that are plugin resources should work in a build --- .gitignore | 1 + build/jslib/requirePatch.js | 19 +- build/tests/builds.js | 20 ++ build/tests/lib/pluginDepExec/build.js | 8 + build/tests/lib/pluginDepExec/dep.js | 9 + build/tests/lib/pluginDepExec/expected.js | 27 ++ build/tests/lib/pluginDepExec/main.js | 5 + build/tests/lib/pluginDepExec/plugin1.js | 29 ++ build/tests/lib/pluginDepExec/plugin2.js | 27 ++ build/tests/lib/pluginDepExec/test1.txt | 1 + build/tests/lib/pluginDepExec/test2.txt | 1 + build/tests/lib/pluginDepExec/text.js | 386 ++++++++++++++++++++++ 12 files changed, 530 insertions(+), 3 deletions(-) create mode 100644 build/tests/lib/pluginDepExec/build.js create mode 100644 build/tests/lib/pluginDepExec/dep.js create mode 100644 build/tests/lib/pluginDepExec/expected.js create mode 100644 build/tests/lib/pluginDepExec/main.js create mode 100644 build/tests/lib/pluginDepExec/plugin1.js create mode 100644 build/tests/lib/pluginDepExec/plugin2.js create mode 100644 build/tests/lib/pluginDepExec/test1.txt create mode 100644 build/tests/lib/pluginDepExec/test2.txt create mode 100644 build/tests/lib/pluginDepExec/text.js diff --git a/.gitignore b/.gitignore index 55b3d721..503c9fb2 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ build/tests/lib/packages/main-built.js build/tests/lib/packagesNode/main-built.js build/tests/lib/pathsNoCopy/js-built build/tests/lib/pluginBuilder/main-built.js +build/tests/lib/pluginDepExec/main-built.js build/tests/lib/pluginShimDep/main-built.js build/tests/lib/plugins/main-built.js build/tests/lib/plugins/main-builtPluginFirst.js diff --git a/build/jslib/requirePatch.js b/build/jslib/requirePatch.js index a1655a41..7d21a5fc 100644 --- a/build/jslib/requirePatch.js +++ b/build/jslib/requirePatch.js @@ -174,7 +174,7 @@ define([ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim' if (mod && !mod.defined) { if (parentId && getOwn(needFullExec, parentId)) { - needFullExec[id] = true; + needFullExec[id] = depMap; } } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) || @@ -379,7 +379,7 @@ define([ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim' pluginMod = getOwn(context.registry, pluginId); context.plugins[pluginId] = true; - context.needFullExec[pluginId] = true; + context.needFullExec[pluginId] = map; //If the module is not waiting to finish being defined, //undef it and start over, to get full execution. @@ -456,13 +456,26 @@ define([ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim' var id = map.id, url; + // Fix up any maps that need to be normalized as part of the fullExec + // plumbing for plugins to participate in the build. + if (context.plugins && lang.hasProp(context.plugins, id)) { + lang.eachProp(context.needFullExec, function(value, prop) { + // For plugin entries themselves, they do not have a map + // value in needFullExec, just a "true" entry. + if (value !== true && value.prefix === id && value.unnormalized) { + var map = context.makeModuleMap(value.originalName, value.parentMap); + context.needFullExec[map.id] = map; + } + }); + } + //If build needed a full execution, indicate it //has been done now. But only do it if the context is tracking //that. Only valid for the context used in a build, not for //other contexts being run, like for useLib, plain requirejs //use in node/rhino. if (context.needFullExec && getOwn(context.needFullExec, id)) { - context.fullExec[id] = true; + context.fullExec[id] = map; } //A plugin. diff --git a/build/tests/builds.js b/build/tests/builds.js index 94d32f07..efe3b2ce 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1758,6 +1758,26 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + //Make sure plugin dependencies that need normalization run in a build. + //https://github.com/jrburke/r.js/issues/648 + doh.register("pluginDepExec", + [ + function pluginDepExec(t) { + file.deleteFile("lib/pluginDepExec/main-built.js"); + + build(["lib/pluginDepExec/build.js"]); + + t.is(nol(c("lib/pluginDepExec/expected.js")), + nol(c("lib/pluginDepExec/main-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + + //Make sure a non-strict plugin does not blow up in the build //https://github.com/jrburke/r.js/issues/181 doh.register("nonStrict", diff --git a/build/tests/lib/pluginDepExec/build.js b/build/tests/lib/pluginDepExec/build.js new file mode 100644 index 00000000..9c06922b --- /dev/null +++ b/build/tests/lib/pluginDepExec/build.js @@ -0,0 +1,8 @@ +({ +stubModules: ['plugin1', 'plugin2', 'text'], +baseUrl: ".", +optimize: "none", +name: "main", +out: "main-built.js" +}) + diff --git a/build/tests/lib/pluginDepExec/dep.js b/build/tests/lib/pluginDepExec/dep.js new file mode 100644 index 00000000..b314cf76 --- /dev/null +++ b/build/tests/lib/pluginDepExec/dep.js @@ -0,0 +1,9 @@ + +define(['plugin2!test2.txt'], function(pluginresult) { + 'use strict'; + return { + wrap: function(v) { + return pluginresult + v + pluginresult; + } + }; +}); diff --git a/build/tests/lib/pluginDepExec/expected.js b/build/tests/lib/pluginDepExec/expected.js new file mode 100644 index 00000000..6abbb402 --- /dev/null +++ b/build/tests/lib/pluginDepExec/expected.js @@ -0,0 +1,27 @@ +define('text',{}); +define('plugin2',{load: function(id){throw new Error("Dynamic load not allowed: " + id);}}); + +define('plugin2!test2.txt', function () { return '!test2!';}); + + +define('dep',['plugin2!test2.txt'], function(pluginresult) { + + return { + wrap: function(v) { + return pluginresult + v + pluginresult; + } + }; +}); + +define('plugin1',{load: function(id){throw new Error("Dynamic load not allowed: " + id);}}); + +define('plugin1!test1.txt', function () { return '!test2!test1!test2!';}); + + +require(['plugin1!test1.txt'], function(pluginresult) { + + alert(pluginresult); +}); + +define("main", function(){}); + diff --git a/build/tests/lib/pluginDepExec/main.js b/build/tests/lib/pluginDepExec/main.js new file mode 100644 index 00000000..1a8f5aa2 --- /dev/null +++ b/build/tests/lib/pluginDepExec/main.js @@ -0,0 +1,5 @@ + +require(['plugin1!test1.txt'], function(pluginresult) { + 'use strict'; + alert(pluginresult); +}); diff --git a/build/tests/lib/pluginDepExec/plugin1.js b/build/tests/lib/pluginDepExec/plugin1.js new file mode 100644 index 00000000..f311519c --- /dev/null +++ b/build/tests/lib/pluginDepExec/plugin1.js @@ -0,0 +1,29 @@ +define(['text', 'dep'], function(text, dep) { + 'use strict'; + + var buildMap = {}; + + return { + + load: function(moduleName, parentRequire, onload, config) { + if (buildMap[moduleName]) { + onload(buildMap[moduleName]); + } + else { + text.load(moduleName, parentRequire, function(source) { + var result = dep.wrap(source); + buildMap[moduleName] = result; + onload(buildMap[moduleName]); + }, config); + } + }, + + write: function(pluginName, moduleName, write, config) { + var build = buildMap[moduleName]; + if (build) { + write("define('" + pluginName + "!" + moduleName + "', function () { return '" + build + "';});\n"); + } + } + }; +}); + diff --git a/build/tests/lib/pluginDepExec/plugin2.js b/build/tests/lib/pluginDepExec/plugin2.js new file mode 100644 index 00000000..9db7e733 --- /dev/null +++ b/build/tests/lib/pluginDepExec/plugin2.js @@ -0,0 +1,27 @@ +define(['text'], function(text) { + 'use strict'; + + var buildMap = {}; + + return { + + load: function(moduleName, parentRequire, onload, config) { + if (buildMap[moduleName]) { + onload(buildMap[moduleName]); + } + else { + text.load(moduleName, parentRequire, function(source) { + buildMap[moduleName] = '!' + source + '!'; + onload(buildMap[moduleName]); + }, config); + } + }, + + write: function(pluginName, moduleName, write, config) { + var build = buildMap[moduleName]; + if (build) { + write("define('" + pluginName + "!" + moduleName + "', function () { return '" + build + "';});\n"); + } + } + }; +}); \ No newline at end of file diff --git a/build/tests/lib/pluginDepExec/test1.txt b/build/tests/lib/pluginDepExec/test1.txt new file mode 100644 index 00000000..f079749c --- /dev/null +++ b/build/tests/lib/pluginDepExec/test1.txt @@ -0,0 +1 @@ +test1 \ No newline at end of file diff --git a/build/tests/lib/pluginDepExec/test2.txt b/build/tests/lib/pluginDepExec/test2.txt new file mode 100644 index 00000000..d606037c --- /dev/null +++ b/build/tests/lib/pluginDepExec/test2.txt @@ -0,0 +1 @@ +test2 \ No newline at end of file diff --git a/build/tests/lib/pluginDepExec/text.js b/build/tests/lib/pluginDepExec/text.js new file mode 100644 index 00000000..1e4fc966 --- /dev/null +++ b/build/tests/lib/pluginDepExec/text.js @@ -0,0 +1,386 @@ +/** + * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/text for details + */ +/*jslint regexp: true */ +/*global require, XMLHttpRequest, ActiveXObject, + define, window, process, Packages, + java, location, Components, FileUtils */ + +define(['module'], function (module) { + 'use strict'; + + var text, fs, Cc, Ci, xpcIsWindows, + progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], + xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, + bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, + hasLocation = typeof location !== 'undefined' && location.href, + defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), + defaultHostName = hasLocation && location.hostname, + defaultPort = hasLocation && (location.port || undefined), + buildMap = {}, + masterConfig = (module.config && module.config()) || {}; + + text = { + version: '2.0.10', + + strip: function (content) { + //Strips declarations so that external SVG and XML + //documents can be added to a document without worry. Also, if the string + //is an HTML document, only the part inside the body tag is returned. + if (content) { + content = content.replace(xmlRegExp, ""); + var matches = content.match(bodyRegExp); + if (matches) { + content = matches[1]; + } + } else { + content = ""; + } + return content; + }, + + jsEscape: function (content) { + return content.replace(/(['\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r") + .replace(/[\u2028]/g, "\\u2028") + .replace(/[\u2029]/g, "\\u2029"); + }, + + createXhr: masterConfig.createXhr || function () { + //Would love to dump the ActiveX crap in here. Need IE 6 to die first. + var xhr, i, progId; + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } else if (typeof ActiveXObject !== "undefined") { + for (i = 0; i < 3; i += 1) { + progId = progIds[i]; + try { + xhr = new ActiveXObject(progId); + } catch (e) {} + + if (xhr) { + progIds = [progId]; // so faster next time + break; + } + } + } + + return xhr; + }, + + /** + * Parses a resource name into its component parts. Resource names + * look like: module/name.ext!strip, where the !strip part is + * optional. + * @param {String} name the resource name + * @returns {Object} with properties "moduleName", "ext" and "strip" + * where strip is a boolean. + */ + parseName: function (name) { + var modName, ext, temp, + strip = false, + index = name.indexOf("."), + isRelative = name.indexOf('./') === 0 || + name.indexOf('../') === 0; + + if (index !== -1 && (!isRelative || index > 1)) { + modName = name.substring(0, index); + ext = name.substring(index + 1, name.length); + } else { + modName = name; + } + + temp = ext || modName; + index = temp.indexOf("!"); + if (index !== -1) { + //Pull off the strip arg. + strip = temp.substring(index + 1) === "strip"; + temp = temp.substring(0, index); + if (ext) { + ext = temp; + } else { + modName = temp; + } + } + + return { + moduleName: modName, + ext: ext, + strip: strip + }; + }, + + xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + + /** + * Is an URL on another domain. Only works for browser use, returns + * false in non-browser environments. Only used to know if an + * optimized .js version of a text resource should be loaded + * instead. + * @param {String} url + * @returns Boolean + */ + useXhr: function (url, protocol, hostname, port) { + var uProtocol, uHostName, uPort, + match = text.xdRegExp.exec(url); + if (!match) { + return true; + } + uProtocol = match[2]; + uHostName = match[3]; + + uHostName = uHostName.split(':'); + uPort = uHostName[1]; + uHostName = uHostName[0]; + + return (!uProtocol || uProtocol === protocol) && + (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && + ((!uPort && !uHostName) || uPort === port); + }, + + finishLoad: function (name, strip, content, onLoad) { + content = strip ? text.strip(content) : content; + if (masterConfig.isBuild) { + buildMap[name] = content; + } + onLoad(content); + }, + + load: function (name, req, onLoad, config) { + //Name has format: some.module.filext!strip + //The strip part is optional. + //if strip is present, then that means only get the string contents + //inside a body tag in an HTML string. For XML/SVG content it means + //removing the declarations so the content can be inserted + //into the current doc without problems. + + // Do not bother with the work if a build and text will + // not be inlined. + if (config.isBuild && !config.inlineText) { + onLoad(); + return; + } + + masterConfig.isBuild = config.isBuild; + + var parsed = text.parseName(name), + nonStripName = parsed.moduleName + + (parsed.ext ? '.' + parsed.ext : ''), + url = req.toUrl(nonStripName), + useXhr = (masterConfig.useXhr) || + text.useXhr; + + // Do not load if it is an empty: url + if (url.indexOf('empty:') === 0) { + onLoad(); + return; + } + + //Load the text. Use XHR if possible and in a browser. + if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { + text.get(url, function (content) { + text.finishLoad(name, parsed.strip, content, onLoad); + }, function (err) { + if (onLoad.error) { + onLoad.error(err); + } + }); + } else { + //Need to fetch the resource across domains. Assume + //the resource has been optimized into a JS module. Fetch + //by the module name + extension, but do not include the + //!strip part to avoid file system issues. + req([nonStripName], function (content) { + text.finishLoad(parsed.moduleName + '.' + parsed.ext, + parsed.strip, content, onLoad); + }); + } + }, + + write: function (pluginName, moduleName, write, config) { + if (buildMap.hasOwnProperty(moduleName)) { + var content = text.jsEscape(buildMap[moduleName]); + write.asModule(pluginName + "!" + moduleName, + "define(function () { return '" + + content + + "';});\n"); + } + }, + + writeFile: function (pluginName, moduleName, req, write, config) { + var parsed = text.parseName(moduleName), + extPart = parsed.ext ? '.' + parsed.ext : '', + nonStripName = parsed.moduleName + extPart, + //Use a '.js' file name so that it indicates it is a + //script that can be loaded across domains. + fileName = req.toUrl(parsed.moduleName + extPart) + '.js'; + + //Leverage own load() method to load plugin value, but only + //write out values that do not have the strip argument, + //to avoid any potential issues with ! in file names. + text.load(nonStripName, req, function (value) { + //Use own write() method to construct full module value. + //But need to create shell that translates writeFile's + //write() to the right interface. + var textWrite = function (contents) { + return write(fileName, contents); + }; + textWrite.asModule = function (moduleName, contents) { + return write.asModule(moduleName, fileName, contents); + }; + + text.write(pluginName, nonStripName, textWrite, config); + }, config); + } + }; + + if (masterConfig.env === 'node' || (!masterConfig.env && + typeof process !== "undefined" && + process.versions && + !!process.versions.node && + !process.versions['node-webkit'])) { + //Using special require.nodeRequire, something added by r.js. + fs = require.nodeRequire('fs'); + + text.get = function (url, callback, errback) { + try { + var file = fs.readFileSync(url, 'utf8'); + //Remove BOM (Byte Mark Order) from utf8 files if it is there. + if (file.indexOf('\uFEFF') === 0) { + file = file.substring(1); + } + callback(file); + } catch (e) { + errback(e); + } + }; + } else if (masterConfig.env === 'xhr' || (!masterConfig.env && + text.createXhr())) { + text.get = function (url, callback, errback, headers) { + var xhr = text.createXhr(), header; + xhr.open('GET', url, true); + + //Allow plugins direct access to xhr headers + if (headers) { + for (header in headers) { + if (headers.hasOwnProperty(header)) { + xhr.setRequestHeader(header.toLowerCase(), headers[header]); + } + } + } + + //Allow overrides specified in config + if (masterConfig.onXhr) { + masterConfig.onXhr(xhr, url); + } + + xhr.onreadystatechange = function (evt) { + var status, err; + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + status = xhr.status; + if (status > 399 && status < 600) { + //An http 4xx or 5xx error. Signal an error. + err = new Error(url + ' HTTP status: ' + status); + err.xhr = xhr; + errback(err); + } else { + callback(xhr.responseText); + } + + if (masterConfig.onXhrComplete) { + masterConfig.onXhrComplete(xhr, url); + } + } + }; + xhr.send(null); + }; + } else if (masterConfig.env === 'rhino' || (!masterConfig.env && + typeof Packages !== 'undefined' && typeof java !== 'undefined')) { + //Why Java, why is this so awkward? + text.get = function (url, callback) { + var stringBuffer, line, + encoding = "utf-8", + file = new java.io.File(url), + lineSeparator = java.lang.System.getProperty("line.separator"), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), + content = ''; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + + if (line !== null) { + stringBuffer.append(line); + } + + while ((line = input.readLine()) !== null) { + stringBuffer.append(lineSeparator); + stringBuffer.append(line); + } + //Make sure we return a JavaScript string and not a Java string. + content = String(stringBuffer.toString()); //String + } finally { + input.close(); + } + callback(content); + }; + } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env && + typeof Components !== 'undefined' && Components.classes && + Components.interfaces)) { + //Avert your gaze! + Cc = Components.classes, + Ci = Components.interfaces; + Components.utils['import']('resource://gre/modules/FileUtils.jsm'); + xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc); + + text.get = function (url, callback) { + var inStream, convertStream, fileObj, + readData = {}; + + if (xpcIsWindows) { + url = url.replace(/\//g, '\\'); + } + + fileObj = new FileUtils.File(url); + + //XPCOM, you so crazy + try { + inStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + inStream.init(fileObj, 1, 0, false); + + convertStream = Cc['@mozilla.org/intl/converter-input-stream;1'] + .createInstance(Ci.nsIConverterInputStream); + convertStream.init(inStream, "utf-8", inStream.available(), + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + + convertStream.readString(inStream.available(), readData); + convertStream.close(); + inStream.close(); + callback(readData.value); + } catch (e) { + throw new Error((fileObj && fileObj.path || '') + ': ' + e); + } + }; + } + return text; +}); From 774f156db4f67f4941de4eece97b6e381f68f104 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 14:28:42 -0700 Subject: [PATCH 182/382] snapshot --- dist/r.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/dist/r.js b/dist/r.js index 0206ca6d..a58813e6 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Mon, 26 May 2014 18:40:49 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Mon, 26 May 2014 21:28:31 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Mon, 26 May 2014 18:40:49 GMT', + version = '2.1.11+ Mon, 26 May 2014 21:28:31 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -25261,7 +25261,7 @@ define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'c if (mod && !mod.defined) { if (parentId && getOwn(needFullExec, parentId)) { - needFullExec[id] = true; + needFullExec[id] = depMap; } } else if ((getOwn(needFullExec, id) && falseProp(fullExec, id)) || @@ -25466,7 +25466,7 @@ define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'c pluginMod = getOwn(context.registry, pluginId); context.plugins[pluginId] = true; - context.needFullExec[pluginId] = true; + context.needFullExec[pluginId] = map; //If the module is not waiting to finish being defined, //undef it and start over, to get full execution. @@ -25543,13 +25543,26 @@ define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'c var id = map.id, url; + // Fix up any maps that need to be normalized as part of the fullExec + // plumbing for plugins to participate in the build. + if (context.plugins && lang.hasProp(context.plugins, id)) { + lang.eachProp(context.needFullExec, function(value, prop) { + // For plugin entries themselves, they do not have a map + // value in needFullExec, just a "true" entry. + if (value !== true && value.prefix === id && value.unnormalized) { + var map = context.makeModuleMap(value.originalName, value.parentMap); + context.needFullExec[map.id] = map; + } + }); + } + //If build needed a full execution, indicate it //has been done now. But only do it if the context is tracking //that. Only valid for the context used in a build, not for //other contexts being run, like for useLib, plain requirejs //use in node/rhino. if (context.needFullExec && getOwn(context.needFullExec, id)) { - context.fullExec[id] = true; + context.fullExec[id] = map; } //A plugin. From 6488e69de254b03b2f8f9d0621da3951e43c7c93 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 15:19:58 -0700 Subject: [PATCH 183/382] Fixes #662, use correct context require in req.get --- build/jslib/node.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jslib/node.js b/build/jslib/node.js index b1d9d66c..fbd63313 100644 --- a/build/jslib/node.js +++ b/build/jslib/node.js @@ -81,7 +81,7 @@ //Break any cycles by requiring it normally, but this will //finish synchronously - require([moduleName]); + context.require([moduleName]); //The above calls are sync, so can do the next thing safely. ret = context.defined[moduleName]; From 83d7ffafb7ab05279c6b780816674ca68e4e03aa Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 15:20:08 -0700 Subject: [PATCH 184/382] snapshot --- dist/r.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index a58813e6..f4402939 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Mon, 26 May 2014 21:28:31 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Mon, 26 May 2014 22:20:01 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Mon, 26 May 2014 21:28:31 GMT', + version = '2.1.11+ Mon, 26 May 2014 22:20:01 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -2455,7 +2455,7 @@ var requirejs, require, define, xpcUtil; //Break any cycles by requiring it normally, but this will //finish synchronously - require([moduleName]); + context.require([moduleName]); //The above calls are sync, so can do the next thing safely. ret = context.defined[moduleName]; From fd4c9140a9496e0459eed8cbeb7cf478ccd52b99 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 16:57:49 -0700 Subject: [PATCH 185/382] Fixes #651, do not detect nested dependencies inside a UMD wrapper --- .gitignore | 1 + build/jslib/parse.js | 51 ++- build/tests/builds.js | 19 ++ build/tests/lib/umdNested/a.js | 1 + build/tests/lib/umdNested/build.js | 6 + build/tests/lib/umdNested/expected.js | 454 ++++++++++++++++++++++++++ build/tests/lib/umdNested/lib.js | 445 +++++++++++++++++++++++++ build/tests/lib/umdNested/main.js | 4 + 8 files changed, 975 insertions(+), 6 deletions(-) create mode 100644 build/tests/lib/umdNested/a.js create mode 100644 build/tests/lib/umdNested/build.js create mode 100644 build/tests/lib/umdNested/expected.js create mode 100644 build/tests/lib/umdNested/lib.js create mode 100644 build/tests/lib/umdNested/main.js diff --git a/.gitignore b/.gitignore index 503c9fb2..3a7bc1cd 100644 --- a/.gitignore +++ b/.gitignore @@ -89,6 +89,7 @@ build/tests/lib/stubModules/main-built.js build/tests/lib/stubModules/perModule/built build/tests/lib/transportBeforeMinify/www-built build/tests/lib/umd/main-built.js +build/tests/lib/umdNested/main-built.js build/tests/lib/unicode/main-built.js build/tests/lib/urlToEmpty/main-built.js build/tests/lib/wrap/outBothArray.js diff --git a/build/jslib/parse.js b/build/jslib/parse.js index c843098e..e17df772 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -126,7 +126,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { needsDefine = true, astRoot = esprima.parse(fileContents); - parse.recurse(astRoot, function (callName, config, name, deps) { + parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier) { if (!deps) { deps = []; } @@ -146,6 +146,10 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { }); } + if (factoryIdentifier) { + return factoryIdentifier; + } + //If define was found, no need to dive deeper, unless //the config explicitly wants to dig deeper. return !!options.findNestedDependencies; @@ -200,7 +204,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //Like traverse, but skips if branches that would not be processed //after has application that results in tests of true or false boolean //literal values. - var key, child, + var key, child, result, hasHas = options && options.has; if (!object) { @@ -219,17 +223,50 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { this.recurse(object.alternate, onMatch, options); } } else { - if (this.parseNode(object, onMatch) === false) { + result = this.parseNode(object, onMatch); + if (result === false) { return; + } else if (typeof result === 'string') { + return result; } + for (key in object) { if (object.hasOwnProperty(key)) { child = object[key]; if (typeof child === 'object' && child !== null) { - this.recurse(child, onMatch, options); + result = this.recurse(child, onMatch, options); + if (typeof result === 'string') { + break; + } } } } + + //Check for an identifier for a factory function identifier being + //passed in as a function expression, indicating a UMD-type of + //wrapping. + if (typeof result === 'string') { + if (object.type === 'ExpressionStatement' && object.expression && + object.expression.type === 'CallExpression' && object.expression.callee && + object.expression.callee.type === 'FunctionExpression') { + object = object.expression.callee; + + if (object.params && object.params.length) { + if (object.params.some(function(param) { + //Found an identifier match, so stop parsing from this + //level down. + return param.type === 'Identifier' && + param.name === result; + })) { + //Just a plain return, parsing can continue past this + //point. + return; + } + } + } + + return result; + } } }; @@ -780,7 +817,8 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { name = name.value; } - return onMatch("define", null, name, deps, node); + return onMatch("define", null, name, deps, node, + (factory && factory.type === 'Identifier' ? factory.name : undefined)); } else if (node.type === 'CallExpression' && node.callee && node.callee.type === 'FunctionExpression' && node.callee.body && node.callee.body.body && @@ -807,7 +845,8 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { }); if (refsDefine) { - return onMatch("define", null, null, null, exp.expression); + return onMatch("define", null, null, null, exp.expression, + exp.expression.arguments[0].name); } } } diff --git a/build/tests/builds.js b/build/tests/builds.js index efe3b2ce..a8e1d5fe 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2332,6 +2332,25 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + //Do not not find nested deps in a UMD wrapper + //https://github.com/jrburke/requirejs/issues/651 + doh.register("umdNested", + [ + function umdNested(t) { + file.deleteFile("lib/umdNested/main-built.js"); + + build(["lib/umdNested/build.js"]); + + t.is(nol(c("lib/umdNested/expected.js")), + nol(c("lib/umdNested/main-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + //out function should get source map if available. //https://github.com/jrburke/r.js/issues/590 doh.register("sourcemapOutFunction", diff --git a/build/tests/lib/umdNested/a.js b/build/tests/lib/umdNested/a.js new file mode 100644 index 00000000..68890c9b --- /dev/null +++ b/build/tests/lib/umdNested/a.js @@ -0,0 +1 @@ +define({ name: 'realA' }); diff --git a/build/tests/lib/umdNested/build.js b/build/tests/lib/umdNested/build.js new file mode 100644 index 00000000..27a971db --- /dev/null +++ b/build/tests/lib/umdNested/build.js @@ -0,0 +1,6 @@ +{ + baseUrl: '.', + name: 'main', + out: 'main-built.js', + optimize: 'none' +} diff --git a/build/tests/lib/umdNested/expected.js b/build/tests/lib/umdNested/expected.js new file mode 100644 index 00000000..eb39ec23 --- /dev/null +++ b/build/tests/lib/umdNested/expected.js @@ -0,0 +1,454 @@ +(function (root, factoryFunc) { + if (typeof define === 'function' && define.amd) { + define('lib',[], factoryFunc); + } else { + root.libGlobalName = factoryFunc(); + } +}(this, function () { + +/** + * @license almond 0.2.9 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/almond for details + */ +//Going sloppy to avoid 'use strict' string cost, but strict practices should +//be followed. +/*jslint sloppy: true */ +/*global setTimeout: false */ + +var requirejs, require, define; +(function (undef) { + var main, req, makeMap, handlers, + defined = {}, + waiting = {}, + config = {}, + defining = {}, + hasOwn = Object.prototype.hasOwnProperty, + aps = [].slice, + jsSuffixRegExp = /\.js$/; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var nameParts, nameSegment, mapValue, foundMap, lastIndex, + foundI, foundStarMap, starI, i, j, part, + baseParts = baseName && baseName.split("/"), + map = config.map, + starMap = (map && map['*']) || {}; + + //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) { + //Convert baseName to array, and lop off the last part, + //so that . matches that "directory" and not name of the baseName's + //module. For instance, baseName of "one/two/three", maps to + //"one/two/three.js", but we want the directory, "one/two" for + //this normalization. + baseParts = baseParts.slice(0, baseParts.length - 1); + name = name.split('/'); + lastIndex = name.length - 1; + + // Node .js allowance: + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + name = baseParts.concat(name); + + //start trimDots + for (i = 0; i < name.length; i += 1) { + part = name[i]; + if (part === ".") { + name.splice(i, 1); + i -= 1; + } else if (part === "..") { + if (i === 1 && (name[2] === '..' || name[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) { + name.splice(i - 1, 2); + i -= 2; + } + } + } + //end trimDots + + name = name.join("/"); + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if ((baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join("/"); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function makeRequire(relName, forceSync) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync])); + }; + } + + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(depName) { + return function (value) { + defined[depName] = value; + }; + } + + function callDep(name) { + if (hasProp(waiting, name)) { + var args = waiting[name]; + delete waiting[name]; + defining[name] = true; + main.apply(undef, args); + } + + if (!hasProp(defined, name) && !hasProp(defining, name)) { + throw new Error('No ' + name); + } + return defined[name]; + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Makes a name map, normalizing the name, and using a plugin + * for normalization if necessary. Grabs a ref to plugin + * too, as an optimization. + */ + makeMap = function (name, relName) { + var plugin, + parts = splitPrefix(name), + prefix = parts[0]; + + name = parts[1]; + + if (prefix) { + prefix = normalize(prefix, relName); + plugin = callDep(prefix); + } + + //Normalize according + if (prefix) { + if (plugin && plugin.normalize) { + name = plugin.normalize(name, makeNormalize(relName)); + } else { + name = normalize(name, relName); + } + } else { + name = normalize(name, relName); + parts = splitPrefix(name); + prefix = parts[0]; + name = parts[1]; + if (prefix) { + plugin = callDep(prefix); + } + } + + //Using ridiculous property names for space reasons + return { + f: prefix ? prefix + '!' + name : name, //fullName + n: name, + pr: prefix, + p: plugin + }; + }; + + function makeConfig(name) { + return function () { + return (config && config.config && config.config[name]) || {}; + }; + } + + handlers = { + require: function (name) { + return makeRequire(name); + }, + exports: function (name) { + var e = defined[name]; + if (typeof e !== 'undefined') { + return e; + } else { + return (defined[name] = {}); + } + }, + module: function (name) { + return { + id: name, + uri: '', + exports: defined[name], + config: makeConfig(name) + }; + } + }; + + main = function (name, deps, callback, relName) { + var cjsModule, depName, ret, map, i, + args = [], + callbackType = typeof callback, + usingExports; + + //Use name if no relName + relName = relName || name; + + //Call the callback to define the module, if necessary. + if (callbackType === 'undefined' || callbackType === 'function') { + //Pull out the defined dependencies and pass the ordered + //values to the callback. + //Default to [require, exports, module] if no deps + deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; + for (i = 0; i < deps.length; i += 1) { + map = makeMap(deps[i], relName); + depName = map.f; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + args[i] = handlers.require(name); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + args[i] = handlers.exports(name); + usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + cjsModule = args[i] = handlers.module(name); + } else if (hasProp(defined, depName) || + hasProp(waiting, depName) || + hasProp(defining, depName)) { + args[i] = callDep(depName); + } else if (map.p) { + map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); + args[i] = defined[depName]; + } else { + throw new Error(name + ' missing ' + depName); + } + } + + ret = callback ? callback.apply(defined[name], args) : undefined; + + if (name) { + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (cjsModule && cjsModule.exports !== undef && + cjsModule.exports !== defined[name]) { + defined[name] = cjsModule.exports; + } else if (ret !== undef || !usingExports) { + //Use the return value from the function. + defined[name] = ret; + } + } + } else if (name) { + //May just be an object definition for the module. Only + //worry about defining if have a module name. + defined[name] = callback; + } + }; + + requirejs = require = req = function (deps, callback, relName, forceSync, alt) { + if (typeof deps === "string") { + if (handlers[deps]) { + //callback in this case is really relName + return handlers[deps](callback); + } + //Just return the module wanted. In this scenario, the + //deps arg is the module name, and second arg (if passed) + //is just the relName. + //Normalize module name, if it contains . or .. + return callDep(makeMap(deps, callback).f); + } else if (!deps.splice) { + //deps is a config object, not an array. + config = deps; + if (config.deps) { + req(config.deps, config.callback); + } + if (!callback) { + return; + } + + if (callback.splice) { + //callback is an array, which means it is a dependency list. + //Adjust args if there are dependencies + deps = callback; + callback = relName; + relName = null; + } else { + deps = undef; + } + } + + //Support require(['a']) + callback = callback || function () {}; + + //If relName is a function, it is an errback handler, + //so remove it. + if (typeof relName === 'function') { + relName = forceSync; + forceSync = alt; + } + + //Simulate async callback; + if (forceSync) { + main(undef, deps, callback, relName); + } else { + //Using a non-zero value because of concern for what old browsers + //do, and latest browsers "upgrade" to 4 if lower value is used: + //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: + //If want a value immediately, use require('id') instead -- something + //that works in almond on the global level, but not guaranteed and + //unlikely to work in other AMD implementations. + setTimeout(function () { + main(undef, deps, callback, relName); + }, 4); + } + + return req; + }; + + /** + * Just drops the config on the floor, but returns req in case + * the config return value is used. + */ + req.config = function (cfg) { + return req(cfg); + }; + + /** + * Expose module registry for debugging and tooling + */ + requirejs._defined = defined; + + define = function (name, deps, callback) { + + //This module may not have dependencies + if (!deps.splice) { + //deps is not an array, so probably means + //an object literal or factory function for + //the value. Adjust args. + callback = deps; + deps = []; + } + + if (!hasProp(defined, name) && !hasProp(waiting, name)) { + waiting[name] = [name, deps, callback]; + } + }; + + define.amd = { + jQuery: true + }; +}()); + +define('a', [], function() { + return { + name: 'fakeA' + }; +}); + +define('main', ['a'], function(a) { + return { + name: 'libmain', + a: a + }; +}); + + return require('main'); +})); +define('a',{ name: 'realA' }); + +require(['lib', 'a'], function (lib, a) { + +}); + + +define("main", function(){}); + diff --git a/build/tests/lib/umdNested/lib.js b/build/tests/lib/umdNested/lib.js new file mode 100644 index 00000000..c7fd15f2 --- /dev/null +++ b/build/tests/lib/umdNested/lib.js @@ -0,0 +1,445 @@ +(function (root, factoryFunc) { + if (typeof define === 'function' && define.amd) { + define([], factoryFunc); + } else { + root.libGlobalName = factoryFunc(); + } +}(this, function () { + +/** + * @license almond 0.2.9 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/almond for details + */ +//Going sloppy to avoid 'use strict' string cost, but strict practices should +//be followed. +/*jslint sloppy: true */ +/*global setTimeout: false */ + +var requirejs, require, define; +(function (undef) { + var main, req, makeMap, handlers, + defined = {}, + waiting = {}, + config = {}, + defining = {}, + hasOwn = Object.prototype.hasOwnProperty, + aps = [].slice, + jsSuffixRegExp = /\.js$/; + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @returns {String} normalized name + */ + function normalize(name, baseName) { + var nameParts, nameSegment, mapValue, foundMap, lastIndex, + foundI, foundStarMap, starI, i, j, part, + baseParts = baseName && baseName.split("/"), + map = config.map, + starMap = (map && map['*']) || {}; + + //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) { + //Convert baseName to array, and lop off the last part, + //so that . matches that "directory" and not name of the baseName's + //module. For instance, baseName of "one/two/three", maps to + //"one/two/three.js", but we want the directory, "one/two" for + //this normalization. + baseParts = baseParts.slice(0, baseParts.length - 1); + name = name.split('/'); + lastIndex = name.length - 1; + + // Node .js allowance: + if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) { + name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, ''); + } + + name = baseParts.concat(name); + + //start trimDots + for (i = 0; i < name.length; i += 1) { + part = name[i]; + if (part === ".") { + name.splice(i, 1); + i -= 1; + } else if (part === "..") { + if (i === 1 && (name[2] === '..' || name[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) { + name.splice(i - 1, 2); + i -= 2; + } + } + } + //end trimDots + + name = name.join("/"); + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if ((baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join("/"); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function makeRequire(relName, forceSync) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + return req.apply(undef, aps.call(arguments, 0).concat([relName, forceSync])); + }; + } + + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + + function makeLoad(depName) { + return function (value) { + defined[depName] = value; + }; + } + + function callDep(name) { + if (hasProp(waiting, name)) { + var args = waiting[name]; + delete waiting[name]; + defining[name] = true; + main.apply(undef, args); + } + + if (!hasProp(defined, name) && !hasProp(defining, name)) { + throw new Error('No ' + name); + } + return defined[name]; + } + + //Turns a plugin!resource to [plugin, resource] + //with the plugin being undefined if the name + //did not have a plugin prefix. + function splitPrefix(name) { + var prefix, + index = name ? name.indexOf('!') : -1; + if (index > -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + return [prefix, name]; + } + + /** + * Makes a name map, normalizing the name, and using a plugin + * for normalization if necessary. Grabs a ref to plugin + * too, as an optimization. + */ + makeMap = function (name, relName) { + var plugin, + parts = splitPrefix(name), + prefix = parts[0]; + + name = parts[1]; + + if (prefix) { + prefix = normalize(prefix, relName); + plugin = callDep(prefix); + } + + //Normalize according + if (prefix) { + if (plugin && plugin.normalize) { + name = plugin.normalize(name, makeNormalize(relName)); + } else { + name = normalize(name, relName); + } + } else { + name = normalize(name, relName); + parts = splitPrefix(name); + prefix = parts[0]; + name = parts[1]; + if (prefix) { + plugin = callDep(prefix); + } + } + + //Using ridiculous property names for space reasons + return { + f: prefix ? prefix + '!' + name : name, //fullName + n: name, + pr: prefix, + p: plugin + }; + }; + + function makeConfig(name) { + return function () { + return (config && config.config && config.config[name]) || {}; + }; + } + + handlers = { + require: function (name) { + return makeRequire(name); + }, + exports: function (name) { + var e = defined[name]; + if (typeof e !== 'undefined') { + return e; + } else { + return (defined[name] = {}); + } + }, + module: function (name) { + return { + id: name, + uri: '', + exports: defined[name], + config: makeConfig(name) + }; + } + }; + + main = function (name, deps, callback, relName) { + var cjsModule, depName, ret, map, i, + args = [], + callbackType = typeof callback, + usingExports; + + //Use name if no relName + relName = relName || name; + + //Call the callback to define the module, if necessary. + if (callbackType === 'undefined' || callbackType === 'function') { + //Pull out the defined dependencies and pass the ordered + //values to the callback. + //Default to [require, exports, module] if no deps + deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps; + for (i = 0; i < deps.length; i += 1) { + map = makeMap(deps[i], relName); + depName = map.f; + + //Fast path CommonJS standard dependencies. + if (depName === "require") { + args[i] = handlers.require(name); + } else if (depName === "exports") { + //CommonJS module spec 1.1 + args[i] = handlers.exports(name); + usingExports = true; + } else if (depName === "module") { + //CommonJS module spec 1.1 + cjsModule = args[i] = handlers.module(name); + } else if (hasProp(defined, depName) || + hasProp(waiting, depName) || + hasProp(defining, depName)) { + args[i] = callDep(depName); + } else if (map.p) { + map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {}); + args[i] = defined[depName]; + } else { + throw new Error(name + ' missing ' + depName); + } + } + + ret = callback ? callback.apply(defined[name], args) : undefined; + + if (name) { + //If setting exports via "module" is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + if (cjsModule && cjsModule.exports !== undef && + cjsModule.exports !== defined[name]) { + defined[name] = cjsModule.exports; + } else if (ret !== undef || !usingExports) { + //Use the return value from the function. + defined[name] = ret; + } + } + } else if (name) { + //May just be an object definition for the module. Only + //worry about defining if have a module name. + defined[name] = callback; + } + }; + + requirejs = require = req = function (deps, callback, relName, forceSync, alt) { + if (typeof deps === "string") { + if (handlers[deps]) { + //callback in this case is really relName + return handlers[deps](callback); + } + //Just return the module wanted. In this scenario, the + //deps arg is the module name, and second arg (if passed) + //is just the relName. + //Normalize module name, if it contains . or .. + return callDep(makeMap(deps, callback).f); + } else if (!deps.splice) { + //deps is a config object, not an array. + config = deps; + if (config.deps) { + req(config.deps, config.callback); + } + if (!callback) { + return; + } + + if (callback.splice) { + //callback is an array, which means it is a dependency list. + //Adjust args if there are dependencies + deps = callback; + callback = relName; + relName = null; + } else { + deps = undef; + } + } + + //Support require(['a']) + callback = callback || function () {}; + + //If relName is a function, it is an errback handler, + //so remove it. + if (typeof relName === 'function') { + relName = forceSync; + forceSync = alt; + } + + //Simulate async callback; + if (forceSync) { + main(undef, deps, callback, relName); + } else { + //Using a non-zero value because of concern for what old browsers + //do, and latest browsers "upgrade" to 4 if lower value is used: + //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout: + //If want a value immediately, use require('id') instead -- something + //that works in almond on the global level, but not guaranteed and + //unlikely to work in other AMD implementations. + setTimeout(function () { + main(undef, deps, callback, relName); + }, 4); + } + + return req; + }; + + /** + * Just drops the config on the floor, but returns req in case + * the config return value is used. + */ + req.config = function (cfg) { + return req(cfg); + }; + + /** + * Expose module registry for debugging and tooling + */ + requirejs._defined = defined; + + define = function (name, deps, callback) { + + //This module may not have dependencies + if (!deps.splice) { + //deps is not an array, so probably means + //an object literal or factory function for + //the value. Adjust args. + callback = deps; + deps = []; + } + + if (!hasProp(defined, name) && !hasProp(waiting, name)) { + waiting[name] = [name, deps, callback]; + } + }; + + define.amd = { + jQuery: true + }; +}()); + +define('a', [], function() { + return { + name: 'fakeA' + }; +}); + +define('main', ['a'], function(a) { + return { + name: 'libmain', + a: a + }; +}); + + return require('main'); +})); \ No newline at end of file diff --git a/build/tests/lib/umdNested/main.js b/build/tests/lib/umdNested/main.js new file mode 100644 index 00000000..0126742b --- /dev/null +++ b/build/tests/lib/umdNested/main.js @@ -0,0 +1,4 @@ +require(['lib', 'a'], function (lib, a) { + +}); + From a6d46d515619aab1a38c7292e3ee71c374245983 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 16:58:05 -0700 Subject: [PATCH 186/382] snapshot --- dist/r.js | 55 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/dist/r.js b/dist/r.js index f4402939..05270008 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Mon, 26 May 2014 22:20:01 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.11+ Mon, 26 May 2014 23:57:55 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Mon, 26 May 2014 22:20:01 GMT', + version = '2.1.11+ Mon, 26 May 2014 23:57:55 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22861,7 +22861,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { needsDefine = true, astRoot = esprima.parse(fileContents); - parse.recurse(astRoot, function (callName, config, name, deps) { + parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier) { if (!deps) { deps = []; } @@ -22881,6 +22881,10 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { }); } + if (factoryIdentifier) { + return factoryIdentifier; + } + //If define was found, no need to dive deeper, unless //the config explicitly wants to dig deeper. return !!options.findNestedDependencies; @@ -22935,7 +22939,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { //Like traverse, but skips if branches that would not be processed //after has application that results in tests of true or false boolean //literal values. - var key, child, + var key, child, result, hasHas = options && options.has; if (!object) { @@ -22954,17 +22958,50 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { this.recurse(object.alternate, onMatch, options); } } else { - if (this.parseNode(object, onMatch) === false) { + result = this.parseNode(object, onMatch); + if (result === false) { return; + } else if (typeof result === 'string') { + return result; } + for (key in object) { if (object.hasOwnProperty(key)) { child = object[key]; if (typeof child === 'object' && child !== null) { - this.recurse(child, onMatch, options); + result = this.recurse(child, onMatch, options); + if (typeof result === 'string') { + break; + } } } } + + //Check for an identifier for a factory function identifier being + //passed in as a function expression, indicating a UMD-type of + //wrapping. + if (typeof result === 'string') { + if (object.type === 'ExpressionStatement' && object.expression && + object.expression.type === 'CallExpression' && object.expression.callee && + object.expression.callee.type === 'FunctionExpression') { + object = object.expression.callee; + + if (object.params && object.params.length) { + if (object.params.some(function(param) { + //Found an identifier match, so stop parsing from this + //level down. + return param.type === 'Identifier' && + param.name === result; + })) { + //Just a plain return, parsing can continue past this + //point. + return; + } + } + } + + return result; + } } }; @@ -23515,7 +23552,8 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { name = name.value; } - return onMatch("define", null, name, deps, node); + return onMatch("define", null, name, deps, node, + (factory && factory.type === 'Identifier' ? factory.name : undefined)); } else if (node.type === 'CallExpression' && node.callee && node.callee.type === 'FunctionExpression' && node.callee.body && node.callee.body.body && @@ -23542,7 +23580,8 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { }); if (refsDefine) { - return onMatch("define", null, null, null, exp.expression); + return onMatch("define", null, null, null, exp.expression, + exp.expression.arguments[0].name); } } } From 675fe273d7ea53805294b473a50368a6a133607e Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 26 May 2014 17:54:31 -0700 Subject: [PATCH 187/382] rev 2.1.12 --- build/jslib/x.js | 4 ++-- dist/r.js | 8 ++++---- require.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 1651adb7..a53050aa 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+', + version = '2.1.12', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index 05270008..1da768ca 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.11+ Mon, 26 May 2014 23:57:55 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.11+ Mon, 26 May 2014 23:57:55 GMT', + version = '2.1.12', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.11+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.11+', + version = '2.1.12', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, diff --git a/require.js b/require.js index 5b6f55a7..76578838 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.11+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.11+', + version = '2.1.12', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, From 0247092c0295f75a20d3bb4fb6a17a84840d5b19 Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 27 May 2014 09:32:48 -0700 Subject: [PATCH 188/382] Rev for 2.1.13, and test for jrburke/requirejs#1129 --- .gitignore | 1 + build/jslib/x.js | 4 +-- build/tests/builds.js | 20 +++++++++++++++ build/tests/lib/dotTrim/build.js | 6 +++++ build/tests/lib/dotTrim/expected.js | 38 +++++++++++++++++++++++++++++ dist/r.js | 15 ++++-------- require.js | 11 +++------ 7 files changed, 75 insertions(+), 20 deletions(-) create mode 100644 build/tests/lib/dotTrim/build.js create mode 100644 build/tests/lib/dotTrim/expected.js diff --git a/.gitignore b/.gitignore index 3a7bc1cd..fa35c3ce 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ build/tests/lib/cssRemoveCombined/www-built build/tests/lib/depsConfig/main-built.js build/tests/lib/dormant213/main-built.js build/tests/lib/dotpackage/built +build/tests/lib/dotTrim/built.js build/tests/lib/dualLayerOverride/built build/tests/lib/empty/built build/tests/lib/hasOwnProperty/built.js diff --git a/build/jslib/x.js b/build/jslib/x.js index a53050aa..714f1f3d 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.12', + version = '2.1.13', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/build/tests/builds.js b/build/tests/builds.js index a8e1d5fe..1a336128 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2435,4 +2435,24 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + //Confirm dot trimming still works as usual. + //https://github.com/jrburke/requirejs/issues/1129 + doh.register("dotTrim", + [ + function dotTrim(t) { + file.deleteFile("lib/dotTrim/built.js"); + + build(["lib/dotTrim/build.js"]); + + t.is(nol(c("lib/dotTrim/expected.js")), + nol(c("lib/dotTrim/built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + + }); diff --git a/build/tests/lib/dotTrim/build.js b/build/tests/lib/dotTrim/build.js new file mode 100644 index 00000000..da930469 --- /dev/null +++ b/build/tests/lib/dotTrim/build.js @@ -0,0 +1,6 @@ +{ + baseUrl: '../../../../../requirejs/tests/dotTrim', + name: 'dotTrim-tests', + out: 'built.js', + optimize: 'none' +} diff --git a/build/tests/lib/dotTrim/expected.js b/build/tests/lib/dotTrim/expected.js new file mode 100644 index 00000000..f42be326 --- /dev/null +++ b/build/tests/lib/dotTrim/expected.js @@ -0,0 +1,38 @@ +define('util/helper',{ + name: 'helper' +}); + +define('sub/ext',['../util/helper', 'require'], function(helper, require) { + var helperPath = require.toUrl('../util/helper'); + return { + name: 'ext', + helperPath: helperPath, + helper: helper + }; +}); + +define('spell',['./sub/ext'], function(ext) { + return { + name: 'spell', + ext: ext + }; +}); + +require(["spell"], function(spell) { + doh.register( + "dotTrim", + [ + function dotTrim(t){ + t.is('spell', spell.name); + t.is('ext', spell.ext.name); + t.is('./util/helper', spell.ext.helperPath); + t.is('helper', spell.ext.helper.name); + } + ] + ); + + doh.run(); +}); + +define("dotTrim-tests", function(){}); + diff --git a/dist/r.js b/dist/r.js index 1da768ca..ba7512e3 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.12', + version = '2.1.13', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.12', + version = '2.1.13', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -483,12 +483,7 @@ var requirejs, require, define, xpcUtil; // still work when converted to a path, even though // as an ID it is less than ideal. In larger point // releases, may be better to just kick out an error. - // Also, want to keep IDs that start with 'a/../', so - // that the 'a' part can be used for ID-to-path mapping - // configs like paths/packages config. This is done - // for legacy code expectations, since previous approach - // in this method used that logic. - if (i < 2 || ary[i - 1] === '..') { + if (i === 0 || (i == 1 && ary[2] === '..') || ary[i - 1] === '..') { continue; } else if (i > 0) { ary.splice(i - 1, 2); diff --git a/require.js b/require.js index 76578838..23ee9f8a 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.12', + version = '2.1.13', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -244,12 +244,7 @@ var requirejs, require, define; // still work when converted to a path, even though // as an ID it is less than ideal. In larger point // releases, may be better to just kick out an error. - // Also, want to keep IDs that start with 'a/../', so - // that the 'a' part can be used for ID-to-path mapping - // configs like paths/packages config. This is done - // for legacy code expectations, since previous approach - // in this method used that logic. - if (i < 2 || ary[i - 1] === '..') { + if (i === 0 || (i == 1 && ary[2] === '..') || ary[i - 1] === '..') { continue; } else if (i > 0) { ary.splice(i - 1, 2); From 3943a7ae2f9f3f931239fdab8281c9fbf096ca2c Mon Sep 17 00:00:00 2001 From: jrburke Date: Tue, 27 May 2014 12:02:51 -0700 Subject: [PATCH 189/382] dotTrim test expansion --- build/tests/lib/dotTrim/expected.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/tests/lib/dotTrim/expected.js b/build/tests/lib/dotTrim/expected.js index f42be326..a45bc35d 100644 --- a/build/tests/lib/dotTrim/expected.js +++ b/build/tests/lib/dotTrim/expected.js @@ -18,7 +18,11 @@ define('spell',['./sub/ext'], function(ext) { }; }); -require(["spell"], function(spell) { +define('b',{ + name: 'b' +}); + +require(["require", "spell", "a/../b"], function(require, spell, b) { doh.register( "dotTrim", [ @@ -26,6 +30,8 @@ require(["spell"], function(spell) { t.is('spell', spell.name); t.is('ext', spell.ext.name); t.is('./util/helper', spell.ext.helperPath); + t.is('b', b.name); + t.is('./b.html', require.toUrl('a/../b.html')); t.is('helper', spell.ext.helper.name); } ] From 023f38f090d7238882036e4006a574dfabd51a79 Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 28 May 2014 15:09:32 -0700 Subject: [PATCH 190/382] Fixes jrburke/requirejs#1128, disable the odd throwing the old prim does on duplicate promise resolution.t does not comply with how promises are supposed to operate, and newer prim no longer does it. --- build/jslib/requirePatch.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/jslib/requirePatch.js b/build/jslib/requirePatch.js index 7d21a5fc..bf35c53c 100644 --- a/build/jslib/requirePatch.js +++ b/build/jslib/requirePatch.js @@ -30,6 +30,11 @@ define([ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'commonJs', 'prim' falseProp = lang.falseProp, getOwn = lang.getOwn; + //Turn off throwing on resolution conflict, that was just an older prim + //idea about finding errors early, but does not comply with how promises + //should operate. + prim.hideResolutionConflict = true; + //This method should be called when the patches to require should take hold. return function () { if (!allowRun) { From 295befee19fee5fe11101339bd5e92670519b800 Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 28 May 2014 15:10:58 -0700 Subject: [PATCH 191/382] snapshot --- build/jslib/x.js | 4 ++-- dist/r.js | 24 +++++++++++++++++++----- require.js | 15 ++++++++++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 714f1f3d..db29771d 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.13', + version = '2.1.13+', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index ba7512e3..b32c227c 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.13+ Wed, 28 May 2014 22:10:41 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.13', + version = '2.1.13+ Wed, 28 May 2014 22:10:41 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.13', + version = '2.1.13+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -683,7 +683,16 @@ var requirejs, require, define, xpcUtil; return normalize(name, parentName, applyMap); }); } else { - normalizedName = normalize(name, parentName, applyMap); + // If nested plugin references, then do not try to + // normalize, as it will not normalize correctly. This + // places a restriction on resourceIds, and the longer + // term solution is not to normalize until plugins are + // loaded and all normalizations to allow for async + // loading of a loader plugin. But for now, fixes the + // common uses. Details in #1131 + normalizedName = name.indexOf('!') === -1 ? + normalize(name, parentName, applyMap) : + name; } } else { //A regular module. @@ -25151,6 +25160,11 @@ define('requirePatch', [ 'env!env/file', 'pragma', 'parse', 'lang', 'logger', 'c falseProp = lang.falseProp, getOwn = lang.getOwn; + //Turn off throwing on resolution conflict, that was just an older prim + //idea about finding errors early, but does not comply with how promises + //should operate. + prim.hideResolutionConflict = true; + //This method should be called when the patches to require should take hold. return function () { if (!allowRun) { diff --git a/require.js b/require.js index 23ee9f8a..ff8aa67c 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.13', + version = '2.1.13+', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, @@ -444,7 +444,16 @@ var requirejs, require, define; return normalize(name, parentName, applyMap); }); } else { - normalizedName = normalize(name, parentName, applyMap); + // If nested plugin references, then do not try to + // normalize, as it will not normalize correctly. This + // places a restriction on resourceIds, and the longer + // term solution is not to normalize until plugins are + // loaded and all normalizations to allow for async + // loading of a loader plugin. But for now, fixes the + // common uses. Details in #1131 + normalizedName = name.indexOf('!') === -1 ? + normalize(name, parentName, applyMap) : + name; } } else { //A regular module. From 90ff54a562e27b1c288a2d110132f969251c03ec Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 1 Jun 2014 16:04:08 -0700 Subject: [PATCH 192/382] Fixes jrburke/requirejs#1133, UMD wrapper detection was too aggressive Instead, pass scope of function expression identifiers, and only skip parsing if define uses one of those identifiers. --- .gitignore | 1 + build/jslib/parse.js | 77 ++++++++----- build/tests/builds.js | 20 ++++ build/tests/lib/nonUmdIdentifiers/angular.js | 1 + build/tests/lib/nonUmdIdentifiers/app.js | 1 + build/tests/lib/nonUmdIdentifiers/build.js | 7 ++ build/tests/lib/nonUmdIdentifiers/debug.js | 1 + build/tests/lib/nonUmdIdentifiers/expected.js | 101 ++++++++++++++++++ .../lib/nonUmdIdentifiers/gsn-extensions.js | 1 + build/tests/lib/nonUmdIdentifiers/gsn.js | 1 + build/tests/lib/nonUmdIdentifiers/jquery.js | 1 + build/tests/lib/nonUmdIdentifiers/jqueryui.js | 1 + build/tests/lib/nonUmdIdentifiers/main.js | 84 +++++++++++++++ build/tests/lib/nonUmdIdentifiers/states.js | 1 + 14 files changed, 269 insertions(+), 29 deletions(-) create mode 100644 build/tests/lib/nonUmdIdentifiers/angular.js create mode 100644 build/tests/lib/nonUmdIdentifiers/app.js create mode 100644 build/tests/lib/nonUmdIdentifiers/build.js create mode 100644 build/tests/lib/nonUmdIdentifiers/debug.js create mode 100644 build/tests/lib/nonUmdIdentifiers/expected.js create mode 100644 build/tests/lib/nonUmdIdentifiers/gsn-extensions.js create mode 100644 build/tests/lib/nonUmdIdentifiers/gsn.js create mode 100644 build/tests/lib/nonUmdIdentifiers/jquery.js create mode 100644 build/tests/lib/nonUmdIdentifiers/jqueryui.js create mode 100644 build/tests/lib/nonUmdIdentifiers/main.js create mode 100644 build/tests/lib/nonUmdIdentifiers/states.js diff --git a/.gitignore b/.gitignore index fa35c3ce..f31b7998 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ build/tests/lib/nestedHas/main-builtNeedD.js build/tests/lib/nestedHas/main-builtNested.js build/tests/lib/noexports/main-built.js build/tests/lib/nonStrict/main-built.js +build/tests/lib/nonUmdIdentifiers/main-built.js build/tests/lib/onBuildAllDir/js-built build/tests/lib/onBuildRead/main-built.js build/tests/lib/onBuildWrite/main-built.js diff --git a/build/jslib/parse.js b/build/jslib/parse.js index e17df772..2e74a98f 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -24,7 +24,11 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //This string is saved off because JSLint complains //about obj.arguments use, as 'reserved word' - var argPropName = 'arguments'; + var argPropName = 'arguments', + //Default object to use for "scope" checking for UMD identifiers. + emptyScope = {}, + mixin = lang.mixin, + hasProp = lang.hasProp; //From an esprima example for traversing its ast. function traverse(object, visitor) { @@ -126,7 +130,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { needsDefine = true, astRoot = esprima.parse(fileContents); - parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier) { + parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier, fnExpScope) { if (!deps) { deps = []; } @@ -146,7 +150,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { }); } - if (factoryIdentifier) { + if (callName === 'define' && factoryIdentifier && hasProp(fnExpScope, factoryIdentifier)) { return factoryIdentifier; } @@ -199,14 +203,18 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { * @param {Function} onMatch function to call on a parse match. * @param {Object} [options] This is normally the build config options if * it is passed. + * @param {Object} [fnExpScope] holds list of function expresssion + * argument identifiers, set up internally, not passed in */ - parse.recurse = function (object, onMatch, options) { + parse.recurse = function (object, onMatch, options, fnExpScope) { //Like traverse, but skips if branches that would not be processed //after has application that results in tests of true or false boolean //literal values. - var key, child, result, + var key, child, result, i, params, param, hasHas = options && options.has; + fnExpScope = fnExpScope || emptyScope; + if (!object) { return; } @@ -217,24 +225,44 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { object.test.type === 'Literal') { if (object.test.value) { //Take the if branch - this.recurse(object.consequent, onMatch, options); + this.recurse(object.consequent, onMatch, options, fnExpScope); } else { //Take the else branch - this.recurse(object.alternate, onMatch, options); + this.recurse(object.alternate, onMatch, options, fnExpScope); } } else { - result = this.parseNode(object, onMatch); + result = this.parseNode(object, onMatch, fnExpScope); if (result === false) { return; } else if (typeof result === 'string') { return result; } + //Build up a "scope" object that informs nested recurse calls if + //the define call references an identifier that is likely a UMD + //wrapped function expresion argument. + if (object.type === 'ExpressionStatement' && object.expression && + object.expression.type === 'CallExpression' && object.expression.callee && + object.expression.callee.type === 'FunctionExpression') { + object = object.expression.callee; + + if (object.params && object.params.length) { + params = object.params; + fnExpScope = mixin({}, fnExpScope, true); + for (i = 0; i < params.length; i++) { + param = params[i]; + if (param.type === 'Identifier') { + fnExpScope[param.name] = true; + } + } + } + } + for (key in object) { if (object.hasOwnProperty(key)) { child = object[key]; if (typeof child === 'object' && child !== null) { - result = this.recurse(child, onMatch, options); + result = this.recurse(child, onMatch, options, fnExpScope); if (typeof result === 'string') { break; } @@ -246,23 +274,10 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //passed in as a function expression, indicating a UMD-type of //wrapping. if (typeof result === 'string') { - if (object.type === 'ExpressionStatement' && object.expression && - object.expression.type === 'CallExpression' && object.expression.callee && - object.expression.callee.type === 'FunctionExpression') { - object = object.expression.callee; - - if (object.params && object.params.length) { - if (object.params.some(function(param) { - //Found an identifier match, so stop parsing from this - //level down. - return param.type === 'Identifier' && - param.name === result; - })) { - //Just a plain return, parsing can continue past this - //point. - return; - } - } + if (hasProp(fnExpScope, result)) { + //Just a plain return, parsing can continue past this + //point. + return; } return result; @@ -740,11 +755,14 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { * @param {Function} onMatch a function to call when a match is found. * It is passed the match name, and the config, name, deps possible args. * The config, name and deps args are not normalized. + * @param {Object} fnExpScope an object whose keys are all function + * expression identifiers that should be in scope. Useful for UMD wrapper + * detection to avoid parsing more into the wrapped UMD code. * * @returns {String} a JS source string with the valid require/define call. * Otherwise null. */ - parse.parseNode = function (node, onMatch) { + parse.parseNode = function (node, onMatch, fnExpScope) { var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode, args = node && node[argPropName], callName = parse.hasRequire(node); @@ -818,7 +836,8 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { } return onMatch("define", null, name, deps, node, - (factory && factory.type === 'Identifier' ? factory.name : undefined)); + (factory && factory.type === 'Identifier' ? factory.name : undefined), + fnExpScope); } else if (node.type === 'CallExpression' && node.callee && node.callee.type === 'FunctionExpression' && node.callee.body && node.callee.body.body && @@ -846,7 +865,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { if (refsDefine) { return onMatch("define", null, null, null, exp.expression, - exp.expression.arguments[0].name); + exp.expression.arguments[0].name, fnExpScope); } } } diff --git a/build/tests/builds.js b/build/tests/builds.js index 1a336128..3cc49688 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2351,6 +2351,26 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + //Keep parsing if a define uses an identifier, but is not part of + //a function wrapper for UMD + //https://github.com/jrburke/requirejs/issues/1133 + doh.register("nonUmdIdentifiers", + [ + function nonUmdIdentifiers(t) { + file.deleteFile("lib/nonUmdIdentifiers/main-built.js"); + + build(["lib/nonUmdIdentifiers/build.js"]); + + t.is(nol(c("lib/nonUmdIdentifiers/expected.js")), + nol(c("lib/nonUmdIdentifiers/main-built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + //out function should get source map if available. //https://github.com/jrburke/r.js/issues/590 doh.register("sourcemapOutFunction", diff --git a/build/tests/lib/nonUmdIdentifiers/angular.js b/build/tests/lib/nonUmdIdentifiers/angular.js new file mode 100644 index 00000000..e62003ec --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/angular.js @@ -0,0 +1 @@ +define({ name: 'angular' }); diff --git a/build/tests/lib/nonUmdIdentifiers/app.js b/build/tests/lib/nonUmdIdentifiers/app.js new file mode 100644 index 00000000..61e0678d --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/app.js @@ -0,0 +1 @@ +define({ name: 'app' }); diff --git a/build/tests/lib/nonUmdIdentifiers/build.js b/build/tests/lib/nonUmdIdentifiers/build.js new file mode 100644 index 00000000..e584e79c --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/build.js @@ -0,0 +1,7 @@ +{ + baseUrl: '.', + name: 'main', + out: 'main-built.js', + findNestedDependencies: true, + optimize: 'none' +} diff --git a/build/tests/lib/nonUmdIdentifiers/debug.js b/build/tests/lib/nonUmdIdentifiers/debug.js new file mode 100644 index 00000000..b4b8d487 --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/debug.js @@ -0,0 +1 @@ +define({ name: 'debug' }); diff --git a/build/tests/lib/nonUmdIdentifiers/expected.js b/build/tests/lib/nonUmdIdentifiers/expected.js new file mode 100644 index 00000000..7994fac8 --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/expected.js @@ -0,0 +1,101 @@ +define('jquery',{ name: 'jquery' }); + +define('gsn',{ name: 'gsn' }); + +define('gsn-extensions',{ name: 'gsn-extensions' }); + +define('debug',{ name: 'debug' }); + +define('jqueryui',{ name: 'jqueryiui' }); + +define('app',{ name: 'app' }); + +define('angular',{ name: 'angular' }); + +define('states',{ name: 'states' }); + +(function (global) { + var loadEvents = (function loadTimerObj() { + }()).add('main-init'); + + define('loadEvents', [], loadEvents); + + if (global.__gsnConfig) { + define('gsnConfig', [], global.__gsnConfig); + } else { + define('gsnConfig', [], { empty: true }); + } + + if (global.__requireConfig) { + define('requireConfig', [], global.__requireConfig); + } else { + define('requireConfig', [], { empty: true }); + } + + if (global.__gaq) { + define('gaq', [], global._gaq); + } else { + define('gaq', [], []); + } + + if (global.__index) { + define('index', [], global.__index); + } else { + define('index', [], {}); + } + + define('modernizr', [], global.Modernizr); + + require(['requireConfig', 'gsnConfig'], function (requireConfig, gsnConfig) { + + + var paymentsShim = {}, legacyShim = {}, debugFilter; + + gsnConfig.dropInHeader = global.__dropInHeader; + + define('legacyShim', [], legacyShim); + if (gsnConfig.useLegacyShim) { + global.redesignShim = legacyShim; + } + + + define('paymentsShim', [], paymentsShim); + if (gsnConfig.usePaymentsShim) { + global.paymentsShim = {}; + } + + var + jqKeys = { jquery: 'jquery', ui: 'jqueryui' }, + jQueryAlreadyDefined = global.jQuery, + jQueryUIAlreadyDefined = global.jQuery && global.jQuery.ui; + if (jQueryAlreadyDefined) { + define(jqKeys.jquery, [], function() { return global.jQuery; }); + } + if (jQueryUIAlreadyDefined) { + define(jqKeys.ui, [], function () { return {}; }); + } + + require(['jquery'], function ($) { + }); + + require([ + 'jquery', + 'gsn', + 'gsn-extensions', + 'debug', + + 'jqueryui' + ], function ($, gsn, gsnExtensions, debugLogger) { + function start() {} + + require([ + 'app', + 'angular', + 'modernizr', + + 'states' + ], start); + }); + }); +})(this); + diff --git a/build/tests/lib/nonUmdIdentifiers/gsn-extensions.js b/build/tests/lib/nonUmdIdentifiers/gsn-extensions.js new file mode 100644 index 00000000..baab89fd --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/gsn-extensions.js @@ -0,0 +1 @@ +define({ name: 'gsn-extensions' }); diff --git a/build/tests/lib/nonUmdIdentifiers/gsn.js b/build/tests/lib/nonUmdIdentifiers/gsn.js new file mode 100644 index 00000000..5f0bc839 --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/gsn.js @@ -0,0 +1 @@ +define({ name: 'gsn' }); diff --git a/build/tests/lib/nonUmdIdentifiers/jquery.js b/build/tests/lib/nonUmdIdentifiers/jquery.js new file mode 100644 index 00000000..b9eab548 --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/jquery.js @@ -0,0 +1 @@ +define({ name: 'jquery' }); diff --git a/build/tests/lib/nonUmdIdentifiers/jqueryui.js b/build/tests/lib/nonUmdIdentifiers/jqueryui.js new file mode 100644 index 00000000..6a651c6f --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/jqueryui.js @@ -0,0 +1 @@ +define({ name: 'jqueryiui' }); diff --git a/build/tests/lib/nonUmdIdentifiers/main.js b/build/tests/lib/nonUmdIdentifiers/main.js new file mode 100644 index 00000000..de511bf1 --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/main.js @@ -0,0 +1,84 @@ +(function (global) { + var loadEvents = (function loadTimerObj() { + }()).add('main-init'); + + define('loadEvents', [], loadEvents); + + if (global.__gsnConfig) { + define('gsnConfig', [], global.__gsnConfig); + } else { + define('gsnConfig', [], { empty: true }); + } + + if (global.__requireConfig) { + define('requireConfig', [], global.__requireConfig); + } else { + define('requireConfig', [], { empty: true }); + } + + if (global.__gaq) { + define('gaq', [], global._gaq); + } else { + define('gaq', [], []); + } + + if (global.__index) { + define('index', [], global.__index); + } else { + define('index', [], {}); + } + + define('modernizr', [], global.Modernizr); + + require(['requireConfig', 'gsnConfig'], function (requireConfig, gsnConfig) { + 'use strict'; + + var paymentsShim = {}, legacyShim = {}, debugFilter; + + gsnConfig.dropInHeader = global.__dropInHeader; + + define('legacyShim', [], legacyShim); + if (gsnConfig.useLegacyShim) { + global.redesignShim = legacyShim; + } + + + define('paymentsShim', [], paymentsShim); + if (gsnConfig.usePaymentsShim) { + global.paymentsShim = {}; + } + + var + jqKeys = { jquery: 'jquery', ui: 'jqueryui' }, + jQueryAlreadyDefined = global.jQuery, + jQueryUIAlreadyDefined = global.jQuery && global.jQuery.ui; + if (jQueryAlreadyDefined) { + define(jqKeys.jquery, [], function() { return global.jQuery; }); + } + if (jQueryUIAlreadyDefined) { + define(jqKeys.ui, [], function () { return {}; }); + } + + require(['jquery'], function ($) { + }); + + require([ + 'jquery', + 'gsn', + 'gsn-extensions', + 'debug', + + 'jqueryui' + ], function ($, gsn, gsnExtensions, debugLogger) { + function start() {} + + require([ + 'app', + 'angular', + 'modernizr', + + 'states' + ], start); + }); + }); +})(this); diff --git a/build/tests/lib/nonUmdIdentifiers/states.js b/build/tests/lib/nonUmdIdentifiers/states.js new file mode 100644 index 00000000..e7cc0da2 --- /dev/null +++ b/build/tests/lib/nonUmdIdentifiers/states.js @@ -0,0 +1 @@ +define({ name: 'states' }); From 71b4ee1e5529a6585c84dc228074dc8691d79e82 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 1 Jun 2014 16:04:20 -0700 Subject: [PATCH 193/382] snapshot --- dist/r.js | 81 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 31 deletions(-) diff --git a/dist/r.js b/dist/r.js index b32c227c..d6dbf05b 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.13+ Wed, 28 May 2014 22:10:41 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.13+ Sun, 01 Jun 2014 23:04:13 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.13+ Wed, 28 May 2014 22:10:41 GMT', + version = '2.1.13+ Sun, 01 Jun 2014 23:04:13 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22763,7 +22763,11 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { //This string is saved off because JSLint complains //about obj.arguments use, as 'reserved word' - var argPropName = 'arguments'; + var argPropName = 'arguments', + //Default object to use for "scope" checking for UMD identifiers. + emptyScope = {}, + mixin = lang.mixin, + hasProp = lang.hasProp; //From an esprima example for traversing its ast. function traverse(object, visitor) { @@ -22865,7 +22869,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { needsDefine = true, astRoot = esprima.parse(fileContents); - parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier) { + parse.recurse(astRoot, function (callName, config, name, deps, node, factoryIdentifier, fnExpScope) { if (!deps) { deps = []; } @@ -22885,7 +22889,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { }); } - if (factoryIdentifier) { + if (callName === 'define' && factoryIdentifier && hasProp(fnExpScope, factoryIdentifier)) { return factoryIdentifier; } @@ -22938,14 +22942,18 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { * @param {Function} onMatch function to call on a parse match. * @param {Object} [options] This is normally the build config options if * it is passed. + * @param {Object} [fnExpScope] holds list of function expresssion + * argument identifiers, set up internally, not passed in */ - parse.recurse = function (object, onMatch, options) { + parse.recurse = function (object, onMatch, options, fnExpScope) { //Like traverse, but skips if branches that would not be processed //after has application that results in tests of true or false boolean //literal values. - var key, child, result, + var key, child, result, i, params, param, hasHas = options && options.has; + fnExpScope = fnExpScope || emptyScope; + if (!object) { return; } @@ -22956,24 +22964,44 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { object.test.type === 'Literal') { if (object.test.value) { //Take the if branch - this.recurse(object.consequent, onMatch, options); + this.recurse(object.consequent, onMatch, options, fnExpScope); } else { //Take the else branch - this.recurse(object.alternate, onMatch, options); + this.recurse(object.alternate, onMatch, options, fnExpScope); } } else { - result = this.parseNode(object, onMatch); + result = this.parseNode(object, onMatch, fnExpScope); if (result === false) { return; } else if (typeof result === 'string') { return result; } + //Build up a "scope" object that informs nested recurse calls if + //the define call references an identifier that is likely a UMD + //wrapped function expresion argument. + if (object.type === 'ExpressionStatement' && object.expression && + object.expression.type === 'CallExpression' && object.expression.callee && + object.expression.callee.type === 'FunctionExpression') { + object = object.expression.callee; + + if (object.params && object.params.length) { + params = object.params; + fnExpScope = mixin({}, fnExpScope, true); + for (i = 0; i < params.length; i++) { + param = params[i]; + if (param.type === 'Identifier') { + fnExpScope[param.name] = true; + } + } + } + } + for (key in object) { if (object.hasOwnProperty(key)) { child = object[key]; if (typeof child === 'object' && child !== null) { - result = this.recurse(child, onMatch, options); + result = this.recurse(child, onMatch, options, fnExpScope); if (typeof result === 'string') { break; } @@ -22985,23 +23013,10 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { //passed in as a function expression, indicating a UMD-type of //wrapping. if (typeof result === 'string') { - if (object.type === 'ExpressionStatement' && object.expression && - object.expression.type === 'CallExpression' && object.expression.callee && - object.expression.callee.type === 'FunctionExpression') { - object = object.expression.callee; - - if (object.params && object.params.length) { - if (object.params.some(function(param) { - //Found an identifier match, so stop parsing from this - //level down. - return param.type === 'Identifier' && - param.name === result; - })) { - //Just a plain return, parsing can continue past this - //point. - return; - } - } + if (hasProp(fnExpScope, result)) { + //Just a plain return, parsing can continue past this + //point. + return; } return result; @@ -23479,11 +23494,14 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { * @param {Function} onMatch a function to call when a match is found. * It is passed the match name, and the config, name, deps possible args. * The config, name and deps args are not normalized. + * @param {Object} fnExpScope an object whose keys are all function + * expression identifiers that should be in scope. Useful for UMD wrapper + * detection to avoid parsing more into the wrapped UMD code. * * @returns {String} a JS source string with the valid require/define call. * Otherwise null. */ - parse.parseNode = function (node, onMatch) { + parse.parseNode = function (node, onMatch, fnExpScope) { var name, deps, cjsDeps, arg, factory, exp, refsDefine, bodyNode, args = node && node[argPropName], callName = parse.hasRequire(node); @@ -23557,7 +23575,8 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { } return onMatch("define", null, name, deps, node, - (factory && factory.type === 'Identifier' ? factory.name : undefined)); + (factory && factory.type === 'Identifier' ? factory.name : undefined), + fnExpScope); } else if (node.type === 'CallExpression' && node.callee && node.callee.type === 'FunctionExpression' && node.callee.body && node.callee.body.body && @@ -23585,7 +23604,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { if (refsDefine) { return onMatch("define", null, null, null, exp.expression, - exp.expression.arguments[0].name); + exp.expression.arguments[0].name, fnExpScope); } } } From 400e4338d4b73b9e25eaf70670fa34ce94fca154 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 2 Jun 2014 09:43:33 -0700 Subject: [PATCH 194/382] rev to 2.1.14 --- build/jslib/x.js | 4 ++-- dist/r.js | 8 ++++---- require.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index db29771d..86f323a3 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.13+', + version = '2.1.14', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index d6dbf05b..4254eb3e 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.13+ Sun, 01 Jun 2014 23:04:13 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.13+ Sun, 01 Jun 2014 23:04:13 GMT', + version = '2.1.14', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.13+', + version = '2.1.14', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, diff --git a/require.js b/require.js index ff8aa67c..7f31fa20 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.13+', + version = '2.1.14', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, From cf9abe82e138579b4e8e89e76aa19108645f25e3 Mon Sep 17 00:00:00 2001 From: Victor Homyakov Date: Thu, 5 Jun 2014 20:03:24 +0300 Subject: [PATCH 195/382] Proper URLs for UglifyJS2 options --- build/example.build.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/build/example.build.js b/build/example.build.js index 9666bedf..ed242d1d 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -171,11 +171,12 @@ no_mangle: true }, - //If using UglifyJS for script optimization, these config options can be - //used to pass configuration values to UglifyJS. - //For possible values see: - //http://lisperator.net/uglifyjs/codegen - //http://lisperator.net/uglifyjs/compress + //If using UglifyJS2 for script optimization, these config options can be + //used to pass configuration values to UglifyJS2. + //For possible `output` values see: + //https://github.com/mishoo/UglifyJS2#beautifier-options + //For possible `compress` values see: + //https://github.com/mishoo/UglifyJS2#compressor-options uglify2: { //Example of a specialized config. If you are fine //with the default options, no need to specify From 55b669b603b3fc062ab6f184e2062c0e967a0b27 Mon Sep 17 00:00:00 2001 From: Fraser Nevett Date: Fri, 8 Aug 2014 10:30:08 +0100 Subject: [PATCH 196/382] Fixes #691, allow mainConfigFile to be an array --- build/jslib/build.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 6c6993e1..9a9c6bf9 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -769,7 +769,8 @@ define(function (require) { "excludeShallow": true, "insertRequire": true, "stubModules": true, - "deps": true + "deps": true, + "mainConfigFile": true }; for (i = 0; i < ary.length; i++) { From bba4072396f406cd93348255d4b917e246ddc26c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=BCrlimann?= Date: Thu, 28 Aug 2014 10:20:11 +0200 Subject: [PATCH 197/382] Update link to AMD documentation page The AMD documentation moved from the commonjs wiki to github. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4e390ec6..e9dded45 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # r.js A command line tool for running JavaScript scripts that use the -[Asychronous Module Defintion API (AMD)](http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition) +[Asychronous Module Defintion API (AMD)](https://github.com/amdjs/amdjs-api/blob/master/AMD.md) for declaring and using JavaScript modules and regular JavaScript script files. It is part of the [RequireJS project](http://requirejs.org), and works with From c19a655c15cd8e395963e3d16a22b6897847644c Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Sep 2014 20:50:42 -0700 Subject: [PATCH 198/382] Fixes #704, UMD wrapper skipping had a bug that resulted in jquery define skipped --- .gitignore | 1 + build/jslib/parse.js | 32 +++++----- build/tests/builds.js | 18 ++++++ build/tests/lib/nojQDupeDefine/build.js | 6 ++ build/tests/lib/nojQDupeDefine/expected.js | 70 ++++++++++++++++++++++ build/tests/lib/nojQDupeDefine/jquery.js | 64 ++++++++++++++++++++ build/tests/lib/nojQDupeDefine/main.js | 2 + 7 files changed, 177 insertions(+), 16 deletions(-) create mode 100644 build/tests/lib/nojQDupeDefine/build.js create mode 100644 build/tests/lib/nojQDupeDefine/expected.js create mode 100644 build/tests/lib/nojQDupeDefine/jquery.js create mode 100644 build/tests/lib/nojQDupeDefine/main.js diff --git a/.gitignore b/.gitignore index f31b7998..63ba660e 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ build/tests/lib/nestedHas/main-builtNeedC.js build/tests/lib/nestedHas/main-builtNeedD.js build/tests/lib/nestedHas/main-builtNested.js build/tests/lib/noexports/main-built.js +build/tests/lib/nojQDupeDefine/main-built.js build/tests/lib/nonStrict/main-built.js build/tests/lib/nonUmdIdentifiers/main-built.js build/tests/lib/onBuildAllDir/js-built diff --git a/build/jslib/parse.js b/build/jslib/parse.js index 2e74a98f..d3525fef 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -210,7 +210,7 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //Like traverse, but skips if branches that would not be processed //after has application that results in tests of true or false boolean //literal values. - var key, child, result, i, params, param, + var key, child, result, i, params, param, tempObject, hasHas = options && options.has; fnExpScope = fnExpScope || emptyScope; @@ -240,23 +240,23 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //Build up a "scope" object that informs nested recurse calls if //the define call references an identifier that is likely a UMD - //wrapped function expresion argument. + //wrapped function expression argument. if (object.type === 'ExpressionStatement' && object.expression && object.expression.type === 'CallExpression' && object.expression.callee && object.expression.callee.type === 'FunctionExpression') { - object = object.expression.callee; - - if (object.params && object.params.length) { - params = object.params; - fnExpScope = mixin({}, fnExpScope, true); - for (i = 0; i < params.length; i++) { - param = params[i]; - if (param.type === 'Identifier') { - fnExpScope[param.name] = true; - } + tempObject = object.expression.callee; + + if (tempObject.params && tempObject.params.length) { + params = tempObject.params; + fnExpScope = mixin({}, fnExpScope, true); + for (i = 0; i < params.length; i++) { + param = params[i]; + if (param.type === 'Identifier') { + fnExpScope[param.name] = true; } } } + } for (key in object) { if (object.hasOwnProperty(key)) { @@ -275,12 +275,12 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //wrapping. if (typeof result === 'string') { if (hasProp(fnExpScope, result)) { - //Just a plain return, parsing can continue past this - //point. - return; + //result still in scope, keep jumping out indicating the + //identifier still in use. + return result; } - return result; + return; } } }; diff --git a/build/tests/builds.js b/build/tests/builds.js index 3cc49688..15233be9 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2474,5 +2474,23 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + //Confirm that the UMD skipping still finds jQuery-type inner + //defines inside a partial, non-AMD UMD wrapper. + //https://github.com/jrburke/r.js/issues/704 + doh.register("nojQDupeDefine", + [ + function nojQDupeDefine(t) { + file.deleteFile("lib/nojQDupeDefine/built.js"); + + build(["lib/nojQDupeDefine/build.js"]); + + t.is(nol(c("lib/nojQDupeDefine/expected.js")), + nol(c("lib/nojQDupeDefine/main-built.js"))); + require._buildReset(); + } + + ] + ); + doh.run(); }); diff --git a/build/tests/lib/nojQDupeDefine/build.js b/build/tests/lib/nojQDupeDefine/build.js new file mode 100644 index 00000000..27a971db --- /dev/null +++ b/build/tests/lib/nojQDupeDefine/build.js @@ -0,0 +1,6 @@ +{ + baseUrl: '.', + name: 'main', + out: 'main-built.js', + optimize: 'none' +} diff --git a/build/tests/lib/nojQDupeDefine/expected.js b/build/tests/lib/nojQDupeDefine/expected.js new file mode 100644 index 00000000..0e1dbc0b --- /dev/null +++ b/build/tests/lib/nojQDupeDefine/expected.js @@ -0,0 +1,70 @@ +/*! + * jQuery JavaScript Library v2.1.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-05-01T17:11Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +var jQuery = {}; + +// Register as a named AMD module, since jQuery can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase jquery is used because AMD module names are +// derived from file names, and jQuery is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + +if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function() { + return jQuery; + }); +} + + +return jQuery; + +})); + +require(['jquery'], function() {}); + + +define("main", function(){}); + diff --git a/build/tests/lib/nojQDupeDefine/jquery.js b/build/tests/lib/nojQDupeDefine/jquery.js new file mode 100644 index 00000000..1fa01c91 --- /dev/null +++ b/build/tests/lib/nojQDupeDefine/jquery.js @@ -0,0 +1,64 @@ +/*! + * jQuery JavaScript Library v2.1.1 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2014-05-01T17:11Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper window is present, + // execute the factory and get jQuery + // For environments that do not inherently posses a window with a document + // (such as Node.js), expose a jQuery-making factory as module.exports + // This accentuates the need for the creation of a real window + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +var jQuery = {}; + +// Register as a named AMD module, since jQuery can be concatenated with other +// files that may use define, but not via a proper concatenation script that +// understands anonymous AMD modules. A named AMD is safest and most robust +// way to register. Lowercase jquery is used because AMD module names are +// derived from file names, and jQuery is normally delivered in a lowercase +// file name. Do this after creating the global so that if an AMD module wants +// to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + +if ( typeof define === "function" && define.amd ) { + define( "jquery", [], function() { + return jQuery; + }); +} + + +return jQuery; + +})); diff --git a/build/tests/lib/nojQDupeDefine/main.js b/build/tests/lib/nojQDupeDefine/main.js new file mode 100644 index 00000000..2dbe0906 --- /dev/null +++ b/build/tests/lib/nojQDupeDefine/main.js @@ -0,0 +1,2 @@ +require(['jquery'], function() {}); + From f6c1c23ada5e821360d7be89ddc100a1f42c4593 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 6 Sep 2014 20:51:20 -0700 Subject: [PATCH 199/382] snapshot --- build/jslib/x.js | 4 ++-- dist/r.js | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 86f323a3..0a39d212 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.14+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.14', + version = '2.1.14+', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index 4254eb3e..1190aab9 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.14+ Sun, 07 Sep 2014 03:51:04 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.14', + version = '2.1.14+ Sun, 07 Sep 2014 03:51:04 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -22949,7 +22949,7 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { //Like traverse, but skips if branches that would not be processed //after has application that results in tests of true or false boolean //literal values. - var key, child, result, i, params, param, + var key, child, result, i, params, param, tempObject, hasHas = options && options.has; fnExpScope = fnExpScope || emptyScope; @@ -22979,23 +22979,23 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { //Build up a "scope" object that informs nested recurse calls if //the define call references an identifier that is likely a UMD - //wrapped function expresion argument. + //wrapped function expression argument. if (object.type === 'ExpressionStatement' && object.expression && object.expression.type === 'CallExpression' && object.expression.callee && object.expression.callee.type === 'FunctionExpression') { - object = object.expression.callee; - - if (object.params && object.params.length) { - params = object.params; - fnExpScope = mixin({}, fnExpScope, true); - for (i = 0; i < params.length; i++) { - param = params[i]; - if (param.type === 'Identifier') { - fnExpScope[param.name] = true; - } + tempObject = object.expression.callee; + + if (tempObject.params && tempObject.params.length) { + params = tempObject.params; + fnExpScope = mixin({}, fnExpScope, true); + for (i = 0; i < params.length; i++) { + param = params[i]; + if (param.type === 'Identifier') { + fnExpScope[param.name] = true; } } } + } for (key in object) { if (object.hasOwnProperty(key)) { @@ -23014,12 +23014,12 @@ define('parse', ['./esprimaAdapter', 'lang'], function (esprima, lang) { //wrapping. if (typeof result === 'string') { if (hasProp(fnExpScope, result)) { - //Just a plain return, parsing can continue past this - //point. - return; + //result still in scope, keep jumping out indicating the + //identifier still in use. + return result; } - return result; + return; } } }; From dd2772a9ab41eea422618c1c15a6339cf3e30580 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Sep 2014 12:28:45 -0700 Subject: [PATCH 200/382] snapshot --- dist/r.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dist/r.js b/dist/r.js index 1190aab9..86b82392 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.14+ Sun, 07 Sep 2014 03:51:04 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.14+ Sun, 07 Sep 2014 19:28:35 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.14+ Sun, 07 Sep 2014 03:51:04 GMT', + version = '2.1.14+ Sun, 07 Sep 2014 19:28:35 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -26539,7 +26539,8 @@ define('build', function (require) { "excludeShallow": true, "insertRequire": true, "stubModules": true, - "deps": true + "deps": true, + "mainConfigFile": true }; for (i = 0; i < ary.length; i++) { From e764f5c476fa665fd9ac60d82b20ad4b0e65f3fe Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 7 Sep 2014 17:46:34 -0700 Subject: [PATCH 201/382] rev for 2.1.15 --- build/jslib/x.js | 4 ++-- dist/r.js | 8 ++++---- require.js | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 0a39d212..48a1e051 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.14+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.14+', + version = '2.1.15', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, diff --git a/dist/r.js b/dist/r.js index 86b82392..ed177d8e 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.14+ Sun, 07 Sep 2014 19:28:35 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.14+ Sun, 07 Sep 2014 19:28:35 GMT', + version = '2.1.15', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -238,7 +238,7 @@ var requirejs, require, define, xpcUtil; } /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -251,7 +251,7 @@ var requirejs, require, define, xpcUtil; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.14', + version = '2.1.15', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, diff --git a/require.js b/require.js index 7f31fa20..77a5bb1d 100644 --- a/require.js +++ b/require.js @@ -1,5 +1,5 @@ /** vim: et:ts=4:sw=4:sts=4 - * @license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -12,7 +12,7 @@ var requirejs, require, define; (function (global) { var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, - version = '2.1.14', + version = '2.1.15', commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, jsSuffixRegExp = /\.js$/, From b2bcbae4529579e4edf4249ffc7c5850c19fda6b Mon Sep 17 00:00:00 2001 From: "Anders D. Johnson" Date: Wed, 24 Dec 2014 12:58:10 -0600 Subject: [PATCH 202/382] Fix typo on rawText in example.build.js --- build/example.build.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/example.build.js b/build/example.build.js index ed242d1d..93928306 100644 --- a/build/example.build.js +++ b/build/example.build.js @@ -575,7 +575,7 @@ //Introduced in 2.1.3: Seed raw text contents for the listed module IDs. //These text contents will be used instead of doing a file IO call for - //those modules. Useful is some module ID contents are dynamically + //those modules. Useful if some module ID contents are dynamically //based on user input, which is common in web build tools. rawText: { 'some/id': 'define(["another/id"], function () {});' From 79bd50c653a541b395f88b6c3e884b6267f1ccbd Mon Sep 17 00:00:00 2001 From: James Burke Date: Wed, 24 Dec 2014 22:19:38 -0800 Subject: [PATCH 203/382] Fixes #740, nashorn support. Thanks to @ceedriic for pointing out API calls needed. --- build/jslib/lang.js | 4 ++- build/jslib/rhino/file.js | 8 +++++- build/jslib/x.js | 16 +++++++++--- build/tests/alljnashorn.sh | 3 +++ build/tests/transform.js | 8 ++++-- .../expected/indentedArrayFunc-nashorn.js | 25 +++++++++++++++++++ tests/alljnashorn.sh | 1 + 7 files changed, 57 insertions(+), 8 deletions(-) create mode 100755 build/tests/alljnashorn.sh create mode 100644 build/tests/transform/expected/indentedArrayFunc-nashorn.js create mode 100755 tests/alljnashorn.sh diff --git a/build/jslib/lang.js b/build/jslib/lang.js index c444ec92..15b7a08d 100644 --- a/build/jslib/lang.js +++ b/build/jslib/lang.js @@ -21,7 +21,9 @@ define(function () { return false; }; - if (typeof java !== 'undefined' && java.lang && java.lang.Object) { + //Rhino, but not Nashorn (detected by importPackage not existing) + //Can have some strange foreign objects. + if (typeof java !== 'undefined' && java.lang && java.lang.Object && typeof importPackage !== 'undefined') { isJavaObj = function (obj) { return obj instanceof java.lang.Object; }; diff --git a/build/jslib/rhino/file.js b/build/jslib/rhino/file.js index e6478590..ac1f0e53 100644 --- a/build/jslib/rhino/file.js +++ b/build/jslib/rhino/file.js @@ -236,7 +236,13 @@ define(['prim'], function (prim) { os = new java.io.BufferedWriter(outWriter); try { - os.write(fileContents); + //If in Nashorn, need to coerce the JS string to a Java string so that + //writer.write method dispatch correctly detects the type. + if (typeof importPackage !== 'undefined') { + os.write(fileContents); + } else { + os.write(new java.lang.String(fileContents)); + } } finally { os.close(); } diff --git a/build/jslib/x.js b/build/jslib/x.js index 48a1e051..522da317 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -102,11 +102,19 @@ var requirejs, require, define, xpcUtil; } //Set up execution context. - rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); + //Nashorn has importPackage, so branch on that + if (typeof importPackage !== 'undefined') { + rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); - exec = function (string, name) { - return rhinoContext.evaluateString(this, string, name, 0, null); - }; + exec = function (string, name) { + return rhinoContext.evaluateString(this, string, name, 0, null); + }; + } else { + exec = function (string, name) { + load({ script: string, name: name}); + }; + readFile = readFully; + } exists = function (fileName) { return (new java.io.File(fileName)).exists(); diff --git a/build/tests/alljnashorn.sh b/build/tests/alljnashorn.sh new file mode 100755 index 00000000..23e1941e --- /dev/null +++ b/build/tests/alljnashorn.sh @@ -0,0 +1,3 @@ +set -e + +jjs -scripting ../../r.js -- all.js diff --git a/build/tests/transform.js b/build/tests/transform.js index 1564b163..efac1e2f 100644 --- a/build/tests/transform.js +++ b/build/tests/transform.js @@ -64,7 +64,11 @@ define(['transform', 'env!env/file'], function (transform, file) { //comparison file to use for the results. xpconnect //version is also different. if (isRhino) { - overideName = 'indentedArrayFunc-rhino.js'; + if (typeof importPackage !== 'undefined') { + overideName = 'indentedArrayFunc-rhino.js'; + } else { + overideName = 'indentedArrayFunc-nashorn.js'; + } } else if (isXpConnect) { overideName = 'indentedArrayFunc-xpconnect.js'; } @@ -77,4 +81,4 @@ define(['transform', 'env!env/file'], function (transform, file) { ] ); doh.run(); -}); \ No newline at end of file +}); diff --git a/build/tests/transform/expected/indentedArrayFunc-nashorn.js b/build/tests/transform/expected/indentedArrayFunc-nashorn.js new file mode 100644 index 00000000..442112e0 --- /dev/null +++ b/build/tests/transform/expected/indentedArrayFunc-nashorn.js @@ -0,0 +1,25 @@ +//Try a config that is indented, and has an array value, with a function. +(function () { + require.config({ + baseUrl: "some/thing", + packages: [ + "a", + "b", + "another" + ], + shim: { + backbone: { + deps: [ + "underscore", + "jquery" + ], + exports: "Backbone", + init: function (underscore, jquery) { + //Do the harsh removal. + return Backbone.noConflict(true); + } + } + }, + waitSeconds: 0 + }); +}()); diff --git a/tests/alljnashorn.sh b/tests/alljnashorn.sh new file mode 100755 index 00000000..bb38d3a4 --- /dev/null +++ b/tests/alljnashorn.sh @@ -0,0 +1 @@ +jjs -scripting ../r.js -- all.js From 72489e30eace1ecbcebc5d4686b824f2de464fde Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 24 Dec 2014 23:18:09 -0800 Subject: [PATCH 204/382] snapshot --- dist/r.js | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/dist/r.js b/dist/r.js index ed177d8e..45dcbb11 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15 Thu, 25 Dec 2014 07:17:47 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15', + version = '2.1.15 Thu, 25 Dec 2014 07:17:47 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -102,11 +102,19 @@ var requirejs, require, define, xpcUtil; } //Set up execution context. - rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); + //Nashorn has importPackage, so branch on that + if (typeof importPackage !== 'undefined') { + rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); - exec = function (string, name) { - return rhinoContext.evaluateString(this, string, name, 0, null); - }; + exec = function (string, name) { + return rhinoContext.evaluateString(this, string, name, 0, null); + }; + } else { + exec = function (string, name) { + load({ script: string, name: name}); + }; + readFile = readFully; + } exists = function (fileName) { return (new java.io.File(fileName)).exists(); @@ -2667,7 +2675,9 @@ define('lang', function () { return false; }; - if (typeof java !== 'undefined' && java.lang && java.lang.Object) { + //Rhino, but not Nashorn (detected by importPackage not existing) + //Can have some strange foreign objects. + if (typeof java !== 'undefined' && java.lang && java.lang.Object && typeof importPackage !== 'undefined') { isJavaObj = function (obj) { return obj instanceof java.lang.Object; }; @@ -4014,7 +4024,13 @@ define('rhino/file', ['prim'], function (prim) { os = new java.io.BufferedWriter(outWriter); try { - os.write(fileContents); + //If in Nashorn, need to coerce the JS string to a Java string so that + //writer.write method dispatch correctly detects the type. + if (typeof importPackage !== 'undefined') { + os.write(fileContents); + } else { + os.write(new java.lang.String(fileContents)); + } } finally { os.close(); } From 71fc5790438edc257181c28ce864c33bbf699cc8 Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 24 Dec 2014 23:21:56 -0800 Subject: [PATCH 205/382] rev version to indicate past 2.1.15 --- build/jslib/x.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 522da317..919de2cc 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15', + version = '2.1.15+', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, From 60c010ea1b6089783c4bc2b388fda4100dada8f9 Mon Sep 17 00:00:00 2001 From: jrburke Date: Wed, 24 Dec 2014 23:22:11 -0800 Subject: [PATCH 206/382] snapshot --- dist/r.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/r.js b/dist/r.js index 45dcbb11..7d74b19c 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15 Thu, 25 Dec 2014 07:17:47 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Thu, 25 Dec 2014 07:21:59 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15 Thu, 25 Dec 2014 07:17:47 GMT', + version = '2.1.15+ Thu, 25 Dec 2014 07:21:59 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, From ef989bf5705bb5c52e040903320e323d21fc9310 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 25 Dec 2014 14:51:37 -0800 Subject: [PATCH 207/382] Fix incorrect comment from #740 --- build/jslib/x.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/build/jslib/x.js b/build/jslib/x.js index 919de2cc..64c8672a 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -101,8 +101,11 @@ var requirejs, require, define, xpcUtil; fileName = args[1]; } - //Set up execution context. - //Nashorn has importPackage, so branch on that + //Exec/readFile differs between Rhino and Nashorn. Rhino has an + //importPackage where Nashorn does not, so branch on that. This is a + //coarser check -- detecting readFile existence might also be enough for + //this spot. However, sticking with importPackage to keep it the same + //as other Rhino/Nashorn detection branches. if (typeof importPackage !== 'undefined') { rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); From e471015779138cd0df8e9688b1a719fd2918c726 Mon Sep 17 00:00:00 2001 From: jrburke Date: Thu, 25 Dec 2014 14:51:52 -0800 Subject: [PATCH 208/382] snapshot --- dist/r.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index 7d74b19c..7a006dc9 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15+ Thu, 25 Dec 2014 07:21:59 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Thu, 25 Dec 2014 22:51:40 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15+ Thu, 25 Dec 2014 07:21:59 GMT', + version = '2.1.15+ Thu, 25 Dec 2014 22:51:40 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -101,8 +101,11 @@ var requirejs, require, define, xpcUtil; fileName = args[1]; } - //Set up execution context. - //Nashorn has importPackage, so branch on that + //Exec/readFile differs between Rhino and Nashorn. Rhino has an + //importPackage where Nashorn does not, so branch on that. This is a + //coarser check -- detecting readFile existence might also be enough for + //this spot. However, sticking with importPackage to keep it the same + //as other Rhino/Nashorn detection branches. if (typeof importPackage !== 'undefined') { rhinoContext = Packages.org.mozilla.javascript.ContextFactory.getGlobal().enterContext(); From 0b5f9b79df6f9a8748779ce4e268ae66244f0c65 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 28 Dec 2014 21:36:41 -0800 Subject: [PATCH 209/382] update test to match text.js 2.0.13 --- build/tests/lib/moduleThenPlugin/expected.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/tests/lib/moduleThenPlugin/expected.js b/build/tests/lib/moduleThenPlugin/expected.js index aa9c09f2..fd8d0b16 100644 --- a/build/tests/lib/moduleThenPlugin/expected.js +++ b/build/tests/lib/moduleThenPlugin/expected.js @@ -6,7 +6,7 @@ require(['sub1'], function (sub1) {}); define("main", function(){}); /** - * @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS text 2.0.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/requirejs/text for details */ @@ -30,7 +30,7 @@ define('text',['module'], function (module) { masterConfig = (module.config && module.config()) || {}; text = { - version: '2.0.12', + version: '2.0.13', strip: function (content) { //Strips declarations so that external SVG and XML @@ -92,13 +92,13 @@ define('text',['module'], function (module) { parseName: function (name) { var modName, ext, temp, strip = false, - index = name.indexOf("."), + index = name.lastIndexOf("."), isRelative = name.indexOf('./') === 0 || name.indexOf('../') === 0; if (index !== -1 && (!isRelative || index > 1)) { modName = name.substring(0, index); - ext = name.substring(index + 1, name.length); + ext = name.substring(index + 1); } else { modName = name; } @@ -259,7 +259,7 @@ define('text',['module'], function (module) { try { var file = fs.readFileSync(url, 'utf8'); //Remove BOM (Byte Mark Order) from utf8 files if it is there. - if (file.indexOf('\uFEFF') === 0) { + if (file[0] === '\uFEFF') { file = file.substring(1); } callback(file); From c9e4b25b500600b34e79bef95e8981da0d71bcdc Mon Sep 17 00:00:00 2001 From: Jon Bretman Date: Mon, 17 Nov 2014 20:36:25 +0000 Subject: [PATCH 210/382] start fileContents with wrap.start to keep sourceMap line numbers in sync --- build/jslib/build.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 9a9c6bf9..97993641 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1735,7 +1735,7 @@ define(function (require) { } //Write the built module to disk, and build up the build output. - fileContents = ""; + fileContents = config.wrap ? config.wrap.start : ""; return prim.serial(layer.buildFilePaths.map(function (path) { return function () { var lineCount, @@ -1974,7 +1974,7 @@ define(function (require) { }).then(function () { return { text: config.wrap ? - config.wrap.start + fileContents + config.wrap.end : + fileContents + config.wrap.end : fileContents, buildText: buildFileContents, sourceMap: sourceMapGenerator ? From 76b75e5b8b04cd3871bc90e3130e04e935b76e1c Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 2 Feb 2015 16:38:31 -0800 Subject: [PATCH 211/382] update test to match latest text.js file --- build/tests/lib/moduleThenPlugin/expected.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/build/tests/lib/moduleThenPlugin/expected.js b/build/tests/lib/moduleThenPlugin/expected.js index fd8d0b16..b519c25a 100644 --- a/build/tests/lib/moduleThenPlugin/expected.js +++ b/build/tests/lib/moduleThenPlugin/expected.js @@ -6,7 +6,7 @@ require(['sub1'], function (sub1) {}); define("main", function(){}); /** - * @license RequireJS text 2.0.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license RequireJS text 2.0.13+ Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/requirejs/text for details */ @@ -30,7 +30,7 @@ define('text',['module'], function (module) { masterConfig = (module.config && module.config()) || {}; text = { - version: '2.0.13', + version: '2.0.13+', strip: function (content) { //Strips declarations so that external SVG and XML @@ -251,7 +251,8 @@ define('text',['module'], function (module) { typeof process !== "undefined" && process.versions && !!process.versions.node && - !process.versions['node-webkit'])) { + !process.versions['node-webkit'] && + !process.versions['atom-shell'])) { //Using special require.nodeRequire, something added by r.js. fs = require.nodeRequire('fs'); From 1f71c9e3d4b5fd9351ecf9f3597a73648a8f734c Mon Sep 17 00:00:00 2001 From: anshulguleria Date: Sat, 7 Feb 2015 22:20:59 +0530 Subject: [PATCH 212/382] Corrects the path for requireLib in http test. Earlier value assumes the folder where project is cloned should be named requirejs. Thus changed the path to go one level less back for require.js path. --- build/tests/http/httpBuild.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tests/http/httpBuild.js b/build/tests/http/httpBuild.js index 3226a22f..0893e271 100644 --- a/build/tests/http/httpBuild.js +++ b/build/tests/http/httpBuild.js @@ -20,7 +20,7 @@ config = { //in use, change this path to that file. One possibility //could be the one at: //https://github.com/ajaxorg/ace/blob/master/build_support/mini_require.js - requireLib: '../../../../../requirejs/require' + requireLib: '../../../../require' }, //Uncomment this line if uglify minification is not wanted. //optimize: 'none', From 0b95168d183f2cb83e39ae53b9b8060edf6d1c7c Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 7 Feb 2015 11:28:07 -0800 Subject: [PATCH 213/382] Fixes #776, use esprima 2.0 --- build/jslib/esprima.js | 1834 ++++++++++++++++++++++++---------------- 1 file changed, 1117 insertions(+), 717 deletions(-) diff --git a/build/jslib/esprima.js b/build/jslib/esprima.js index 593021f5..a1f80c83 100644 --- a/build/jslib/esprima.js +++ b/build/jslib/esprima.js @@ -31,17 +31,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*jslint bitwise:true plusplus:true */ -/*global esprima:true, define:true, exports:true, window: true, -throwErrorTolerant: true, -throwError: true, generateStatement: true, peek: true, -parseAssignmentExpression: true, parseBlock: true, parseExpression: true, -parseFunctionDeclaration: true, parseFunctionExpression: true, -parseFunctionSourceElements: true, parseVariableIdentifier: true, -parseLeftHandSideExpression: true, -parseUnaryExpression: true, -parseStatement: true, parseSourceElement: true */ - (function (root, factory) { 'use strict'; @@ -63,17 +52,16 @@ parseStatement: true, parseSourceElement: true */ TokenName, FnExprTokens, Syntax, + PlaceHolders, PropertyKind, Messages, Regex, - SyntaxTreeDelegate, source, strict, index, lineNumber, lineStart, length, - delegate, lookahead, state, extra; @@ -115,6 +103,7 @@ parseStatement: true, parseSourceElement: true */ Syntax = { AssignmentExpression: 'AssignmentExpression', ArrayExpression: 'ArrayExpression', + ArrowFunctionExpression: 'ArrowFunctionExpression', BlockStatement: 'BlockStatement', BinaryExpression: 'BinaryExpression', BreakStatement: 'BreakStatement', @@ -155,6 +144,12 @@ parseStatement: true, parseSourceElement: true */ WithStatement: 'WithStatement' }; + PlaceHolders = { + ArrowParameterPlaceHolder: { + type: 'ArrowParameterPlaceHolder' + } + }; + PropertyKind = { Data: 1, Get: 2, @@ -163,45 +158,45 @@ parseStatement: true, parseSourceElement: true */ // Error messages should be identical to V8. Messages = { - UnexpectedToken: 'Unexpected token %0', - UnexpectedNumber: 'Unexpected number', - UnexpectedString: 'Unexpected string', - UnexpectedIdentifier: 'Unexpected identifier', - UnexpectedReserved: 'Unexpected reserved word', - UnexpectedEOS: 'Unexpected end of input', - NewlineAfterThrow: 'Illegal newline after throw', + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', InvalidRegExp: 'Invalid regular expression', - UnterminatedRegExp: 'Invalid regular expression: missing /', - InvalidLHSInAssignment: 'Invalid left-hand side in assignment', - InvalidLHSInForIn: 'Invalid left-hand side in for-in', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', MultipleDefaultsInSwitch: 'More than one default clause in switch statement', - NoCatchOrFinally: 'Missing catch or finally after try', + NoCatchOrFinally: 'Missing catch or finally after try', UnknownLabel: 'Undefined label \'%0\'', Redeclaration: '%0 \'%1\' has already been declared', IllegalContinue: 'Illegal continue statement', IllegalBreak: 'Illegal break statement', IllegalReturn: 'Illegal return statement', - StrictModeWith: 'Strict mode code may not include a with statement', - StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', - StrictVarName: 'Variable name may not be eval or arguments in strict mode', - StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', StrictParamDupe: 'Strict mode function may not have duplicate parameter names', - StrictFunctionName: 'Function name may not be eval or arguments in strict mode', - StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', - StrictDelete: 'Delete of an unqualified identifier in strict mode.', - StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', - AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', - AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', - StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', - StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', - StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', - StrictReservedWord: 'Use of future reserved word in strict mode' + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode' }; // See also tools/generate-unicode-regex.py. Regex = { - NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), - NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') + NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), + NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') }; // Ensure the condition is true, otherwise throw an error. @@ -217,7 +212,7 @@ parseStatement: true, parseSourceElement: true */ } function isDecimalDigit(ch) { - return (ch >= 48 && ch <= 57); // 0..9 + return (ch >= 0x30 && ch <= 0x39); // 0..9 } function isHexDigit(ch) { @@ -306,7 +301,7 @@ parseStatement: true, parseSourceElement: true */ } // 'const' is specialized as Keyword in V8. - // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next. // Some others are from future reserved words. switch (id.length) { @@ -339,7 +334,7 @@ parseStatement: true, parseSourceElement: true */ // 7.4 Comments function addComment(type, value, start, end, loc) { - var comment, attacher; + var comment; assert(typeof start === 'number', 'Comment must have valid position'); @@ -434,7 +429,7 @@ parseStatement: true, parseSourceElement: true */ ++index; lineStart = index; if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } } else if (ch === 0x2A) { // Block comment ends with '*/'. @@ -457,7 +452,7 @@ parseStatement: true, parseSourceElement: true */ } } - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } function skipComment() { @@ -531,6 +526,38 @@ parseStatement: true, parseSourceElement: true */ return String.fromCharCode(code); } + function scanUnicodeCodePointEscape() { + var ch, code, cu1, cu2; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwUnexpectedToken(); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwUnexpectedToken(); + } + + // UTF-16 Encoding + if (code <= 0xFFFF) { + return String.fromCharCode(code); + } + cu1 = ((code - 0x10000) >> 10) + 0xD800; + cu2 = ((code - 0x10000) & 1023) + 0xDC00; + return String.fromCharCode(cu1, cu2); + } + function getEscapedIdentifier() { var ch, id; @@ -540,12 +567,12 @@ parseStatement: true, parseSourceElement: true */ // '\u' (U+005C, U+0075) denotes an escaped character. if (ch === 0x5C) { if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } ++index; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } id = ch; } @@ -562,12 +589,12 @@ parseStatement: true, parseSourceElement: true */ if (ch === 0x5C) { id = id.substr(0, id.length - 1); if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } ++index; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } id += ch; } @@ -767,6 +794,7 @@ parseStatement: true, parseSourceElement: true */ } // 1-character punctuators: < > = ! + - * % & | ^ / + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { ++index; return { @@ -779,7 +807,7 @@ parseStatement: true, parseSourceElement: true */ }; } - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } // 7.8.3 Numeric Literals @@ -795,11 +823,11 @@ parseStatement: true, parseSourceElement: true */ } if (number.length === 0) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { @@ -812,8 +840,54 @@ parseStatement: true, parseSourceElement: true */ }; } - function scanOctalLiteral(start) { - var number = '0' + source[index++]; + function scanBinaryLiteral(start) { + var ch, number; + + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwUnexpectedToken(); + } + + if (index < length) { + ch = source.charCodeAt(index); + /* istanbul ignore else */ + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwUnexpectedToken(); + } + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + while (index < length) { if (!isOctalDigit(source[index])) { break; @@ -821,14 +895,19 @@ parseStatement: true, parseSourceElement: true */ number += source[index++]; } + if (!octal && number.length === 0) { + // only 0o or 0O + throwUnexpectedToken(); + } + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { type: Token.NumericLiteral, value: parseInt(number, 8), - octal: true, + octal: octal, lineNumber: lineNumber, lineStart: lineStart, start: start, @@ -836,6 +915,24 @@ parseStatement: true, parseSourceElement: true */ }; } + function isImplicitOctalLiteral() { + var i, ch; + + // Implicit octal, unless there is a non-octal digit. + // (Annex B.1.1 on Numeric Literals) + for (i = index + 1; i < length; ++i) { + ch = source[i]; + if (ch === '8' || ch === '9') { + return false; + } + if (!isOctalDigit(ch)) { + return true; + } + } + + return true; + } + function scanNumericLiteral() { var number, start, ch; @@ -851,18 +948,25 @@ parseStatement: true, parseSourceElement: true */ // Hex number starts with '0x'. // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. if (number === '0') { if (ch === 'x' || ch === 'X') { ++index; return scanHexLiteral(start); } - if (isOctalDigit(ch)) { - return scanOctalLiteral(start); + if (ch === 'b' || ch === 'B') { + ++index; + return scanBinaryLiteral(start); + } + if (ch === 'o' || ch === 'O') { + return scanOctalLiteral(ch, start); } - // decimal number starts with '0' such as '09' is illegal. - if (ch && isDecimalDigit(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + if (isOctalDigit(ch)) { + if (isImplicitOctalLiteral()) { + return scanOctalLiteral(ch, start); + } } } @@ -892,12 +996,12 @@ parseStatement: true, parseSourceElement: true */ number += source[index++]; } } else { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } } if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { @@ -936,13 +1040,18 @@ parseStatement: true, parseSourceElement: true */ switch (ch) { case 'u': case 'x': - restore = index; - unescaped = scanHexEscape(ch); - if (unescaped) { - str += unescaped; + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); } else { - index = restore; - str += ch; + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } } break; case 'n': @@ -993,7 +1102,7 @@ parseStatement: true, parseSourceElement: true */ } } else { ++lineNumber; - if (ch === '\r' && source[index] === '\n') { + if (ch === '\r' && source[index] === '\n') { ++index; } lineStart = index; @@ -1006,7 +1115,7 @@ parseStatement: true, parseSourceElement: true */ } if (quote !== '') { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { @@ -1023,13 +1132,43 @@ parseStatement: true, parseSourceElement: true */ } function testRegExp(pattern, flags) { - var value; + var tmp = pattern, + value; + + if (flags.indexOf('u') >= 0) { + // Replace each astral symbol and every Unicode code point + // escape sequence with a single ASCII symbol to avoid throwing on + // regular expressions that are only valid in combination with the + // `/u` flag. + // Note: replacing with the ASCII symbol `x` might cause false + // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a + // perfectly valid pattern that is equivalent to `[a-b]`, but it + // would be replaced by `[x-b]` which throws an error. + tmp = tmp + .replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) { + if (parseInt($1, 16) <= 0x10FFFF) { + return 'x'; + } + throwError(Messages.InvalidRegExp); + }) + .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x'); + } + + // First, detect invalid regular expressions. try { - value = new RegExp(pattern, flags); + value = new RegExp(tmp); } catch (e) { - throwError({}, Messages.InvalidRegExp); + throwError(Messages.InvalidRegExp); + } + + // Return a regular expression object for this pattern-flag pair, or + // `null` in case the current environment doesn't support the flags it + // uses. + try { + return new RegExp(pattern, flags); + } catch (exception) { + return null; } - return value; } function scanRegExpBody() { @@ -1048,11 +1187,11 @@ parseStatement: true, parseSourceElement: true */ ch = source[index++]; // ECMA-262 7.8.5 if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); + throwError(Messages.UnterminatedRegExp); } str += ch; } else if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); + throwError(Messages.UnterminatedRegExp); } else if (classMarker) { if (ch === ']') { classMarker = false; @@ -1068,7 +1207,7 @@ parseStatement: true, parseSourceElement: true */ } if (!terminated) { - throwError({}, Messages.UnterminatedRegExp); + throwError(Messages.UnterminatedRegExp); } // Exclude leading and trailing slash. @@ -1107,10 +1246,10 @@ parseStatement: true, parseSourceElement: true */ flags += 'u'; str += '\\u'; } - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); + tolerateUnexpectedToken(); } else { str += '\\'; - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); + tolerateUnexpectedToken(); } } else { flags += ch; @@ -1125,7 +1264,7 @@ parseStatement: true, parseSourceElement: true */ } function scanRegExp() { - var start, body, flags, pattern, value; + var start, body, flags, value; lookahead = null; skipComment(); @@ -1139,6 +1278,10 @@ parseStatement: true, parseSourceElement: true */ return { type: Token.RegularExpression, value: value, + regex: { + pattern: body.value, + flags: flags.value + }, lineNumber: lineNumber, lineStart: lineStart, start: start, @@ -1149,6 +1292,10 @@ parseStatement: true, parseSourceElement: true */ return { literal: body.literal + flags.literal, value: value, + regex: { + pattern: body.value, + flags: flags.value + }, start: start, end: index }; @@ -1168,6 +1315,7 @@ parseStatement: true, parseSourceElement: true */ }; regex = scanRegExp(); + loc.end = { line: lineNumber, column: index - lineStart @@ -1188,6 +1336,7 @@ parseStatement: true, parseSourceElement: true */ extra.tokens.push({ type: 'RegularExpression', value: regex.literal, + regex: regex.regex, range: [pos, index], loc: loc }); @@ -1260,7 +1409,7 @@ parseStatement: true, parseSourceElement: true */ } return collectRegex(); } - if (prevToken.type === 'Keyword') { + if (prevToken.type === 'Keyword' && prevToken.value !== 'this') { return collectRegex(); } return scanPunctuator(); @@ -1320,7 +1469,7 @@ parseStatement: true, parseSourceElement: true */ } function collectToken() { - var loc, token, range, value; + var loc, token, value, entry; skipComment(); loc = { @@ -1338,12 +1487,19 @@ parseStatement: true, parseSourceElement: true */ if (token.type !== Token.EOF) { value = source.slice(token.start, token.end); - extra.tokens.push({ + entry = { type: TokenName[token.type], value: value, range: [token.start, token.end], loc: loc - }); + }; + if (token.regex) { + entry.regex = { + pattern: token.regex.pattern, + flags: token.regex.flags + }; + } + extra.tokens.push(entry); } return token; @@ -1378,422 +1534,478 @@ parseStatement: true, parseSourceElement: true */ lineStart = start; } - function Position(line, column) { - this.line = line; - this.column = column; + function Position() { + this.line = lineNumber; + this.column = index - lineStart; } - function SourceLocation(startLine, startColumn, line, column) { - this.start = new Position(startLine, startColumn); - this.end = new Position(line, column); + function SourceLocation() { + this.start = new Position(); + this.end = null; } - SyntaxTreeDelegate = { + function WrappingSourceLocation(startToken) { + if (startToken.type === Token.StringLiteral) { + this.start = { + line: startToken.startLineNumber, + column: startToken.start - startToken.startLineStart + }; + } else { + this.start = { + line: startToken.lineNumber, + column: startToken.start - startToken.lineStart + }; + } + this.end = null; + } - name: 'SyntaxTree', + function Node() { + // Skip comment. + index = lookahead.start; + if (lookahead.type === Token.StringLiteral) { + lineNumber = lookahead.startLineNumber; + lineStart = lookahead.startLineStart; + } else { + lineNumber = lookahead.lineNumber; + lineStart = lookahead.lineStart; + } + if (extra.range) { + this.range = [index, 0]; + } + if (extra.loc) { + this.loc = new SourceLocation(); + } + } - processComment: function (node) { - var lastChild, trailingComments; + function WrappingNode(startToken) { + if (extra.range) { + this.range = [startToken.start, 0]; + } + if (extra.loc) { + this.loc = new WrappingSourceLocation(startToken); + } + } + + WrappingNode.prototype = Node.prototype = { - if (node.type === Syntax.Program) { - if (node.body.length > 0) { + processComment: function () { + var lastChild, + leadingComments, + trailingComments, + bottomRight = extra.bottomRightStack, + i, + comment, + last = bottomRight[bottomRight.length - 1]; + + if (this.type === Syntax.Program) { + if (this.body.length > 0) { return; } } if (extra.trailingComments.length > 0) { - if (extra.trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.trailingComments; - extra.trailingComments = []; - } else { - extra.trailingComments.length = 0; + trailingComments = []; + for (i = extra.trailingComments.length - 1; i >= 0; --i) { + comment = extra.trailingComments[i]; + if (comment.range[0] >= this.range[1]) { + trailingComments.unshift(comment); + extra.trailingComments.splice(i, 1); + } } + extra.trailingComments = []; } else { - if (extra.bottomRightStack.length > 0 && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; - delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) { + trailingComments = last.trailingComments; + delete last.trailingComments; } } // Eating the stack. - while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { - lastChild = extra.bottomRightStack.pop(); + if (last) { + while (last && last.range[0] >= this.range[0]) { + lastChild = last; + last = bottomRight.pop(); + } } if (lastChild) { - if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = lastChild.leadingComments; - delete lastChild.leadingComments; + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= this.range[0]) { + this.leadingComments = lastChild.leadingComments; + lastChild.leadingComments = undefined; + } + } else if (extra.leadingComments.length > 0) { + leadingComments = []; + for (i = extra.leadingComments.length - 1; i >= 0; --i) { + comment = extra.leadingComments[i]; + if (comment.range[1] <= this.range[0]) { + leadingComments.unshift(comment); + extra.leadingComments.splice(i, 1); + } } - } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = extra.leadingComments; - extra.leadingComments = []; } - if (trailingComments) { - node.trailingComments = trailingComments; + if (leadingComments && leadingComments.length > 0) { + this.leadingComments = leadingComments; + } + if (trailingComments && trailingComments.length > 0) { + this.trailingComments = trailingComments; } - extra.bottomRightStack.push(node); + bottomRight.push(this); }, - markEnd: function (node, startToken) { + finish: function () { if (extra.range) { - node.range = [startToken.start, index]; + this.range[1] = index; } if (extra.loc) { - node.loc = new SourceLocation( - startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber, - startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart), - lineNumber, - index - lineStart - ); - this.postProcess(node); + this.loc.end = new Position(); + if (extra.source) { + this.loc.source = extra.source; + } } if (extra.attachComment) { - this.processComment(node); + this.processComment(); } - return node; }, - postProcess: function (node) { - if (extra.source) { - node.loc.source = extra.source; - } - return node; + finishArrayExpression: function (elements) { + this.type = Syntax.ArrayExpression; + this.elements = elements; + this.finish(); + return this; }, - createArrayExpression: function (elements) { - return { - type: Syntax.ArrayExpression, - elements: elements - }; + finishArrowFunctionExpression: function (params, defaults, body, expression) { + this.type = Syntax.ArrowFunctionExpression; + this.id = null; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = expression; + this.finish(); + return this; }, - createAssignmentExpression: function (operator, left, right) { - return { - type: Syntax.AssignmentExpression, - operator: operator, - left: left, - right: right - }; + finishAssignmentExpression: function (operator, left, right) { + this.type = Syntax.AssignmentExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; }, - createBinaryExpression: function (operator, left, right) { - var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : - Syntax.BinaryExpression; - return { - type: type, - operator: operator, - left: left, - right: right - }; + finishBinaryExpression: function (operator, left, right) { + this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; }, - createBlockStatement: function (body) { - return { - type: Syntax.BlockStatement, - body: body - }; + finishBlockStatement: function (body) { + this.type = Syntax.BlockStatement; + this.body = body; + this.finish(); + return this; }, - createBreakStatement: function (label) { - return { - type: Syntax.BreakStatement, - label: label - }; + finishBreakStatement: function (label) { + this.type = Syntax.BreakStatement; + this.label = label; + this.finish(); + return this; }, - createCallExpression: function (callee, args) { - return { - type: Syntax.CallExpression, - callee: callee, - 'arguments': args - }; + finishCallExpression: function (callee, args) { + this.type = Syntax.CallExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; }, - createCatchClause: function (param, body) { - return { - type: Syntax.CatchClause, - param: param, - body: body - }; + finishCatchClause: function (param, body) { + this.type = Syntax.CatchClause; + this.param = param; + this.body = body; + this.finish(); + return this; }, - createConditionalExpression: function (test, consequent, alternate) { - return { - type: Syntax.ConditionalExpression, - test: test, - consequent: consequent, - alternate: alternate - }; + finishConditionalExpression: function (test, consequent, alternate) { + this.type = Syntax.ConditionalExpression; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; }, - createContinueStatement: function (label) { - return { - type: Syntax.ContinueStatement, - label: label - }; + finishContinueStatement: function (label) { + this.type = Syntax.ContinueStatement; + this.label = label; + this.finish(); + return this; }, - createDebuggerStatement: function () { - return { - type: Syntax.DebuggerStatement - }; + finishDebuggerStatement: function () { + this.type = Syntax.DebuggerStatement; + this.finish(); + return this; }, - createDoWhileStatement: function (body, test) { - return { - type: Syntax.DoWhileStatement, - body: body, - test: test - }; + finishDoWhileStatement: function (body, test) { + this.type = Syntax.DoWhileStatement; + this.body = body; + this.test = test; + this.finish(); + return this; }, - createEmptyStatement: function () { - return { - type: Syntax.EmptyStatement - }; + finishEmptyStatement: function () { + this.type = Syntax.EmptyStatement; + this.finish(); + return this; }, - createExpressionStatement: function (expression) { - return { - type: Syntax.ExpressionStatement, - expression: expression - }; + finishExpressionStatement: function (expression) { + this.type = Syntax.ExpressionStatement; + this.expression = expression; + this.finish(); + return this; }, - createForStatement: function (init, test, update, body) { - return { - type: Syntax.ForStatement, - init: init, - test: test, - update: update, - body: body - }; + finishForStatement: function (init, test, update, body) { + this.type = Syntax.ForStatement; + this.init = init; + this.test = test; + this.update = update; + this.body = body; + this.finish(); + return this; }, - createForInStatement: function (left, right, body) { - return { - type: Syntax.ForInStatement, - left: left, - right: right, - body: body, - each: false - }; + finishForInStatement: function (left, right, body) { + this.type = Syntax.ForInStatement; + this.left = left; + this.right = right; + this.body = body; + this.each = false; + this.finish(); + return this; }, - createFunctionDeclaration: function (id, params, defaults, body) { - return { - type: Syntax.FunctionDeclaration, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false - }; + finishFunctionDeclaration: function (id, params, defaults, body) { + this.type = Syntax.FunctionDeclaration; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = false; + this.finish(); + return this; }, - createFunctionExpression: function (id, params, defaults, body) { - return { - type: Syntax.FunctionExpression, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false - }; + finishFunctionExpression: function (id, params, defaults, body) { + this.type = Syntax.FunctionExpression; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = false; + this.finish(); + return this; }, - createIdentifier: function (name) { - return { - type: Syntax.Identifier, - name: name - }; + finishIdentifier: function (name) { + this.type = Syntax.Identifier; + this.name = name; + this.finish(); + return this; }, - createIfStatement: function (test, consequent, alternate) { - return { - type: Syntax.IfStatement, - test: test, - consequent: consequent, - alternate: alternate - }; + finishIfStatement: function (test, consequent, alternate) { + this.type = Syntax.IfStatement; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; }, - createLabeledStatement: function (label, body) { - return { - type: Syntax.LabeledStatement, - label: label, - body: body - }; + finishLabeledStatement: function (label, body) { + this.type = Syntax.LabeledStatement; + this.label = label; + this.body = body; + this.finish(); + return this; }, - createLiteral: function (token) { - return { - type: Syntax.Literal, - value: token.value, - raw: source.slice(token.start, token.end) - }; + finishLiteral: function (token) { + this.type = Syntax.Literal; + this.value = token.value; + this.raw = source.slice(token.start, token.end); + if (token.regex) { + this.regex = token.regex; + } + this.finish(); + return this; }, - createMemberExpression: function (accessor, object, property) { - return { - type: Syntax.MemberExpression, - computed: accessor === '[', - object: object, - property: property - }; + finishMemberExpression: function (accessor, object, property) { + this.type = Syntax.MemberExpression; + this.computed = accessor === '['; + this.object = object; + this.property = property; + this.finish(); + return this; }, - createNewExpression: function (callee, args) { - return { - type: Syntax.NewExpression, - callee: callee, - 'arguments': args - }; + finishNewExpression: function (callee, args) { + this.type = Syntax.NewExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; }, - createObjectExpression: function (properties) { - return { - type: Syntax.ObjectExpression, - properties: properties - }; + finishObjectExpression: function (properties) { + this.type = Syntax.ObjectExpression; + this.properties = properties; + this.finish(); + return this; }, - createPostfixExpression: function (operator, argument) { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: false - }; + finishPostfixExpression: function (operator, argument) { + this.type = Syntax.UpdateExpression; + this.operator = operator; + this.argument = argument; + this.prefix = false; + this.finish(); + return this; }, - createProgram: function (body) { - return { - type: Syntax.Program, - body: body - }; + finishProgram: function (body) { + this.type = Syntax.Program; + this.body = body; + this.finish(); + return this; }, - createProperty: function (kind, key, value) { - return { - type: Syntax.Property, - key: key, - value: value, - kind: kind - }; + finishProperty: function (kind, key, value, method, shorthand) { + this.type = Syntax.Property; + this.key = key; + this.value = value; + this.kind = kind; + this.method = method; + this.shorthand = shorthand; + this.finish(); + return this; }, - createReturnStatement: function (argument) { - return { - type: Syntax.ReturnStatement, - argument: argument - }; + finishReturnStatement: function (argument) { + this.type = Syntax.ReturnStatement; + this.argument = argument; + this.finish(); + return this; }, - createSequenceExpression: function (expressions) { - return { - type: Syntax.SequenceExpression, - expressions: expressions - }; + finishSequenceExpression: function (expressions) { + this.type = Syntax.SequenceExpression; + this.expressions = expressions; + this.finish(); + return this; }, - createSwitchCase: function (test, consequent) { - return { - type: Syntax.SwitchCase, - test: test, - consequent: consequent - }; + finishSwitchCase: function (test, consequent) { + this.type = Syntax.SwitchCase; + this.test = test; + this.consequent = consequent; + this.finish(); + return this; }, - createSwitchStatement: function (discriminant, cases) { - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; + finishSwitchStatement: function (discriminant, cases) { + this.type = Syntax.SwitchStatement; + this.discriminant = discriminant; + this.cases = cases; + this.finish(); + return this; }, - createThisExpression: function () { - return { - type: Syntax.ThisExpression - }; + finishThisExpression: function () { + this.type = Syntax.ThisExpression; + this.finish(); + return this; }, - createThrowStatement: function (argument) { - return { - type: Syntax.ThrowStatement, - argument: argument - }; + finishThrowStatement: function (argument) { + this.type = Syntax.ThrowStatement; + this.argument = argument; + this.finish(); + return this; }, - createTryStatement: function (block, guardedHandlers, handlers, finalizer) { - return { - type: Syntax.TryStatement, - block: block, - guardedHandlers: guardedHandlers, - handlers: handlers, - finalizer: finalizer - }; + finishTryStatement: function (block, guardedHandlers, handlers, finalizer) { + this.type = Syntax.TryStatement; + this.block = block; + this.guardedHandlers = guardedHandlers; + this.handlers = handlers; + this.finalizer = finalizer; + this.finish(); + return this; }, - createUnaryExpression: function (operator, argument) { - if (operator === '++' || operator === '--') { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: true - }; - } - return { - type: Syntax.UnaryExpression, - operator: operator, - argument: argument, - prefix: true - }; + finishUnaryExpression: function (operator, argument) { + this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression; + this.operator = operator; + this.argument = argument; + this.prefix = true; + this.finish(); + return this; }, - createVariableDeclaration: function (declarations, kind) { - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: kind - }; + finishVariableDeclaration: function (declarations, kind) { + this.type = Syntax.VariableDeclaration; + this.declarations = declarations; + this.kind = kind; + this.finish(); + return this; }, - createVariableDeclarator: function (id, init) { - return { - type: Syntax.VariableDeclarator, - id: id, - init: init - }; + finishVariableDeclarator: function (id, init) { + this.type = Syntax.VariableDeclarator; + this.id = id; + this.init = init; + this.finish(); + return this; }, - createWhileStatement: function (test, body) { - return { - type: Syntax.WhileStatement, - test: test, - body: body - }; + finishWhileStatement: function (test, body) { + this.type = Syntax.WhileStatement; + this.test = test; + this.body = body; + this.finish(); + return this; }, - createWithStatement: function (object, body) { - return { - type: Syntax.WithStatement, - object: object, - body: body - }; + finishWithStatement: function (object, body) { + this.type = Syntax.WithStatement; + this.object = object; + this.body = body; + this.finish(); + return this; } }; @@ -1814,79 +2026,91 @@ parseStatement: true, parseSourceElement: true */ return found; } + function createError(line, pos, description) { + var error = new Error('Line ' + line + ': ' + description); + error.index = pos; + error.lineNumber = line; + error.column = pos - lineStart + 1; + error.description = description; + return error; + } + // Throw an exception - function throwError(token, messageFormat) { - var error, - args = Array.prototype.slice.call(arguments, 2), - msg = messageFormat.replace( - /%(\d)/g, - function (whole, index) { - assert(index < args.length, 'Message reference must be in range'); - return args[index]; - } - ); + function throwError(messageFormat) { + var args, msg; - if (typeof token.lineNumber === 'number') { - error = new Error('Line ' + token.lineNumber + ': ' + msg); - error.index = token.start; - error.lineNumber = token.lineNumber; - error.column = token.start - lineStart + 1; - } else { - error = new Error('Line ' + lineNumber + ': ' + msg); - error.index = index; - error.lineNumber = lineNumber; - error.column = index - lineStart + 1; - } + args = Array.prototype.slice.call(arguments, 1); + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; + } + ); - error.description = msg; - throw error; + throw createError(lineNumber, index, msg); } - function throwErrorTolerant() { - try { - throwError.apply(null, arguments); - } catch (e) { - if (extra.errors) { - extra.errors.push(e); - } else { - throw e; + function tolerateError(messageFormat) { + var args, msg, error; + + args = Array.prototype.slice.call(arguments, 1); + /* istanbul ignore next */ + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; } + ); + + error = createError(lineNumber, index, msg); + if (extra.errors) { + extra.errors.push(error); + } else { + throw error; } } - // Throw an exception because of the token. - function throwUnexpected(token) { - if (token.type === Token.EOF) { - throwError(token, Messages.UnexpectedEOS); + function unexpectedTokenError(token, message) { + var msg = Messages.UnexpectedToken; + + if (token) { + msg = message ? message : + (token.type === Token.EOF) ? Messages.UnexpectedEOS : + (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier : + (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber : + (token.type === Token.StringLiteral) ? Messages.UnexpectedString : + Messages.UnexpectedToken; + + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + msg = Messages.UnexpectedReserved; + } else if (strict && isStrictModeReservedWord(token.value)) { + msg = Messages.StrictReservedWord; + } + } } - if (token.type === Token.NumericLiteral) { - throwError(token, Messages.UnexpectedNumber); - } + msg = msg.replace('%0', token ? token.value : 'ILLEGAL'); - if (token.type === Token.StringLiteral) { - throwError(token, Messages.UnexpectedString); - } + return (token && typeof token.lineNumber === 'number') ? + createError(token.lineNumber, token.start, msg) : + createError(lineNumber, index, msg); + } - if (token.type === Token.Identifier) { - throwError(token, Messages.UnexpectedIdentifier); - } + function throwUnexpectedToken(token, message) { + throw unexpectedTokenError(token, message); + } - if (token.type === Token.Keyword) { - if (isFutureReservedWord(token.value)) { - throwError(token, Messages.UnexpectedReserved); - } else if (strict && isStrictModeReservedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictReservedWord); - return; - } - throwError(token, Messages.UnexpectedToken, token.value); + function tolerateUnexpectedToken(token, message) { + var error = unexpectedTokenError(token, message); + if (extra.errors) { + extra.errors.push(error); + } else { + throw error; } - - // BooleanLiteral, NullLiteral, or Punctuator. - throwError(token, Messages.UnexpectedToken, token.value); } // Expect the next token to match the specified punctuator. @@ -1895,7 +2119,31 @@ parseStatement: true, parseSourceElement: true */ function expect(value) { var token = lex(); if (token.type !== Token.Punctuator || token.value !== value) { - throwUnexpected(token); + throwUnexpectedToken(token); + } + } + + /** + * @name expectCommaSeparator + * @description Quietly expect a comma when in tolerant mode, otherwise delegates + * to expect(value) + * @since 2.0 + */ + function expectCommaSeparator() { + var token; + + if (extra.errors) { + token = lookahead; + if (token.type === Token.Punctuator && token.value === ',') { + lex(); + } else if (token.type === Token.Punctuator && token.value === ';') { + lex(); + tolerateUnexpectedToken(token); + } else { + tolerateUnexpectedToken(token, Messages.UnexpectedToken); + } + } else { + expect(','); } } @@ -1905,7 +2153,7 @@ parseStatement: true, parseSourceElement: true */ function expectKeyword(keyword) { var token = lex(); if (token.type !== Token.Keyword || token.value !== keyword) { - throwUnexpected(token); + throwUnexpectedToken(token); } } @@ -1945,7 +2193,8 @@ parseStatement: true, parseSourceElement: true */ } function consumeSemicolon() { - var line; + var line, oldIndex = index, oldLineNumber = lineNumber, + oldLineStart = lineStart, oldLookahead = lookahead; // Catch the very common case first: immediately a semicolon (U+003B). if (source.charCodeAt(index) === 0x3B || match(';')) { @@ -1956,11 +2205,15 @@ parseStatement: true, parseSourceElement: true */ line = lineNumber; skipComment(); if (lineNumber !== line) { + index = oldIndex; + lineNumber = oldLineNumber; + lineStart = oldLineStart; + lookahead = oldLookahead; return; } if (lookahead.type !== Token.EOF && !match('}')) { - throwUnexpected(lookahead); + throwUnexpectedToken(lookahead); } } @@ -1973,9 +2226,8 @@ parseStatement: true, parseSourceElement: true */ // 11.1.4 Array Initialiser function parseArrayInitialiser() { - var elements = [], startToken; + var elements = [], node = new Node(); - startToken = lookahead; expect('['); while (!match(']')) { @@ -1993,28 +2245,38 @@ parseStatement: true, parseSourceElement: true */ lex(); - return delegate.markEnd(delegate.createArrayExpression(elements), startToken); + return node.finishArrayExpression(elements); } // 11.1.5 Object Initialiser function parsePropertyFunction(param, first) { - var previousStrict, body, startToken; + var previousStrict, body, node = new Node(); previousStrict = strict; - startToken = lookahead; body = parseFunctionSourceElements(); if (first && strict && isRestrictedWord(param[0].name)) { - throwErrorTolerant(first, Messages.StrictParamName); + tolerateUnexpectedToken(first, Messages.StrictParamName); } strict = previousStrict; - return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken); + return node.finishFunctionExpression(null, param, [], body); + } + + function parsePropertyMethodFunction() { + var previousStrict, param, method; + + previousStrict = strict; + strict = true; + param = parseParams(); + method = parsePropertyFunction(param.params); + strict = previousStrict; + + return method; } function parseObjectPropertyKey() { - var token, startToken; + var token, node = new Node(); - startToken = lookahead; token = lex(); // Note: This function is called only from parseObjectProperty(), where @@ -2022,19 +2284,18 @@ parseStatement: true, parseSourceElement: true */ if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(token, Messages.StrictOctalLiteral); } - return delegate.markEnd(delegate.createLiteral(token), startToken); + return node.finishLiteral(token); } - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + return node.finishIdentifier(token.value); } function parseObjectProperty() { - var token, key, id, value, param, startToken; + var token, key, id, value, param, node = new Node(); token = lookahead; - startToken = lookahead; if (token.type === Token.Identifier) { @@ -2042,46 +2303,60 @@ parseStatement: true, parseSourceElement: true */ // Property Assignment: Getter and Setter. - if (token.value === 'get' && !match(':')) { + if (token.value === 'get' && !(match(':') || match('('))) { key = parseObjectPropertyKey(); expect('('); expect(')'); value = parsePropertyFunction([]); - return delegate.markEnd(delegate.createProperty('get', key, value), startToken); + return node.finishProperty('get', key, value, false, false); } - if (token.value === 'set' && !match(':')) { + if (token.value === 'set' && !(match(':') || match('('))) { key = parseObjectPropertyKey(); expect('('); token = lookahead; if (token.type !== Token.Identifier) { expect(')'); - throwErrorTolerant(token, Messages.UnexpectedToken, token.value); + tolerateUnexpectedToken(token); value = parsePropertyFunction([]); } else { param = [ parseVariableIdentifier() ]; expect(')'); value = parsePropertyFunction(param, token); } - return delegate.markEnd(delegate.createProperty('set', key, value), startToken); + return node.finishProperty('set', key, value, false, false); } - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd(delegate.createProperty('init', id, value), startToken); + if (match(':')) { + lex(); + value = parseAssignmentExpression(); + return node.finishProperty('init', id, value, false, false); + } + if (match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', id, value, true, false); + } + + value = id; + return node.finishProperty('init', id, value, false, true); } if (token.type === Token.EOF || token.type === Token.Punctuator) { - throwUnexpected(token); + throwUnexpectedToken(token); } else { key = parseObjectPropertyKey(); - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd(delegate.createProperty('init', key, value), startToken); + if (match(':')) { + lex(); + value = parseAssignmentExpression(); + return node.finishProperty('init', key, value, false, false); + } + if (match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', key, value, true, false); + } + throwUnexpectedToken(lex()); } } function parseObjectInitialiser() { - var properties = [], property, name, key, kind, map = {}, toString = String, startToken; - - startToken = lookahead; + var properties = [], property, name, key, kind, map = {}, toString = String, node = new Node(); expect('{'); @@ -2099,15 +2374,15 @@ parseStatement: true, parseSourceElement: true */ if (Object.prototype.hasOwnProperty.call(map, key)) { if (map[key] === PropertyKind.Data) { if (strict && kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.StrictDuplicateProperty); + tolerateError(Messages.StrictDuplicateProperty); } else if (kind !== PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); + tolerateError(Messages.AccessorDataProperty); } } else { if (kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); + tolerateError(Messages.AccessorDataProperty); } else if (map[key] & kind) { - throwErrorTolerant({}, Messages.AccessorGetSet); + tolerateError(Messages.AccessorGetSet); } } map[key] |= kind; @@ -2118,13 +2393,13 @@ parseStatement: true, parseSourceElement: true */ properties.push(property); if (!match('}')) { - expect(','); + expectCommaSeparator(); } } expect('}'); - return delegate.markEnd(delegate.createObjectExpression(properties), startToken); + return node.finishObjectExpression(properties); } // 11.1.6 The Grouping Operator @@ -2134,6 +2409,13 @@ parseStatement: true, parseSourceElement: true */ expect('('); + if (match(')')) { + lex(); + return PlaceHolders.ArrowParameterPlaceHolder; + } + + ++state.parenthesisCount; + expr = parseExpression(); expect(')'); @@ -2145,7 +2427,7 @@ parseStatement: true, parseSourceElement: true */ // 11.1 Primary Expressions function parsePrimaryExpression() { - var type, token, expr, startToken; + var type, token, expr, node; if (match('(')) { return parseGroupExpression(); @@ -2160,45 +2442,45 @@ parseStatement: true, parseSourceElement: true */ } type = lookahead.type; - startToken = lookahead; + node = new Node(); if (type === Token.Identifier) { - expr = delegate.createIdentifier(lex().value); + expr = node.finishIdentifier(lex().value); } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { if (strict && lookahead.octal) { - throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral); } - expr = delegate.createLiteral(lex()); + expr = node.finishLiteral(lex()); } else if (type === Token.Keyword) { if (matchKeyword('function')) { return parseFunctionExpression(); } if (matchKeyword('this')) { lex(); - expr = delegate.createThisExpression(); + expr = node.finishThisExpression(); } else { - throwUnexpected(lex()); + throwUnexpectedToken(lex()); } } else if (type === Token.BooleanLiteral) { token = lex(); token.value = (token.value === 'true'); - expr = delegate.createLiteral(token); + expr = node.finishLiteral(token); } else if (type === Token.NullLiteral) { token = lex(); token.value = null; - expr = delegate.createLiteral(token); + expr = node.finishLiteral(token); } else if (match('/') || match('/=')) { if (typeof extra.tokens !== 'undefined') { - expr = delegate.createLiteral(collectRegex()); + expr = node.finishLiteral(collectRegex()); } else { - expr = delegate.createLiteral(scanRegExp()); + expr = node.finishLiteral(scanRegExp()); } peek(); } else { - throwUnexpected(lex()); + throwUnexpectedToken(lex()); } - return delegate.markEnd(expr, startToken); + return expr; } // 11.2 Left-Hand-Side Expressions @@ -2214,7 +2496,7 @@ parseStatement: true, parseSourceElement: true */ if (match(')')) { break; } - expect(','); + expectCommaSeparator(); } } @@ -2224,16 +2506,15 @@ parseStatement: true, parseSourceElement: true */ } function parseNonComputedProperty() { - var token, startToken; + var token, node = new Node(); - startToken = lookahead; token = lex(); if (!isIdentifierName(token)) { - throwUnexpected(token); + throwUnexpectedToken(token); } - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + return node.finishIdentifier(token.value); } function parseNonComputedMember() { @@ -2255,65 +2536,60 @@ parseStatement: true, parseSourceElement: true */ } function parseNewExpression() { - var callee, args, startToken; + var callee, args, node = new Node(); - startToken = lookahead; expectKeyword('new'); callee = parseLeftHandSideExpression(); args = match('(') ? parseArguments() : []; - return delegate.markEnd(delegate.createNewExpression(callee, args), startToken); + return node.finishNewExpression(callee, args); } function parseLeftHandSideExpressionAllowCall() { - var previousAllowIn, expr, args, property, startToken; + var expr, args, property, startToken, previousAllowIn = state.allowIn; startToken = lookahead; - - previousAllowIn = state.allowIn; state.allowIn = true; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - state.allowIn = previousAllowIn; for (;;) { if (match('.')) { property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); } else if (match('(')) { args = parseArguments(); - expr = delegate.createCallExpression(expr, args); + expr = new WrappingNode(startToken).finishCallExpression(expr, args); } else if (match('[')) { property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); } else { break; } - delegate.markEnd(expr, startToken); } + state.allowIn = previousAllowIn; return expr; } function parseLeftHandSideExpression() { - var previousAllowIn, expr, property, startToken; + var expr, property, startToken; + assert(state.allowIn, 'callee of new expression always allow in keyword.'); startToken = lookahead; - previousAllowIn = state.allowIn; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - state.allowIn = previousAllowIn; - while (match('.') || match('[')) { + for (;;) { if (match('[')) { property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); - } else { + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); + } else if (match('.')) { property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); + } else { + break; } - delegate.markEnd(expr, startToken); } - return expr; } @@ -2328,15 +2604,15 @@ parseStatement: true, parseSourceElement: true */ if ((match('++') || match('--')) && !peekLineTerminator()) { // 11.3.1, 11.3.2 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPostfix); + tolerateError(Messages.StrictLHSPostfix); } if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + tolerateError(Messages.InvalidLHSInAssignment); } token = lex(); - expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken); + expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr); } } @@ -2356,29 +2632,26 @@ parseStatement: true, parseSourceElement: true */ expr = parseUnaryExpression(); // 11.4.4, 11.4.5 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPrefix); + tolerateError(Messages.StrictLHSPrefix); } if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + tolerateError(Messages.InvalidLHSInAssignment); } - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); } else if (match('+') || match('-') || match('~') || match('!')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { - throwErrorTolerant({}, Messages.StrictDelete); + tolerateError(Messages.StrictDelete); } } else { expr = parsePostfixExpression(); @@ -2471,6 +2744,9 @@ parseStatement: true, parseSourceElement: true */ marker = lookahead; left = parseUnaryExpression(); + if (left === PlaceHolders.ArrowParameterPlaceHolder) { + return left; + } token = lookahead; prec = binaryPrecedence(token, state.allowIn); @@ -2492,10 +2768,8 @@ parseStatement: true, parseSourceElement: true */ right = stack.pop(); operator = stack.pop().value; left = stack.pop(); - expr = delegate.createBinaryExpression(operator, left, right); markers.pop(); - marker = markers[markers.length - 1]; - delegate.markEnd(expr, marker); + expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right); stack.push(expr); } @@ -2513,10 +2787,8 @@ parseStatement: true, parseSourceElement: true */ expr = stack[i]; markers.pop(); while (i > 1) { - expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); i -= 2; - marker = markers.pop(); - delegate.markEnd(expr, marker); } return expr; @@ -2531,7 +2803,9 @@ parseStatement: true, parseSourceElement: true */ startToken = lookahead; expr = parseBinaryExpression(); - + if (expr === PlaceHolders.ArrowParameterPlaceHolder) { + return expr; + } if (match('?')) { lex(); previousAllowIn = state.allowIn; @@ -2541,61 +2815,155 @@ parseStatement: true, parseSourceElement: true */ expect(':'); alternate = parseAssignmentExpression(); - expr = delegate.createConditionalExpression(expr, consequent, alternate); - delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate); } return expr; } + // [ES6] 14.2 Arrow Function + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return parseAssignmentExpression(); + } + + function reinterpretAsCoverFormalsList(expressions) { + var i, len, param, params, defaults, defaultCount, options, rest, token; + + params = []; + defaults = []; + defaultCount = 0; + rest = null; + options = { + paramSet: {} + }; + + for (i = 0, len = expressions.length; i < len; i += 1) { + param = expressions[i]; + if (param.type === Syntax.Identifier) { + params.push(param); + defaults.push(null); + validateParam(options, param, param.name); + } else if (param.type === Syntax.AssignmentExpression) { + params.push(param.left); + defaults.push(param.right); + ++defaultCount; + validateParam(options, param.left, param.left.name); + } else { + return null; + } + } + + if (options.message === Messages.StrictParamDupe) { + token = strict ? options.stricted : options.firstRestricted; + throwUnexpectedToken(token, options.message); + } + + if (defaultCount === 0) { + defaults = []; + } + + return { + params: params, + defaults: defaults, + rest: rest, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseArrowFunctionExpression(options, node) { + var previousStrict, body; + + expect('=>'); + previousStrict = strict; + + body = parseConciseBody(); + + if (strict && options.firstRestricted) { + throwUnexpectedToken(options.firstRestricted, options.message); + } + if (strict && options.stricted) { + tolerateUnexpectedToken(options.stricted, options.message); + } + + strict = previousStrict; + + return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement); + } + // 11.13 Assignment Operators function parseAssignmentExpression() { - var token, left, right, node, startToken; + var oldParenthesisCount, token, expr, right, list, startToken; + + oldParenthesisCount = state.parenthesisCount; - token = lookahead; startToken = lookahead; + token = lookahead; - node = left = parseConditionalExpression(); + expr = parseConditionalExpression(); + + if (expr === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) { + if (state.parenthesisCount === oldParenthesisCount || + state.parenthesisCount === (oldParenthesisCount + 1)) { + if (expr.type === Syntax.Identifier) { + list = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.AssignmentExpression) { + list = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.SequenceExpression) { + list = reinterpretAsCoverFormalsList(expr.expressions); + } else if (expr === PlaceHolders.ArrowParameterPlaceHolder) { + list = reinterpretAsCoverFormalsList([]); + } + if (list) { + return parseArrowFunctionExpression(list, new WrappingNode(startToken)); + } + } + } if (matchAssign()) { // LeftHandSideExpression - if (!isLeftHandSide(left)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + if (!isLeftHandSide(expr)) { + tolerateError(Messages.InvalidLHSInAssignment); } // 11.13.1 - if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { - throwErrorTolerant(token, Messages.StrictLHSAssignment); + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateUnexpectedToken(token, Messages.StrictLHSAssignment); } token = lex(); right = parseAssignmentExpression(); - node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken); + expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right); } - return node; + return expr; } // 11.14 Comma Operator function parseExpression() { - var expr, startToken = lookahead; + var expr, startToken = lookahead, expressions; expr = parseAssignmentExpression(); if (match(',')) { - expr = delegate.createSequenceExpression([ expr ]); + expressions = [expr]; while (index < length) { if (!match(',')) { break; } lex(); - expr.expressions.push(parseAssignmentExpression()); + expressions.push(parseAssignmentExpression()); } - delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishSequenceExpression(expressions); } return expr; @@ -2622,42 +2990,43 @@ parseStatement: true, parseSourceElement: true */ } function parseBlock() { - var block, startToken; + var block, node = new Node(); - startToken = lookahead; expect('{'); block = parseStatementList(); expect('}'); - return delegate.markEnd(delegate.createBlockStatement(block), startToken); + return node.finishBlockStatement(block); } // 12.2 Variable Statement function parseVariableIdentifier() { - var token, startToken; + var token, node = new Node(); - startToken = lookahead; token = lex(); if (token.type !== Token.Identifier) { - throwUnexpected(token); + if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictReservedWord); + } else { + throwUnexpectedToken(token); + } } - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + return node.finishIdentifier(token.value); } function parseVariableDeclaration(kind) { - var init = null, id, startToken; + var init = null, id, node = new Node(); - startToken = lookahead; id = parseVariableIdentifier(); // 12.2.1 if (strict && isRestrictedWord(id.name)) { - throwErrorTolerant({}, Messages.StrictVarName); + tolerateError(Messages.StrictVarName); } if (kind === 'const') { @@ -2668,7 +3037,7 @@ parseStatement: true, parseSourceElement: true */ init = parseAssignmentExpression(); } - return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken); + return node.finishVariableDeclarator(id, init); } function parseVariableDeclarationList(kind) { @@ -2685,7 +3054,7 @@ parseStatement: true, parseSourceElement: true */ return list; } - function parseVariableStatement() { + function parseVariableStatement(node) { var declarations; expectKeyword('var'); @@ -2694,7 +3063,7 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return delegate.createVariableDeclaration(declarations, 'var'); + return node.finishVariableDeclaration(declarations, 'var'); } // kind may be `const` or `let` @@ -2702,9 +3071,7 @@ parseStatement: true, parseSourceElement: true */ // see http://wiki.ecmascript.org/doku.php?id=harmony:const // and http://wiki.ecmascript.org/doku.php?id=harmony:let function parseConstLetDeclaration(kind) { - var declarations, startToken; - - startToken = lookahead; + var declarations, node = new Node(); expectKeyword(kind); @@ -2712,27 +3079,28 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken); + return node.finishVariableDeclaration(declarations, kind); } // 12.3 Empty Statement function parseEmptyStatement() { + var node = new Node(); expect(';'); - return delegate.createEmptyStatement(); + return node.finishEmptyStatement(); } // 12.4 Expression Statement - function parseExpressionStatement() { + function parseExpressionStatement(node) { var expr = parseExpression(); consumeSemicolon(); - return delegate.createExpressionStatement(expr); + return node.finishExpressionStatement(expr); } // 12.5 If statement - function parseIfStatement() { + function parseIfStatement(node) { var test, consequent, alternate; expectKeyword('if'); @@ -2752,12 +3120,12 @@ parseStatement: true, parseSourceElement: true */ alternate = null; } - return delegate.createIfStatement(test, consequent, alternate); + return node.finishIfStatement(test, consequent, alternate); } // 12.6 Iteration Statements - function parseDoWhileStatement() { + function parseDoWhileStatement(node) { var body, test, oldInIteration; expectKeyword('do'); @@ -2781,10 +3149,10 @@ parseStatement: true, parseSourceElement: true */ lex(); } - return delegate.createDoWhileStatement(body, test); + return node.finishDoWhileStatement(body, test); } - function parseWhileStatement() { + function parseWhileStatement(node) { var test, body, oldInIteration; expectKeyword('while'); @@ -2802,21 +3170,20 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; - return delegate.createWhileStatement(test, body); + return node.finishWhileStatement(test, body); } function parseForVariableDeclaration() { - var token, declarations, startToken; + var token, declarations, node = new Node(); - startToken = lookahead; token = lex(); declarations = parseVariableDeclarationList(); - return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken); + return node.finishVariableDeclaration(declarations, token.value); } - function parseForStatement() { - var init, test, update, left, right, body, oldInIteration; + function parseForStatement(node) { + var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn; init = test = update = null; @@ -2830,7 +3197,7 @@ parseStatement: true, parseSourceElement: true */ if (matchKeyword('var') || matchKeyword('let')) { state.allowIn = false; init = parseForVariableDeclaration(); - state.allowIn = true; + state.allowIn = previousAllowIn; if (init.declarations.length === 1 && matchKeyword('in')) { lex(); @@ -2841,12 +3208,12 @@ parseStatement: true, parseSourceElement: true */ } else { state.allowIn = false; init = parseExpression(); - state.allowIn = true; + state.allowIn = previousAllowIn; if (matchKeyword('in')) { // LeftHandSideExpression if (!isLeftHandSide(init)) { - throwErrorTolerant({}, Messages.InvalidLHSInForIn); + tolerateError(Messages.InvalidLHSInForIn); } lex(); @@ -2883,13 +3250,13 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; return (typeof left === 'undefined') ? - delegate.createForStatement(init, test, update, body) : - delegate.createForInStatement(left, right, body); + node.finishForStatement(init, test, update, body) : + node.finishForInStatement(left, right, body); } // 12.7 The continue statement - function parseContinueStatement() { + function parseContinueStatement(node) { var label = null, key; expectKeyword('continue'); @@ -2899,18 +3266,18 @@ parseStatement: true, parseSourceElement: true */ lex(); if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); + throwError(Messages.IllegalContinue); } - return delegate.createContinueStatement(null); + return node.finishContinueStatement(null); } if (peekLineTerminator()) { if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); + throwError(Messages.IllegalContinue); } - return delegate.createContinueStatement(null); + return node.finishContinueStatement(null); } if (lookahead.type === Token.Identifier) { @@ -2918,22 +3285,22 @@ parseStatement: true, parseSourceElement: true */ key = '$' + label.name; if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); + throwError(Messages.UnknownLabel, label.name); } } consumeSemicolon(); if (label === null && !state.inIteration) { - throwError({}, Messages.IllegalContinue); + throwError(Messages.IllegalContinue); } - return delegate.createContinueStatement(label); + return node.finishContinueStatement(label); } // 12.8 The break statement - function parseBreakStatement() { + function parseBreakStatement(node) { var label = null, key; expectKeyword('break'); @@ -2943,18 +3310,18 @@ parseStatement: true, parseSourceElement: true */ lex(); if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); + throwError(Messages.IllegalBreak); } - return delegate.createBreakStatement(null); + return node.finishBreakStatement(null); } if (peekLineTerminator()) { if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); + throwError(Messages.IllegalBreak); } - return delegate.createBreakStatement(null); + return node.finishBreakStatement(null); } if (lookahead.type === Token.Identifier) { @@ -2962,28 +3329,28 @@ parseStatement: true, parseSourceElement: true */ key = '$' + label.name; if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); + throwError(Messages.UnknownLabel, label.name); } } consumeSemicolon(); if (label === null && !(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); + throwError(Messages.IllegalBreak); } - return delegate.createBreakStatement(label); + return node.finishBreakStatement(label); } // 12.9 The return statement - function parseReturnStatement() { + function parseReturnStatement(node) { var argument = null; expectKeyword('return'); if (!state.inFunctionBody) { - throwErrorTolerant({}, Messages.IllegalReturn); + tolerateError(Messages.IllegalReturn); } // 'return' followed by a space and an identifier is very common. @@ -2991,12 +3358,12 @@ parseStatement: true, parseSourceElement: true */ if (isIdentifierStart(source.charCodeAt(index + 1))) { argument = parseExpression(); consumeSemicolon(); - return delegate.createReturnStatement(argument); + return node.finishReturnStatement(argument); } } if (peekLineTerminator()) { - return delegate.createReturnStatement(null); + return node.finishReturnStatement(null); } if (!match(';')) { @@ -3007,18 +3374,18 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return delegate.createReturnStatement(argument); + return node.finishReturnStatement(argument); } // 12.10 The with statement - function parseWithStatement() { + function parseWithStatement(node) { var object, body; if (strict) { // TODO(ikarienator): Should we update the test cases instead? skipComment(); - throwErrorTolerant({}, Messages.StrictModeWith); + tolerateError(Messages.StrictModeWith); } expectKeyword('with'); @@ -3031,15 +3398,14 @@ parseStatement: true, parseSourceElement: true */ body = parseStatement(); - return delegate.createWithStatement(object, body); + return node.finishWithStatement(object, body); } // 12.10 The swith statement function parseSwitchCase() { - var test, consequent = [], statement, startToken; + var test, consequent = [], statement, node = new Node(); - startToken = lookahead; if (matchKeyword('default')) { lex(); test = null; @@ -3057,10 +3423,10 @@ parseStatement: true, parseSourceElement: true */ consequent.push(statement); } - return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken); + return node.finishSwitchCase(test, consequent); } - function parseSwitchStatement() { + function parseSwitchStatement(node) { var discriminant, cases, clause, oldInSwitch, defaultFound; expectKeyword('switch'); @@ -3077,7 +3443,7 @@ parseStatement: true, parseSourceElement: true */ if (match('}')) { lex(); - return delegate.createSwitchStatement(discriminant, cases); + return node.finishSwitchStatement(discriminant, cases); } oldInSwitch = state.inSwitch; @@ -3091,7 +3457,7 @@ parseStatement: true, parseSourceElement: true */ clause = parseSwitchCase(); if (clause.test === null) { if (defaultFound) { - throwError({}, Messages.MultipleDefaultsInSwitch); + throwError(Messages.MultipleDefaultsInSwitch); } defaultFound = true; } @@ -3102,52 +3468,51 @@ parseStatement: true, parseSourceElement: true */ expect('}'); - return delegate.createSwitchStatement(discriminant, cases); + return node.finishSwitchStatement(discriminant, cases); } // 12.13 The throw statement - function parseThrowStatement() { + function parseThrowStatement(node) { var argument; expectKeyword('throw'); if (peekLineTerminator()) { - throwError({}, Messages.NewlineAfterThrow); + throwError(Messages.NewlineAfterThrow); } argument = parseExpression(); consumeSemicolon(); - return delegate.createThrowStatement(argument); + return node.finishThrowStatement(argument); } // 12.14 The try statement function parseCatchClause() { - var param, body, startToken; + var param, body, node = new Node(); - startToken = lookahead; expectKeyword('catch'); expect('('); if (match(')')) { - throwUnexpected(lookahead); + throwUnexpectedToken(lookahead); } param = parseVariableIdentifier(); // 12.14.1 if (strict && isRestrictedWord(param.name)) { - throwErrorTolerant({}, Messages.StrictCatchVariable); + tolerateError(Messages.StrictCatchVariable); } expect(')'); body = parseBlock(); - return delegate.markEnd(delegate.createCatchClause(param, body), startToken); + return node.finishCatchClause(param, body); } - function parseTryStatement() { + function parseTryStatement(node) { var block, handlers = [], finalizer = null; expectKeyword('try'); @@ -3164,20 +3529,20 @@ parseStatement: true, parseSourceElement: true */ } if (handlers.length === 0 && !finalizer) { - throwError({}, Messages.NoCatchOrFinally); + throwError(Messages.NoCatchOrFinally); } - return delegate.createTryStatement(block, [], handlers, finalizer); + return node.finishTryStatement(block, [], handlers, finalizer); } // 12.15 The debugger statement - function parseDebuggerStatement() { + function parseDebuggerStatement(node) { expectKeyword('debugger'); consumeSemicolon(); - return delegate.createDebuggerStatement(); + return node.finishDebuggerStatement(); } // 12 Statements @@ -3187,59 +3552,57 @@ parseStatement: true, parseSourceElement: true */ expr, labeledBody, key, - startToken; + node; if (type === Token.EOF) { - throwUnexpected(lookahead); + throwUnexpectedToken(lookahead); } if (type === Token.Punctuator && lookahead.value === '{') { return parseBlock(); } - startToken = lookahead; + node = new Node(); if (type === Token.Punctuator) { switch (lookahead.value) { case ';': - return delegate.markEnd(parseEmptyStatement(), startToken); + return parseEmptyStatement(node); case '(': - return delegate.markEnd(parseExpressionStatement(), startToken); + return parseExpressionStatement(node); default: break; } - } - - if (type === Token.Keyword) { + } else if (type === Token.Keyword) { switch (lookahead.value) { case 'break': - return delegate.markEnd(parseBreakStatement(), startToken); + return parseBreakStatement(node); case 'continue': - return delegate.markEnd(parseContinueStatement(), startToken); + return parseContinueStatement(node); case 'debugger': - return delegate.markEnd(parseDebuggerStatement(), startToken); + return parseDebuggerStatement(node); case 'do': - return delegate.markEnd(parseDoWhileStatement(), startToken); + return parseDoWhileStatement(node); case 'for': - return delegate.markEnd(parseForStatement(), startToken); + return parseForStatement(node); case 'function': - return delegate.markEnd(parseFunctionDeclaration(), startToken); + return parseFunctionDeclaration(node); case 'if': - return delegate.markEnd(parseIfStatement(), startToken); + return parseIfStatement(node); case 'return': - return delegate.markEnd(parseReturnStatement(), startToken); + return parseReturnStatement(node); case 'switch': - return delegate.markEnd(parseSwitchStatement(), startToken); + return parseSwitchStatement(node); case 'throw': - return delegate.markEnd(parseThrowStatement(), startToken); + return parseThrowStatement(node); case 'try': - return delegate.markEnd(parseTryStatement(), startToken); + return parseTryStatement(node); case 'var': - return delegate.markEnd(parseVariableStatement(), startToken); + return parseVariableStatement(node); case 'while': - return delegate.markEnd(parseWhileStatement(), startToken); + return parseWhileStatement(node); case 'with': - return delegate.markEnd(parseWithStatement(), startToken); + return parseWithStatement(node); default: break; } @@ -3253,27 +3616,27 @@ parseStatement: true, parseSourceElement: true */ key = '$' + expr.name; if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.Redeclaration, 'Label', expr.name); + throwError(Messages.Redeclaration, 'Label', expr.name); } state.labelSet[key] = true; labeledBody = parseStatement(); delete state.labelSet[key]; - return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken); + return node.finishLabeledStatement(expr, labeledBody); } consumeSemicolon(); - return delegate.markEnd(delegate.createExpressionStatement(expr), startToken); + return node.finishExpressionStatement(expr); } // 13 Function Definition function parseFunctionSourceElements() { var sourceElement, sourceElements = [], token, directive, firstRestricted, - oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken; + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount, + node = new Node(); - startToken = lookahead; expect('{'); while (index < length) { @@ -3292,7 +3655,7 @@ parseStatement: true, parseSourceElement: true */ if (directive === 'use strict') { strict = true; if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); } } else { if (!firstRestricted && token.octal) { @@ -3305,11 +3668,13 @@ parseStatement: true, parseSourceElement: true */ oldInIteration = state.inIteration; oldInSwitch = state.inSwitch; oldInFunctionBody = state.inFunctionBody; + oldParenthesisCount = state.parenthesizedCount; state.labelSet = {}; state.inIteration = false; state.inSwitch = false; state.inFunctionBody = true; + state.parenthesizedCount = 0; while (index < length) { if (match('}')) { @@ -3328,44 +3693,71 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; state.inSwitch = oldInSwitch; state.inFunctionBody = oldInFunctionBody; + state.parenthesizedCount = oldParenthesisCount; + + return node.finishBlockStatement(sourceElements); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.firstRestricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, param, def; + + token = lookahead; + param = parseVariableIdentifier(); + validateParam(options, token, token.value); + if (match('=')) { + lex(); + def = parseAssignmentExpression(); + ++options.defaultCount; + } - return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken); + options.params.push(param); + options.defaults.push(def); + + return !match(')'); } function parseParams(firstRestricted) { - var param, params = [], token, stricted, paramSet, key, message; + var options; + + options = { + params: [], + defaultCount: 0, + defaults: [], + firstRestricted: firstRestricted + }; + expect('('); if (!match(')')) { - paramSet = {}; + options.paramSet = {}; while (index < length) { - token = lookahead; - param = parseVariableIdentifier(); - key = '$' + token.value; - if (strict) { - if (isRestrictedWord(token.value)) { - stricted = token; - message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - stricted = token; - message = Messages.StrictParamDupe; - } - } else if (!firstRestricted) { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - firstRestricted = token; - message = Messages.StrictParamDupe; - } - } - params.push(param); - paramSet[key] = true; - if (match(')')) { + if (!parseParam(options)) { break; } expect(','); @@ -3374,25 +3766,28 @@ parseStatement: true, parseSourceElement: true */ expect(')'); + if (options.defaultCount === 0) { + options.defaults = []; + } + return { - params: params, - stricted: stricted, - firstRestricted: firstRestricted, - message: message + params: options.params, + defaults: options.defaults, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message }; } function parseFunctionDeclaration() { - var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken; - - startToken = lookahead; + var id, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, node = new Node(); expectKeyword('function'); token = lookahead; id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); + tolerateUnexpectedToken(token, Messages.StrictFunctionName); } } else { if (isRestrictedWord(token.value)) { @@ -3406,6 +3801,7 @@ parseStatement: true, parseSourceElement: true */ tmp = parseParams(firstRestricted); params = tmp.params; + defaults = tmp.defaults; stricted = tmp.stricted; firstRestricted = tmp.firstRestricted; if (tmp.message) { @@ -3415,20 +3811,20 @@ parseStatement: true, parseSourceElement: true */ previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { - throwError(firstRestricted, message); + throwUnexpectedToken(firstRestricted, message); } if (strict && stricted) { - throwErrorTolerant(stricted, message); + tolerateUnexpectedToken(stricted, message); } strict = previousStrict; - return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken); + return node.finishFunctionDeclaration(id, params, defaults, body); } function parseFunctionExpression() { - var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken; + var token, id = null, stricted, firstRestricted, message, tmp, + params = [], defaults = [], body, previousStrict, node = new Node(); - startToken = lookahead; expectKeyword('function'); if (!match('(')) { @@ -3436,7 +3832,7 @@ parseStatement: true, parseSourceElement: true */ id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); + tolerateUnexpectedToken(token, Messages.StrictFunctionName); } } else { if (isRestrictedWord(token.value)) { @@ -3451,6 +3847,7 @@ parseStatement: true, parseSourceElement: true */ tmp = parseParams(firstRestricted); params = tmp.params; + defaults = tmp.defaults; stricted = tmp.stricted; firstRestricted = tmp.firstRestricted; if (tmp.message) { @@ -3460,14 +3857,14 @@ parseStatement: true, parseSourceElement: true */ previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { - throwError(firstRestricted, message); + throwUnexpectedToken(firstRestricted, message); } if (strict && stricted) { - throwErrorTolerant(stricted, message); + tolerateUnexpectedToken(stricted, message); } strict = previousStrict; - return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken); + return node.finishFunctionExpression(id, params, defaults, body); } // 14 Program @@ -3509,7 +3906,7 @@ parseStatement: true, parseSourceElement: true */ if (directive === 'use strict') { strict = true; if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); } } else { if (!firstRestricted && token.octal) { @@ -3530,15 +3927,15 @@ parseStatement: true, parseSourceElement: true */ } function parseProgram() { - var body, startToken; + var body, node; skipComment(); peek(); - startToken = lookahead; + node = new Node(); strict = false; body = parseSourceElements(); - return delegate.markEnd(delegate.createProgram(body), startToken); + return node.finishProgram(body); } function filterTokenLocation() { @@ -3550,6 +3947,12 @@ parseStatement: true, parseSourceElement: true */ type: entry.type, value: entry.value }; + if (entry.regex) { + token.regex = { + pattern: entry.regex.pattern, + flags: entry.regex.flags + }; + } if (extra.range) { token.range = entry.range; } @@ -3564,7 +3967,6 @@ parseStatement: true, parseSourceElement: true */ function tokenize(code, options) { var toString, - token, tokens; toString = String; @@ -3572,7 +3974,6 @@ parseStatement: true, parseSourceElement: true */ code = toString(code); } - delegate = SyntaxTreeDelegate; source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; @@ -3617,12 +4018,11 @@ parseStatement: true, parseSourceElement: true */ return extra.tokens; } - token = lex(); + lex(); while (lookahead.type !== Token.EOF) { try { - token = lex(); + lex(); } catch (lexError) { - token = lookahead; if (extra.errors) { extra.errors.push(lexError); // We have to break on the first error @@ -3658,7 +4058,6 @@ parseStatement: true, parseSourceElement: true */ code = toString(code); } - delegate = SyntaxTreeDelegate; source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; @@ -3668,6 +4067,7 @@ parseStatement: true, parseSourceElement: true */ state = { allowIn: true, labelSet: {}, + parenthesisCount: 0, inFunctionBody: false, inIteration: false, inSwitch: false, @@ -3724,7 +4124,7 @@ parseStatement: true, parseSourceElement: true */ } // Sync with *.json manifests. - exports.version = '1.2.2'; + exports.version = '2.0.0'; exports.tokenize = tokenize; From 8614bfba3abe4ed22875c41978383221c1f9e94b Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 7 Feb 2015 11:28:22 -0800 Subject: [PATCH 214/382] snapshot --- dist/r.js | 1838 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 1119 insertions(+), 719 deletions(-) diff --git a/dist/r.js b/dist/r.js index 7a006dc9..fa456af7 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15+ Thu, 25 Dec 2014 22:51:40 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Sat, 07 Feb 2015 19:28:10 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15+ Thu, 25 Dec 2014 22:51:40 GMT', + version = '2.1.15+ Sat, 07 Feb 2015 19:28:10 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -4574,17 +4574,6 @@ define('logger', ['env!env/print'], function (print) { THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/*jslint bitwise:true plusplus:true */ -/*global esprima:true, define:true, exports:true, window: true, -throwErrorTolerant: true, -throwError: true, generateStatement: true, peek: true, -parseAssignmentExpression: true, parseBlock: true, parseExpression: true, -parseFunctionDeclaration: true, parseFunctionExpression: true, -parseFunctionSourceElements: true, parseVariableIdentifier: true, -parseLeftHandSideExpression: true, -parseUnaryExpression: true, -parseStatement: true, parseSourceElement: true */ - (function (root, factory) { 'use strict'; @@ -4606,17 +4595,16 @@ parseStatement: true, parseSourceElement: true */ TokenName, FnExprTokens, Syntax, + PlaceHolders, PropertyKind, Messages, Regex, - SyntaxTreeDelegate, source, strict, index, lineNumber, lineStart, length, - delegate, lookahead, state, extra; @@ -4658,6 +4646,7 @@ parseStatement: true, parseSourceElement: true */ Syntax = { AssignmentExpression: 'AssignmentExpression', ArrayExpression: 'ArrayExpression', + ArrowFunctionExpression: 'ArrowFunctionExpression', BlockStatement: 'BlockStatement', BinaryExpression: 'BinaryExpression', BreakStatement: 'BreakStatement', @@ -4698,6 +4687,12 @@ parseStatement: true, parseSourceElement: true */ WithStatement: 'WithStatement' }; + PlaceHolders = { + ArrowParameterPlaceHolder: { + type: 'ArrowParameterPlaceHolder' + } + }; + PropertyKind = { Data: 1, Get: 2, @@ -4706,45 +4701,45 @@ parseStatement: true, parseSourceElement: true */ // Error messages should be identical to V8. Messages = { - UnexpectedToken: 'Unexpected token %0', - UnexpectedNumber: 'Unexpected number', - UnexpectedString: 'Unexpected string', - UnexpectedIdentifier: 'Unexpected identifier', - UnexpectedReserved: 'Unexpected reserved word', - UnexpectedEOS: 'Unexpected end of input', - NewlineAfterThrow: 'Illegal newline after throw', + UnexpectedToken: 'Unexpected token %0', + UnexpectedNumber: 'Unexpected number', + UnexpectedString: 'Unexpected string', + UnexpectedIdentifier: 'Unexpected identifier', + UnexpectedReserved: 'Unexpected reserved word', + UnexpectedEOS: 'Unexpected end of input', + NewlineAfterThrow: 'Illegal newline after throw', InvalidRegExp: 'Invalid regular expression', - UnterminatedRegExp: 'Invalid regular expression: missing /', - InvalidLHSInAssignment: 'Invalid left-hand side in assignment', - InvalidLHSInForIn: 'Invalid left-hand side in for-in', + UnterminatedRegExp: 'Invalid regular expression: missing /', + InvalidLHSInAssignment: 'Invalid left-hand side in assignment', + InvalidLHSInForIn: 'Invalid left-hand side in for-in', MultipleDefaultsInSwitch: 'More than one default clause in switch statement', - NoCatchOrFinally: 'Missing catch or finally after try', + NoCatchOrFinally: 'Missing catch or finally after try', UnknownLabel: 'Undefined label \'%0\'', Redeclaration: '%0 \'%1\' has already been declared', IllegalContinue: 'Illegal continue statement', IllegalBreak: 'Illegal break statement', IllegalReturn: 'Illegal return statement', - StrictModeWith: 'Strict mode code may not include a with statement', - StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', - StrictVarName: 'Variable name may not be eval or arguments in strict mode', - StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', + StrictModeWith: 'Strict mode code may not include a with statement', + StrictCatchVariable: 'Catch variable may not be eval or arguments in strict mode', + StrictVarName: 'Variable name may not be eval or arguments in strict mode', + StrictParamName: 'Parameter name eval or arguments is not allowed in strict mode', StrictParamDupe: 'Strict mode function may not have duplicate parameter names', - StrictFunctionName: 'Function name may not be eval or arguments in strict mode', - StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', - StrictDelete: 'Delete of an unqualified identifier in strict mode.', - StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', - AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', - AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', - StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', - StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', - StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', - StrictReservedWord: 'Use of future reserved word in strict mode' + StrictFunctionName: 'Function name may not be eval or arguments in strict mode', + StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', + StrictDelete: 'Delete of an unqualified identifier in strict mode.', + StrictDuplicateProperty: 'Duplicate data property in object literal not allowed in strict mode', + AccessorDataProperty: 'Object literal may not have data and accessor property with the same name', + AccessorGetSet: 'Object literal may not have multiple get/set accessors with the same name', + StrictLHSAssignment: 'Assignment to eval or arguments is not allowed in strict mode', + StrictLHSPostfix: 'Postfix increment/decrement may not have eval or arguments operand in strict mode', + StrictLHSPrefix: 'Prefix increment/decrement may not have eval or arguments operand in strict mode', + StrictReservedWord: 'Use of future reserved word in strict mode' }; // See also tools/generate-unicode-regex.py. Regex = { - NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), - NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') + NonAsciiIdentifierStart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]'), + NonAsciiIdentifierPart: new RegExp('[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]') }; // Ensure the condition is true, otherwise throw an error. @@ -4760,7 +4755,7 @@ parseStatement: true, parseSourceElement: true */ } function isDecimalDigit(ch) { - return (ch >= 48 && ch <= 57); // 0..9 + return (ch >= 0x30 && ch <= 0x39); // 0..9 } function isHexDigit(ch) { @@ -4849,7 +4844,7 @@ parseStatement: true, parseSourceElement: true */ } // 'const' is specialized as Keyword in V8. - // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. + // 'yield' and 'let' are for compatibility with SpiderMonkey and ES.next. // Some others are from future reserved words. switch (id.length) { @@ -4882,7 +4877,7 @@ parseStatement: true, parseSourceElement: true */ // 7.4 Comments function addComment(type, value, start, end, loc) { - var comment, attacher; + var comment; assert(typeof start === 'number', 'Comment must have valid position'); @@ -4977,7 +4972,7 @@ parseStatement: true, parseSourceElement: true */ ++index; lineStart = index; if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } } else if (ch === 0x2A) { // Block comment ends with '*/'. @@ -5000,7 +4995,7 @@ parseStatement: true, parseSourceElement: true */ } } - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } function skipComment() { @@ -5074,6 +5069,38 @@ parseStatement: true, parseSourceElement: true */ return String.fromCharCode(code); } + function scanUnicodeCodePointEscape() { + var ch, code, cu1, cu2; + + ch = source[index]; + code = 0; + + // At least, one hex digit is required. + if (ch === '}') { + throwUnexpectedToken(); + } + + while (index < length) { + ch = source[index++]; + if (!isHexDigit(ch)) { + break; + } + code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); + } + + if (code > 0x10FFFF || ch !== '}') { + throwUnexpectedToken(); + } + + // UTF-16 Encoding + if (code <= 0xFFFF) { + return String.fromCharCode(code); + } + cu1 = ((code - 0x10000) >> 10) + 0xD800; + cu2 = ((code - 0x10000) & 1023) + 0xDC00; + return String.fromCharCode(cu1, cu2); + } + function getEscapedIdentifier() { var ch, id; @@ -5083,12 +5110,12 @@ parseStatement: true, parseSourceElement: true */ // '\u' (U+005C, U+0075) denotes an escaped character. if (ch === 0x5C) { if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } ++index; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } id = ch; } @@ -5105,12 +5132,12 @@ parseStatement: true, parseSourceElement: true */ if (ch === 0x5C) { id = id.substr(0, id.length - 1); if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } ++index; ch = scanHexEscape('u'); if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } id += ch; } @@ -5310,6 +5337,7 @@ parseStatement: true, parseSourceElement: true */ } // 1-character punctuators: < > = ! + - * % & | ^ / + if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { ++index; return { @@ -5322,7 +5350,7 @@ parseStatement: true, parseSourceElement: true */ }; } - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } // 7.8.3 Numeric Literals @@ -5338,11 +5366,11 @@ parseStatement: true, parseSourceElement: true */ } if (number.length === 0) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { @@ -5355,8 +5383,54 @@ parseStatement: true, parseSourceElement: true */ }; } - function scanOctalLiteral(start) { - var number = '0' + source[index++]; + function scanBinaryLiteral(start) { + var ch, number; + + number = ''; + + while (index < length) { + ch = source[index]; + if (ch !== '0' && ch !== '1') { + break; + } + number += source[index++]; + } + + if (number.length === 0) { + // only 0b or 0B + throwUnexpectedToken(); + } + + if (index < length) { + ch = source.charCodeAt(index); + /* istanbul ignore else */ + if (isIdentifierStart(ch) || isDecimalDigit(ch)) { + throwUnexpectedToken(); + } + } + + return { + type: Token.NumericLiteral, + value: parseInt(number, 2), + lineNumber: lineNumber, + lineStart: lineStart, + start: start, + end: index + }; + } + + function scanOctalLiteral(prefix, start) { + var number, octal; + + if (isOctalDigit(prefix)) { + octal = true; + number = '0' + source[index++]; + } else { + octal = false; + ++index; + number = ''; + } + while (index < length) { if (!isOctalDigit(source[index])) { break; @@ -5364,14 +5438,19 @@ parseStatement: true, parseSourceElement: true */ number += source[index++]; } + if (!octal && number.length === 0) { + // only 0o or 0O + throwUnexpectedToken(); + } + if (isIdentifierStart(source.charCodeAt(index)) || isDecimalDigit(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { type: Token.NumericLiteral, value: parseInt(number, 8), - octal: true, + octal: octal, lineNumber: lineNumber, lineStart: lineStart, start: start, @@ -5379,6 +5458,24 @@ parseStatement: true, parseSourceElement: true */ }; } + function isImplicitOctalLiteral() { + var i, ch; + + // Implicit octal, unless there is a non-octal digit. + // (Annex B.1.1 on Numeric Literals) + for (i = index + 1; i < length; ++i) { + ch = source[i]; + if (ch === '8' || ch === '9') { + return false; + } + if (!isOctalDigit(ch)) { + return true; + } + } + + return true; + } + function scanNumericLiteral() { var number, start, ch; @@ -5394,18 +5491,25 @@ parseStatement: true, parseSourceElement: true */ // Hex number starts with '0x'. // Octal number starts with '0'. + // Octal number in ES6 starts with '0o'. + // Binary number in ES6 starts with '0b'. if (number === '0') { if (ch === 'x' || ch === 'X') { ++index; return scanHexLiteral(start); } - if (isOctalDigit(ch)) { - return scanOctalLiteral(start); + if (ch === 'b' || ch === 'B') { + ++index; + return scanBinaryLiteral(start); + } + if (ch === 'o' || ch === 'O') { + return scanOctalLiteral(ch, start); } - // decimal number starts with '0' such as '09' is illegal. - if (ch && isDecimalDigit(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + if (isOctalDigit(ch)) { + if (isImplicitOctalLiteral()) { + return scanOctalLiteral(ch, start); + } } } @@ -5435,12 +5539,12 @@ parseStatement: true, parseSourceElement: true */ number += source[index++]; } } else { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } } if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { @@ -5479,13 +5583,18 @@ parseStatement: true, parseSourceElement: true */ switch (ch) { case 'u': case 'x': - restore = index; - unescaped = scanHexEscape(ch); - if (unescaped) { - str += unescaped; + if (source[index] === '{') { + ++index; + str += scanUnicodeCodePointEscape(); } else { - index = restore; - str += ch; + restore = index; + unescaped = scanHexEscape(ch); + if (unescaped) { + str += unescaped; + } else { + index = restore; + str += ch; + } } break; case 'n': @@ -5536,7 +5645,7 @@ parseStatement: true, parseSourceElement: true */ } } else { ++lineNumber; - if (ch === '\r' && source[index] === '\n') { + if (ch === '\r' && source[index] === '\n') { ++index; } lineStart = index; @@ -5549,7 +5658,7 @@ parseStatement: true, parseSourceElement: true */ } if (quote !== '') { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); + throwUnexpectedToken(); } return { @@ -5566,13 +5675,43 @@ parseStatement: true, parseSourceElement: true */ } function testRegExp(pattern, flags) { - var value; + var tmp = pattern, + value; + + if (flags.indexOf('u') >= 0) { + // Replace each astral symbol and every Unicode code point + // escape sequence with a single ASCII symbol to avoid throwing on + // regular expressions that are only valid in combination with the + // `/u` flag. + // Note: replacing with the ASCII symbol `x` might cause false + // negatives in unlikely scenarios. For example, `[\u{61}-b]` is a + // perfectly valid pattern that is equivalent to `[a-b]`, but it + // would be replaced by `[x-b]` which throws an error. + tmp = tmp + .replace(/\\u\{([0-9a-fA-F]+)\}/g, function ($0, $1) { + if (parseInt($1, 16) <= 0x10FFFF) { + return 'x'; + } + throwError(Messages.InvalidRegExp); + }) + .replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, 'x'); + } + + // First, detect invalid regular expressions. try { - value = new RegExp(pattern, flags); + value = new RegExp(tmp); } catch (e) { - throwError({}, Messages.InvalidRegExp); + throwError(Messages.InvalidRegExp); + } + + // Return a regular expression object for this pattern-flag pair, or + // `null` in case the current environment doesn't support the flags it + // uses. + try { + return new RegExp(pattern, flags); + } catch (exception) { + return null; } - return value; } function scanRegExpBody() { @@ -5591,11 +5730,11 @@ parseStatement: true, parseSourceElement: true */ ch = source[index++]; // ECMA-262 7.8.5 if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); + throwError(Messages.UnterminatedRegExp); } str += ch; } else if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); + throwError(Messages.UnterminatedRegExp); } else if (classMarker) { if (ch === ']') { classMarker = false; @@ -5611,7 +5750,7 @@ parseStatement: true, parseSourceElement: true */ } if (!terminated) { - throwError({}, Messages.UnterminatedRegExp); + throwError(Messages.UnterminatedRegExp); } // Exclude leading and trailing slash. @@ -5650,10 +5789,10 @@ parseStatement: true, parseSourceElement: true */ flags += 'u'; str += '\\u'; } - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); + tolerateUnexpectedToken(); } else { str += '\\'; - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); + tolerateUnexpectedToken(); } } else { flags += ch; @@ -5668,7 +5807,7 @@ parseStatement: true, parseSourceElement: true */ } function scanRegExp() { - var start, body, flags, pattern, value; + var start, body, flags, value; lookahead = null; skipComment(); @@ -5682,6 +5821,10 @@ parseStatement: true, parseSourceElement: true */ return { type: Token.RegularExpression, value: value, + regex: { + pattern: body.value, + flags: flags.value + }, lineNumber: lineNumber, lineStart: lineStart, start: start, @@ -5692,6 +5835,10 @@ parseStatement: true, parseSourceElement: true */ return { literal: body.literal + flags.literal, value: value, + regex: { + pattern: body.value, + flags: flags.value + }, start: start, end: index }; @@ -5711,6 +5858,7 @@ parseStatement: true, parseSourceElement: true */ }; regex = scanRegExp(); + loc.end = { line: lineNumber, column: index - lineStart @@ -5731,6 +5879,7 @@ parseStatement: true, parseSourceElement: true */ extra.tokens.push({ type: 'RegularExpression', value: regex.literal, + regex: regex.regex, range: [pos, index], loc: loc }); @@ -5803,7 +5952,7 @@ parseStatement: true, parseSourceElement: true */ } return collectRegex(); } - if (prevToken.type === 'Keyword') { + if (prevToken.type === 'Keyword' && prevToken.value !== 'this') { return collectRegex(); } return scanPunctuator(); @@ -5863,7 +6012,7 @@ parseStatement: true, parseSourceElement: true */ } function collectToken() { - var loc, token, range, value; + var loc, token, value, entry; skipComment(); loc = { @@ -5881,12 +6030,19 @@ parseStatement: true, parseSourceElement: true */ if (token.type !== Token.EOF) { value = source.slice(token.start, token.end); - extra.tokens.push({ + entry = { type: TokenName[token.type], value: value, range: [token.start, token.end], loc: loc - }); + }; + if (token.regex) { + entry.regex = { + pattern: token.regex.pattern, + flags: token.regex.flags + }; + } + extra.tokens.push(entry); } return token; @@ -5921,422 +6077,478 @@ parseStatement: true, parseSourceElement: true */ lineStart = start; } - function Position(line, column) { - this.line = line; - this.column = column; + function Position() { + this.line = lineNumber; + this.column = index - lineStart; } - function SourceLocation(startLine, startColumn, line, column) { - this.start = new Position(startLine, startColumn); - this.end = new Position(line, column); + function SourceLocation() { + this.start = new Position(); + this.end = null; } - SyntaxTreeDelegate = { + function WrappingSourceLocation(startToken) { + if (startToken.type === Token.StringLiteral) { + this.start = { + line: startToken.startLineNumber, + column: startToken.start - startToken.startLineStart + }; + } else { + this.start = { + line: startToken.lineNumber, + column: startToken.start - startToken.lineStart + }; + } + this.end = null; + } - name: 'SyntaxTree', + function Node() { + // Skip comment. + index = lookahead.start; + if (lookahead.type === Token.StringLiteral) { + lineNumber = lookahead.startLineNumber; + lineStart = lookahead.startLineStart; + } else { + lineNumber = lookahead.lineNumber; + lineStart = lookahead.lineStart; + } + if (extra.range) { + this.range = [index, 0]; + } + if (extra.loc) { + this.loc = new SourceLocation(); + } + } - processComment: function (node) { - var lastChild, trailingComments; + function WrappingNode(startToken) { + if (extra.range) { + this.range = [startToken.start, 0]; + } + if (extra.loc) { + this.loc = new WrappingSourceLocation(startToken); + } + } + + WrappingNode.prototype = Node.prototype = { + + processComment: function () { + var lastChild, + leadingComments, + trailingComments, + bottomRight = extra.bottomRightStack, + i, + comment, + last = bottomRight[bottomRight.length - 1]; - if (node.type === Syntax.Program) { - if (node.body.length > 0) { + if (this.type === Syntax.Program) { + if (this.body.length > 0) { return; } } if (extra.trailingComments.length > 0) { - if (extra.trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.trailingComments; - extra.trailingComments = []; - } else { - extra.trailingComments.length = 0; + trailingComments = []; + for (i = extra.trailingComments.length - 1; i >= 0; --i) { + comment = extra.trailingComments[i]; + if (comment.range[0] >= this.range[1]) { + trailingComments.unshift(comment); + extra.trailingComments.splice(i, 1); + } } + extra.trailingComments = []; } else { - if (extra.bottomRightStack.length > 0 && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments && - extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; - delete extra.bottomRightStack[extra.bottomRightStack.length - 1].trailingComments; + if (last && last.trailingComments && last.trailingComments[0].range[0] >= this.range[1]) { + trailingComments = last.trailingComments; + delete last.trailingComments; } } // Eating the stack. - while (extra.bottomRightStack.length > 0 && extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= node.range[0]) { - lastChild = extra.bottomRightStack.pop(); + if (last) { + while (last && last.range[0] >= this.range[0]) { + lastChild = last; + last = bottomRight.pop(); + } } if (lastChild) { - if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = lastChild.leadingComments; - delete lastChild.leadingComments; + if (lastChild.leadingComments && lastChild.leadingComments[lastChild.leadingComments.length - 1].range[1] <= this.range[0]) { + this.leadingComments = lastChild.leadingComments; + lastChild.leadingComments = undefined; + } + } else if (extra.leadingComments.length > 0) { + leadingComments = []; + for (i = extra.leadingComments.length - 1; i >= 0; --i) { + comment = extra.leadingComments[i]; + if (comment.range[1] <= this.range[0]) { + leadingComments.unshift(comment); + extra.leadingComments.splice(i, 1); + } } - } else if (extra.leadingComments.length > 0 && extra.leadingComments[extra.leadingComments.length - 1].range[1] <= node.range[0]) { - node.leadingComments = extra.leadingComments; - extra.leadingComments = []; } - if (trailingComments) { - node.trailingComments = trailingComments; + if (leadingComments && leadingComments.length > 0) { + this.leadingComments = leadingComments; + } + if (trailingComments && trailingComments.length > 0) { + this.trailingComments = trailingComments; } - extra.bottomRightStack.push(node); + bottomRight.push(this); }, - markEnd: function (node, startToken) { + finish: function () { if (extra.range) { - node.range = [startToken.start, index]; + this.range[1] = index; } if (extra.loc) { - node.loc = new SourceLocation( - startToken.startLineNumber === undefined ? startToken.lineNumber : startToken.startLineNumber, - startToken.start - (startToken.startLineStart === undefined ? startToken.lineStart : startToken.startLineStart), - lineNumber, - index - lineStart - ); - this.postProcess(node); + this.loc.end = new Position(); + if (extra.source) { + this.loc.source = extra.source; + } } if (extra.attachComment) { - this.processComment(node); + this.processComment(); } - return node; }, - postProcess: function (node) { - if (extra.source) { - node.loc.source = extra.source; - } - return node; + finishArrayExpression: function (elements) { + this.type = Syntax.ArrayExpression; + this.elements = elements; + this.finish(); + return this; }, - createArrayExpression: function (elements) { - return { - type: Syntax.ArrayExpression, - elements: elements - }; + finishArrowFunctionExpression: function (params, defaults, body, expression) { + this.type = Syntax.ArrowFunctionExpression; + this.id = null; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = expression; + this.finish(); + return this; }, - createAssignmentExpression: function (operator, left, right) { - return { - type: Syntax.AssignmentExpression, - operator: operator, - left: left, - right: right - }; + finishAssignmentExpression: function (operator, left, right) { + this.type = Syntax.AssignmentExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; }, - createBinaryExpression: function (operator, left, right) { - var type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : - Syntax.BinaryExpression; - return { - type: type, - operator: operator, - left: left, - right: right - }; + finishBinaryExpression: function (operator, left, right) { + this.type = (operator === '||' || operator === '&&') ? Syntax.LogicalExpression : Syntax.BinaryExpression; + this.operator = operator; + this.left = left; + this.right = right; + this.finish(); + return this; }, - createBlockStatement: function (body) { - return { - type: Syntax.BlockStatement, - body: body - }; + finishBlockStatement: function (body) { + this.type = Syntax.BlockStatement; + this.body = body; + this.finish(); + return this; }, - createBreakStatement: function (label) { - return { - type: Syntax.BreakStatement, - label: label - }; + finishBreakStatement: function (label) { + this.type = Syntax.BreakStatement; + this.label = label; + this.finish(); + return this; }, - createCallExpression: function (callee, args) { - return { - type: Syntax.CallExpression, - callee: callee, - 'arguments': args - }; + finishCallExpression: function (callee, args) { + this.type = Syntax.CallExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; }, - createCatchClause: function (param, body) { - return { - type: Syntax.CatchClause, - param: param, - body: body - }; + finishCatchClause: function (param, body) { + this.type = Syntax.CatchClause; + this.param = param; + this.body = body; + this.finish(); + return this; }, - createConditionalExpression: function (test, consequent, alternate) { - return { - type: Syntax.ConditionalExpression, - test: test, - consequent: consequent, - alternate: alternate - }; + finishConditionalExpression: function (test, consequent, alternate) { + this.type = Syntax.ConditionalExpression; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; }, - createContinueStatement: function (label) { - return { - type: Syntax.ContinueStatement, - label: label - }; + finishContinueStatement: function (label) { + this.type = Syntax.ContinueStatement; + this.label = label; + this.finish(); + return this; }, - createDebuggerStatement: function () { - return { - type: Syntax.DebuggerStatement - }; + finishDebuggerStatement: function () { + this.type = Syntax.DebuggerStatement; + this.finish(); + return this; }, - createDoWhileStatement: function (body, test) { - return { - type: Syntax.DoWhileStatement, - body: body, - test: test - }; + finishDoWhileStatement: function (body, test) { + this.type = Syntax.DoWhileStatement; + this.body = body; + this.test = test; + this.finish(); + return this; }, - createEmptyStatement: function () { - return { - type: Syntax.EmptyStatement - }; + finishEmptyStatement: function () { + this.type = Syntax.EmptyStatement; + this.finish(); + return this; }, - createExpressionStatement: function (expression) { - return { - type: Syntax.ExpressionStatement, - expression: expression - }; + finishExpressionStatement: function (expression) { + this.type = Syntax.ExpressionStatement; + this.expression = expression; + this.finish(); + return this; }, - createForStatement: function (init, test, update, body) { - return { - type: Syntax.ForStatement, - init: init, - test: test, - update: update, - body: body - }; + finishForStatement: function (init, test, update, body) { + this.type = Syntax.ForStatement; + this.init = init; + this.test = test; + this.update = update; + this.body = body; + this.finish(); + return this; }, - createForInStatement: function (left, right, body) { - return { - type: Syntax.ForInStatement, - left: left, - right: right, - body: body, - each: false - }; + finishForInStatement: function (left, right, body) { + this.type = Syntax.ForInStatement; + this.left = left; + this.right = right; + this.body = body; + this.each = false; + this.finish(); + return this; }, - createFunctionDeclaration: function (id, params, defaults, body) { - return { - type: Syntax.FunctionDeclaration, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false - }; + finishFunctionDeclaration: function (id, params, defaults, body) { + this.type = Syntax.FunctionDeclaration; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = false; + this.finish(); + return this; }, - createFunctionExpression: function (id, params, defaults, body) { - return { - type: Syntax.FunctionExpression, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false - }; + finishFunctionExpression: function (id, params, defaults, body) { + this.type = Syntax.FunctionExpression; + this.id = id; + this.params = params; + this.defaults = defaults; + this.body = body; + this.rest = null; + this.generator = false; + this.expression = false; + this.finish(); + return this; }, - createIdentifier: function (name) { - return { - type: Syntax.Identifier, - name: name - }; + finishIdentifier: function (name) { + this.type = Syntax.Identifier; + this.name = name; + this.finish(); + return this; }, - createIfStatement: function (test, consequent, alternate) { - return { - type: Syntax.IfStatement, - test: test, - consequent: consequent, - alternate: alternate - }; + finishIfStatement: function (test, consequent, alternate) { + this.type = Syntax.IfStatement; + this.test = test; + this.consequent = consequent; + this.alternate = alternate; + this.finish(); + return this; }, - createLabeledStatement: function (label, body) { - return { - type: Syntax.LabeledStatement, - label: label, - body: body - }; + finishLabeledStatement: function (label, body) { + this.type = Syntax.LabeledStatement; + this.label = label; + this.body = body; + this.finish(); + return this; }, - createLiteral: function (token) { - return { - type: Syntax.Literal, - value: token.value, - raw: source.slice(token.start, token.end) - }; + finishLiteral: function (token) { + this.type = Syntax.Literal; + this.value = token.value; + this.raw = source.slice(token.start, token.end); + if (token.regex) { + this.regex = token.regex; + } + this.finish(); + return this; }, - createMemberExpression: function (accessor, object, property) { - return { - type: Syntax.MemberExpression, - computed: accessor === '[', - object: object, - property: property - }; + finishMemberExpression: function (accessor, object, property) { + this.type = Syntax.MemberExpression; + this.computed = accessor === '['; + this.object = object; + this.property = property; + this.finish(); + return this; }, - createNewExpression: function (callee, args) { - return { - type: Syntax.NewExpression, - callee: callee, - 'arguments': args - }; + finishNewExpression: function (callee, args) { + this.type = Syntax.NewExpression; + this.callee = callee; + this.arguments = args; + this.finish(); + return this; }, - createObjectExpression: function (properties) { - return { - type: Syntax.ObjectExpression, - properties: properties - }; + finishObjectExpression: function (properties) { + this.type = Syntax.ObjectExpression; + this.properties = properties; + this.finish(); + return this; }, - createPostfixExpression: function (operator, argument) { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: false - }; + finishPostfixExpression: function (operator, argument) { + this.type = Syntax.UpdateExpression; + this.operator = operator; + this.argument = argument; + this.prefix = false; + this.finish(); + return this; }, - createProgram: function (body) { - return { - type: Syntax.Program, - body: body - }; + finishProgram: function (body) { + this.type = Syntax.Program; + this.body = body; + this.finish(); + return this; }, - createProperty: function (kind, key, value) { - return { - type: Syntax.Property, - key: key, - value: value, - kind: kind - }; + finishProperty: function (kind, key, value, method, shorthand) { + this.type = Syntax.Property; + this.key = key; + this.value = value; + this.kind = kind; + this.method = method; + this.shorthand = shorthand; + this.finish(); + return this; }, - createReturnStatement: function (argument) { - return { - type: Syntax.ReturnStatement, - argument: argument - }; + finishReturnStatement: function (argument) { + this.type = Syntax.ReturnStatement; + this.argument = argument; + this.finish(); + return this; }, - createSequenceExpression: function (expressions) { - return { - type: Syntax.SequenceExpression, - expressions: expressions - }; + finishSequenceExpression: function (expressions) { + this.type = Syntax.SequenceExpression; + this.expressions = expressions; + this.finish(); + return this; }, - createSwitchCase: function (test, consequent) { - return { - type: Syntax.SwitchCase, - test: test, - consequent: consequent - }; + finishSwitchCase: function (test, consequent) { + this.type = Syntax.SwitchCase; + this.test = test; + this.consequent = consequent; + this.finish(); + return this; }, - createSwitchStatement: function (discriminant, cases) { - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases - }; + finishSwitchStatement: function (discriminant, cases) { + this.type = Syntax.SwitchStatement; + this.discriminant = discriminant; + this.cases = cases; + this.finish(); + return this; }, - createThisExpression: function () { - return { - type: Syntax.ThisExpression - }; + finishThisExpression: function () { + this.type = Syntax.ThisExpression; + this.finish(); + return this; }, - createThrowStatement: function (argument) { - return { - type: Syntax.ThrowStatement, - argument: argument - }; + finishThrowStatement: function (argument) { + this.type = Syntax.ThrowStatement; + this.argument = argument; + this.finish(); + return this; }, - createTryStatement: function (block, guardedHandlers, handlers, finalizer) { - return { - type: Syntax.TryStatement, - block: block, - guardedHandlers: guardedHandlers, - handlers: handlers, - finalizer: finalizer - }; + finishTryStatement: function (block, guardedHandlers, handlers, finalizer) { + this.type = Syntax.TryStatement; + this.block = block; + this.guardedHandlers = guardedHandlers; + this.handlers = handlers; + this.finalizer = finalizer; + this.finish(); + return this; }, - createUnaryExpression: function (operator, argument) { - if (operator === '++' || operator === '--') { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: true - }; - } - return { - type: Syntax.UnaryExpression, - operator: operator, - argument: argument, - prefix: true - }; + finishUnaryExpression: function (operator, argument) { + this.type = (operator === '++' || operator === '--') ? Syntax.UpdateExpression : Syntax.UnaryExpression; + this.operator = operator; + this.argument = argument; + this.prefix = true; + this.finish(); + return this; }, - createVariableDeclaration: function (declarations, kind) { - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: kind - }; + finishVariableDeclaration: function (declarations, kind) { + this.type = Syntax.VariableDeclaration; + this.declarations = declarations; + this.kind = kind; + this.finish(); + return this; }, - createVariableDeclarator: function (id, init) { - return { - type: Syntax.VariableDeclarator, - id: id, - init: init - }; + finishVariableDeclarator: function (id, init) { + this.type = Syntax.VariableDeclarator; + this.id = id; + this.init = init; + this.finish(); + return this; }, - createWhileStatement: function (test, body) { - return { - type: Syntax.WhileStatement, - test: test, - body: body - }; + finishWhileStatement: function (test, body) { + this.type = Syntax.WhileStatement; + this.test = test; + this.body = body; + this.finish(); + return this; }, - createWithStatement: function (object, body) { - return { - type: Syntax.WithStatement, - object: object, - body: body - }; + finishWithStatement: function (object, body) { + this.type = Syntax.WithStatement; + this.object = object; + this.body = body; + this.finish(); + return this; } }; @@ -6357,79 +6569,91 @@ parseStatement: true, parseSourceElement: true */ return found; } + function createError(line, pos, description) { + var error = new Error('Line ' + line + ': ' + description); + error.index = pos; + error.lineNumber = line; + error.column = pos - lineStart + 1; + error.description = description; + return error; + } + // Throw an exception - function throwError(token, messageFormat) { - var error, - args = Array.prototype.slice.call(arguments, 2), - msg = messageFormat.replace( - /%(\d)/g, - function (whole, index) { - assert(index < args.length, 'Message reference must be in range'); - return args[index]; - } - ); + function throwError(messageFormat) { + var args, msg; - if (typeof token.lineNumber === 'number') { - error = new Error('Line ' + token.lineNumber + ': ' + msg); - error.index = token.start; - error.lineNumber = token.lineNumber; - error.column = token.start - lineStart + 1; - } else { - error = new Error('Line ' + lineNumber + ': ' + msg); - error.index = index; - error.lineNumber = lineNumber; - error.column = index - lineStart + 1; - } + args = Array.prototype.slice.call(arguments, 1); + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; + } + ); - error.description = msg; - throw error; + throw createError(lineNumber, index, msg); } - function throwErrorTolerant() { - try { - throwError.apply(null, arguments); - } catch (e) { - if (extra.errors) { - extra.errors.push(e); - } else { - throw e; + function tolerateError(messageFormat) { + var args, msg, error; + + args = Array.prototype.slice.call(arguments, 1); + /* istanbul ignore next */ + msg = messageFormat.replace(/%(\d)/g, + function (whole, idx) { + assert(idx < args.length, 'Message reference must be in range'); + return args[idx]; } + ); + + error = createError(lineNumber, index, msg); + if (extra.errors) { + extra.errors.push(error); + } else { + throw error; } } - // Throw an exception because of the token. - function throwUnexpected(token) { - if (token.type === Token.EOF) { - throwError(token, Messages.UnexpectedEOS); - } + function unexpectedTokenError(token, message) { + var msg = Messages.UnexpectedToken; - if (token.type === Token.NumericLiteral) { - throwError(token, Messages.UnexpectedNumber); - } + if (token) { + msg = message ? message : + (token.type === Token.EOF) ? Messages.UnexpectedEOS : + (token.type === Token.Identifier) ? Messages.UnexpectedIdentifier : + (token.type === Token.NumericLiteral) ? Messages.UnexpectedNumber : + (token.type === Token.StringLiteral) ? Messages.UnexpectedString : + Messages.UnexpectedToken; - if (token.type === Token.StringLiteral) { - throwError(token, Messages.UnexpectedString); + if (token.type === Token.Keyword) { + if (isFutureReservedWord(token.value)) { + msg = Messages.UnexpectedReserved; + } else if (strict && isStrictModeReservedWord(token.value)) { + msg = Messages.StrictReservedWord; + } + } } - if (token.type === Token.Identifier) { - throwError(token, Messages.UnexpectedIdentifier); - } + msg = msg.replace('%0', token ? token.value : 'ILLEGAL'); - if (token.type === Token.Keyword) { - if (isFutureReservedWord(token.value)) { - throwError(token, Messages.UnexpectedReserved); - } else if (strict && isStrictModeReservedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictReservedWord); - return; - } - throwError(token, Messages.UnexpectedToken, token.value); - } + return (token && typeof token.lineNumber === 'number') ? + createError(token.lineNumber, token.start, msg) : + createError(lineNumber, index, msg); + } + + function throwUnexpectedToken(token, message) { + throw unexpectedTokenError(token, message); + } - // BooleanLiteral, NullLiteral, or Punctuator. - throwError(token, Messages.UnexpectedToken, token.value); + function tolerateUnexpectedToken(token, message) { + var error = unexpectedTokenError(token, message); + if (extra.errors) { + extra.errors.push(error); + } else { + throw error; + } } // Expect the next token to match the specified punctuator. @@ -6438,7 +6662,31 @@ parseStatement: true, parseSourceElement: true */ function expect(value) { var token = lex(); if (token.type !== Token.Punctuator || token.value !== value) { - throwUnexpected(token); + throwUnexpectedToken(token); + } + } + + /** + * @name expectCommaSeparator + * @description Quietly expect a comma when in tolerant mode, otherwise delegates + * to expect(value) + * @since 2.0 + */ + function expectCommaSeparator() { + var token; + + if (extra.errors) { + token = lookahead; + if (token.type === Token.Punctuator && token.value === ',') { + lex(); + } else if (token.type === Token.Punctuator && token.value === ';') { + lex(); + tolerateUnexpectedToken(token); + } else { + tolerateUnexpectedToken(token, Messages.UnexpectedToken); + } + } else { + expect(','); } } @@ -6448,7 +6696,7 @@ parseStatement: true, parseSourceElement: true */ function expectKeyword(keyword) { var token = lex(); if (token.type !== Token.Keyword || token.value !== keyword) { - throwUnexpected(token); + throwUnexpectedToken(token); } } @@ -6488,7 +6736,8 @@ parseStatement: true, parseSourceElement: true */ } function consumeSemicolon() { - var line; + var line, oldIndex = index, oldLineNumber = lineNumber, + oldLineStart = lineStart, oldLookahead = lookahead; // Catch the very common case first: immediately a semicolon (U+003B). if (source.charCodeAt(index) === 0x3B || match(';')) { @@ -6499,11 +6748,15 @@ parseStatement: true, parseSourceElement: true */ line = lineNumber; skipComment(); if (lineNumber !== line) { + index = oldIndex; + lineNumber = oldLineNumber; + lineStart = oldLineStart; + lookahead = oldLookahead; return; } if (lookahead.type !== Token.EOF && !match('}')) { - throwUnexpected(lookahead); + throwUnexpectedToken(lookahead); } } @@ -6516,9 +6769,8 @@ parseStatement: true, parseSourceElement: true */ // 11.1.4 Array Initialiser function parseArrayInitialiser() { - var elements = [], startToken; + var elements = [], node = new Node(); - startToken = lookahead; expect('['); while (!match(']')) { @@ -6536,28 +6788,38 @@ parseStatement: true, parseSourceElement: true */ lex(); - return delegate.markEnd(delegate.createArrayExpression(elements), startToken); + return node.finishArrayExpression(elements); } // 11.1.5 Object Initialiser function parsePropertyFunction(param, first) { - var previousStrict, body, startToken; + var previousStrict, body, node = new Node(); previousStrict = strict; - startToken = lookahead; body = parseFunctionSourceElements(); if (first && strict && isRestrictedWord(param[0].name)) { - throwErrorTolerant(first, Messages.StrictParamName); + tolerateUnexpectedToken(first, Messages.StrictParamName); } strict = previousStrict; - return delegate.markEnd(delegate.createFunctionExpression(null, param, [], body), startToken); + return node.finishFunctionExpression(null, param, [], body); + } + + function parsePropertyMethodFunction() { + var previousStrict, param, method; + + previousStrict = strict; + strict = true; + param = parseParams(); + method = parsePropertyFunction(param.params); + strict = previousStrict; + + return method; } function parseObjectPropertyKey() { - var token, startToken; + var token, node = new Node(); - startToken = lookahead; token = lex(); // Note: This function is called only from parseObjectProperty(), where @@ -6565,19 +6827,18 @@ parseStatement: true, parseSourceElement: true */ if (token.type === Token.StringLiteral || token.type === Token.NumericLiteral) { if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(token, Messages.StrictOctalLiteral); } - return delegate.markEnd(delegate.createLiteral(token), startToken); + return node.finishLiteral(token); } - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + return node.finishIdentifier(token.value); } function parseObjectProperty() { - var token, key, id, value, param, startToken; + var token, key, id, value, param, node = new Node(); token = lookahead; - startToken = lookahead; if (token.type === Token.Identifier) { @@ -6585,46 +6846,60 @@ parseStatement: true, parseSourceElement: true */ // Property Assignment: Getter and Setter. - if (token.value === 'get' && !match(':')) { + if (token.value === 'get' && !(match(':') || match('('))) { key = parseObjectPropertyKey(); expect('('); expect(')'); value = parsePropertyFunction([]); - return delegate.markEnd(delegate.createProperty('get', key, value), startToken); + return node.finishProperty('get', key, value, false, false); } - if (token.value === 'set' && !match(':')) { + if (token.value === 'set' && !(match(':') || match('('))) { key = parseObjectPropertyKey(); expect('('); token = lookahead; if (token.type !== Token.Identifier) { expect(')'); - throwErrorTolerant(token, Messages.UnexpectedToken, token.value); + tolerateUnexpectedToken(token); value = parsePropertyFunction([]); } else { param = [ parseVariableIdentifier() ]; expect(')'); value = parsePropertyFunction(param, token); } - return delegate.markEnd(delegate.createProperty('set', key, value), startToken); + return node.finishProperty('set', key, value, false, false); } - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd(delegate.createProperty('init', id, value), startToken); + if (match(':')) { + lex(); + value = parseAssignmentExpression(); + return node.finishProperty('init', id, value, false, false); + } + if (match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', id, value, true, false); + } + + value = id; + return node.finishProperty('init', id, value, false, true); } if (token.type === Token.EOF || token.type === Token.Punctuator) { - throwUnexpected(token); + throwUnexpectedToken(token); } else { key = parseObjectPropertyKey(); - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd(delegate.createProperty('init', key, value), startToken); + if (match(':')) { + lex(); + value = parseAssignmentExpression(); + return node.finishProperty('init', key, value, false, false); + } + if (match('(')) { + value = parsePropertyMethodFunction(); + return node.finishProperty('init', key, value, true, false); + } + throwUnexpectedToken(lex()); } } function parseObjectInitialiser() { - var properties = [], property, name, key, kind, map = {}, toString = String, startToken; - - startToken = lookahead; + var properties = [], property, name, key, kind, map = {}, toString = String, node = new Node(); expect('{'); @@ -6642,15 +6917,15 @@ parseStatement: true, parseSourceElement: true */ if (Object.prototype.hasOwnProperty.call(map, key)) { if (map[key] === PropertyKind.Data) { if (strict && kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.StrictDuplicateProperty); + tolerateError(Messages.StrictDuplicateProperty); } else if (kind !== PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); + tolerateError(Messages.AccessorDataProperty); } } else { if (kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); + tolerateError(Messages.AccessorDataProperty); } else if (map[key] & kind) { - throwErrorTolerant({}, Messages.AccessorGetSet); + tolerateError(Messages.AccessorGetSet); } } map[key] |= kind; @@ -6661,13 +6936,13 @@ parseStatement: true, parseSourceElement: true */ properties.push(property); if (!match('}')) { - expect(','); + expectCommaSeparator(); } } expect('}'); - return delegate.markEnd(delegate.createObjectExpression(properties), startToken); + return node.finishObjectExpression(properties); } // 11.1.6 The Grouping Operator @@ -6677,6 +6952,13 @@ parseStatement: true, parseSourceElement: true */ expect('('); + if (match(')')) { + lex(); + return PlaceHolders.ArrowParameterPlaceHolder; + } + + ++state.parenthesisCount; + expr = parseExpression(); expect(')'); @@ -6688,7 +6970,7 @@ parseStatement: true, parseSourceElement: true */ // 11.1 Primary Expressions function parsePrimaryExpression() { - var type, token, expr, startToken; + var type, token, expr, node; if (match('(')) { return parseGroupExpression(); @@ -6703,45 +6985,45 @@ parseStatement: true, parseSourceElement: true */ } type = lookahead.type; - startToken = lookahead; + node = new Node(); if (type === Token.Identifier) { - expr = delegate.createIdentifier(lex().value); + expr = node.finishIdentifier(lex().value); } else if (type === Token.StringLiteral || type === Token.NumericLiteral) { if (strict && lookahead.octal) { - throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(lookahead, Messages.StrictOctalLiteral); } - expr = delegate.createLiteral(lex()); + expr = node.finishLiteral(lex()); } else if (type === Token.Keyword) { if (matchKeyword('function')) { return parseFunctionExpression(); } if (matchKeyword('this')) { lex(); - expr = delegate.createThisExpression(); + expr = node.finishThisExpression(); } else { - throwUnexpected(lex()); + throwUnexpectedToken(lex()); } } else if (type === Token.BooleanLiteral) { token = lex(); token.value = (token.value === 'true'); - expr = delegate.createLiteral(token); + expr = node.finishLiteral(token); } else if (type === Token.NullLiteral) { token = lex(); token.value = null; - expr = delegate.createLiteral(token); + expr = node.finishLiteral(token); } else if (match('/') || match('/=')) { if (typeof extra.tokens !== 'undefined') { - expr = delegate.createLiteral(collectRegex()); + expr = node.finishLiteral(collectRegex()); } else { - expr = delegate.createLiteral(scanRegExp()); + expr = node.finishLiteral(scanRegExp()); } peek(); } else { - throwUnexpected(lex()); + throwUnexpectedToken(lex()); } - return delegate.markEnd(expr, startToken); + return expr; } // 11.2 Left-Hand-Side Expressions @@ -6757,7 +7039,7 @@ parseStatement: true, parseSourceElement: true */ if (match(')')) { break; } - expect(','); + expectCommaSeparator(); } } @@ -6767,16 +7049,15 @@ parseStatement: true, parseSourceElement: true */ } function parseNonComputedProperty() { - var token, startToken; + var token, node = new Node(); - startToken = lookahead; token = lex(); if (!isIdentifierName(token)) { - throwUnexpected(token); + throwUnexpectedToken(token); } - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + return node.finishIdentifier(token.value); } function parseNonComputedMember() { @@ -6798,65 +7079,60 @@ parseStatement: true, parseSourceElement: true */ } function parseNewExpression() { - var callee, args, startToken; + var callee, args, node = new Node(); - startToken = lookahead; expectKeyword('new'); callee = parseLeftHandSideExpression(); args = match('(') ? parseArguments() : []; - return delegate.markEnd(delegate.createNewExpression(callee, args), startToken); + return node.finishNewExpression(callee, args); } function parseLeftHandSideExpressionAllowCall() { - var previousAllowIn, expr, args, property, startToken; + var expr, args, property, startToken, previousAllowIn = state.allowIn; startToken = lookahead; - - previousAllowIn = state.allowIn; state.allowIn = true; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - state.allowIn = previousAllowIn; for (;;) { if (match('.')) { property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); } else if (match('(')) { args = parseArguments(); - expr = delegate.createCallExpression(expr, args); + expr = new WrappingNode(startToken).finishCallExpression(expr, args); } else if (match('[')) { property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); } else { break; } - delegate.markEnd(expr, startToken); } + state.allowIn = previousAllowIn; return expr; } function parseLeftHandSideExpression() { - var previousAllowIn, expr, property, startToken; + var expr, property, startToken; + assert(state.allowIn, 'callee of new expression always allow in keyword.'); startToken = lookahead; - previousAllowIn = state.allowIn; expr = matchKeyword('new') ? parseNewExpression() : parsePrimaryExpression(); - state.allowIn = previousAllowIn; - while (match('.') || match('[')) { + for (;;) { if (match('[')) { property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); - } else { + expr = new WrappingNode(startToken).finishMemberExpression('[', expr, property); + } else if (match('.')) { property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); + expr = new WrappingNode(startToken).finishMemberExpression('.', expr, property); + } else { + break; } - delegate.markEnd(expr, startToken); } - return expr; } @@ -6871,15 +7147,15 @@ parseStatement: true, parseSourceElement: true */ if ((match('++') || match('--')) && !peekLineTerminator()) { // 11.3.1, 11.3.2 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPostfix); + tolerateError(Messages.StrictLHSPostfix); } if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + tolerateError(Messages.InvalidLHSInAssignment); } token = lex(); - expr = delegate.markEnd(delegate.createPostfixExpression(token.value, expr), startToken); + expr = new WrappingNode(startToken).finishPostfixExpression(token.value, expr); } } @@ -6899,29 +7175,26 @@ parseStatement: true, parseSourceElement: true */ expr = parseUnaryExpression(); // 11.4.4, 11.4.5 if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { - throwErrorTolerant({}, Messages.StrictLHSPrefix); + tolerateError(Messages.StrictLHSPrefix); } if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + tolerateError(Messages.InvalidLHSInAssignment); } - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); } else if (match('+') || match('-') || match('~') || match('!')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); } else if (matchKeyword('delete') || matchKeyword('void') || matchKeyword('typeof')) { startToken = lookahead; token = lex(); expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishUnaryExpression(token.value, expr); if (strict && expr.operator === 'delete' && expr.argument.type === Syntax.Identifier) { - throwErrorTolerant({}, Messages.StrictDelete); + tolerateError(Messages.StrictDelete); } } else { expr = parsePostfixExpression(); @@ -7014,6 +7287,9 @@ parseStatement: true, parseSourceElement: true */ marker = lookahead; left = parseUnaryExpression(); + if (left === PlaceHolders.ArrowParameterPlaceHolder) { + return left; + } token = lookahead; prec = binaryPrecedence(token, state.allowIn); @@ -7035,10 +7311,8 @@ parseStatement: true, parseSourceElement: true */ right = stack.pop(); operator = stack.pop().value; left = stack.pop(); - expr = delegate.createBinaryExpression(operator, left, right); markers.pop(); - marker = markers[markers.length - 1]; - delegate.markEnd(expr, marker); + expr = new WrappingNode(markers[markers.length - 1]).finishBinaryExpression(operator, left, right); stack.push(expr); } @@ -7056,10 +7330,8 @@ parseStatement: true, parseSourceElement: true */ expr = stack[i]; markers.pop(); while (i > 1) { - expr = delegate.createBinaryExpression(stack[i - 1].value, stack[i - 2], expr); + expr = new WrappingNode(markers.pop()).finishBinaryExpression(stack[i - 1].value, stack[i - 2], expr); i -= 2; - marker = markers.pop(); - delegate.markEnd(expr, marker); } return expr; @@ -7074,7 +7346,9 @@ parseStatement: true, parseSourceElement: true */ startToken = lookahead; expr = parseBinaryExpression(); - + if (expr === PlaceHolders.ArrowParameterPlaceHolder) { + return expr; + } if (match('?')) { lex(); previousAllowIn = state.allowIn; @@ -7084,61 +7358,155 @@ parseStatement: true, parseSourceElement: true */ expect(':'); alternate = parseAssignmentExpression(); - expr = delegate.createConditionalExpression(expr, consequent, alternate); - delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishConditionalExpression(expr, consequent, alternate); } return expr; } + // [ES6] 14.2 Arrow Function + + function parseConciseBody() { + if (match('{')) { + return parseFunctionSourceElements(); + } + return parseAssignmentExpression(); + } + + function reinterpretAsCoverFormalsList(expressions) { + var i, len, param, params, defaults, defaultCount, options, rest, token; + + params = []; + defaults = []; + defaultCount = 0; + rest = null; + options = { + paramSet: {} + }; + + for (i = 0, len = expressions.length; i < len; i += 1) { + param = expressions[i]; + if (param.type === Syntax.Identifier) { + params.push(param); + defaults.push(null); + validateParam(options, param, param.name); + } else if (param.type === Syntax.AssignmentExpression) { + params.push(param.left); + defaults.push(param.right); + ++defaultCount; + validateParam(options, param.left, param.left.name); + } else { + return null; + } + } + + if (options.message === Messages.StrictParamDupe) { + token = strict ? options.stricted : options.firstRestricted; + throwUnexpectedToken(token, options.message); + } + + if (defaultCount === 0) { + defaults = []; + } + + return { + params: params, + defaults: defaults, + rest: rest, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message + }; + } + + function parseArrowFunctionExpression(options, node) { + var previousStrict, body; + + expect('=>'); + previousStrict = strict; + + body = parseConciseBody(); + + if (strict && options.firstRestricted) { + throwUnexpectedToken(options.firstRestricted, options.message); + } + if (strict && options.stricted) { + tolerateUnexpectedToken(options.stricted, options.message); + } + + strict = previousStrict; + + return node.finishArrowFunctionExpression(options.params, options.defaults, body, body.type !== Syntax.BlockStatement); + } + // 11.13 Assignment Operators function parseAssignmentExpression() { - var token, left, right, node, startToken; + var oldParenthesisCount, token, expr, right, list, startToken; + + oldParenthesisCount = state.parenthesisCount; - token = lookahead; startToken = lookahead; + token = lookahead; - node = left = parseConditionalExpression(); + expr = parseConditionalExpression(); + + if (expr === PlaceHolders.ArrowParameterPlaceHolder || match('=>')) { + if (state.parenthesisCount === oldParenthesisCount || + state.parenthesisCount === (oldParenthesisCount + 1)) { + if (expr.type === Syntax.Identifier) { + list = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.AssignmentExpression) { + list = reinterpretAsCoverFormalsList([ expr ]); + } else if (expr.type === Syntax.SequenceExpression) { + list = reinterpretAsCoverFormalsList(expr.expressions); + } else if (expr === PlaceHolders.ArrowParameterPlaceHolder) { + list = reinterpretAsCoverFormalsList([]); + } + if (list) { + return parseArrowFunctionExpression(list, new WrappingNode(startToken)); + } + } + } if (matchAssign()) { // LeftHandSideExpression - if (!isLeftHandSide(left)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); + if (!isLeftHandSide(expr)) { + tolerateError(Messages.InvalidLHSInAssignment); } // 11.13.1 - if (strict && left.type === Syntax.Identifier && isRestrictedWord(left.name)) { - throwErrorTolerant(token, Messages.StrictLHSAssignment); + if (strict && expr.type === Syntax.Identifier && isRestrictedWord(expr.name)) { + tolerateUnexpectedToken(token, Messages.StrictLHSAssignment); } token = lex(); right = parseAssignmentExpression(); - node = delegate.markEnd(delegate.createAssignmentExpression(token.value, left, right), startToken); + expr = new WrappingNode(startToken).finishAssignmentExpression(token.value, expr, right); } - return node; + return expr; } // 11.14 Comma Operator function parseExpression() { - var expr, startToken = lookahead; + var expr, startToken = lookahead, expressions; expr = parseAssignmentExpression(); if (match(',')) { - expr = delegate.createSequenceExpression([ expr ]); + expressions = [expr]; while (index < length) { if (!match(',')) { break; } lex(); - expr.expressions.push(parseAssignmentExpression()); + expressions.push(parseAssignmentExpression()); } - delegate.markEnd(expr, startToken); + expr = new WrappingNode(startToken).finishSequenceExpression(expressions); } return expr; @@ -7165,42 +7533,43 @@ parseStatement: true, parseSourceElement: true */ } function parseBlock() { - var block, startToken; + var block, node = new Node(); - startToken = lookahead; expect('{'); block = parseStatementList(); expect('}'); - return delegate.markEnd(delegate.createBlockStatement(block), startToken); + return node.finishBlockStatement(block); } // 12.2 Variable Statement function parseVariableIdentifier() { - var token, startToken; + var token, node = new Node(); - startToken = lookahead; token = lex(); if (token.type !== Token.Identifier) { - throwUnexpected(token); + if (strict && token.type === Token.Keyword && isStrictModeReservedWord(token.value)) { + tolerateUnexpectedToken(token, Messages.StrictReservedWord); + } else { + throwUnexpectedToken(token); + } } - return delegate.markEnd(delegate.createIdentifier(token.value), startToken); + return node.finishIdentifier(token.value); } function parseVariableDeclaration(kind) { - var init = null, id, startToken; + var init = null, id, node = new Node(); - startToken = lookahead; id = parseVariableIdentifier(); // 12.2.1 if (strict && isRestrictedWord(id.name)) { - throwErrorTolerant({}, Messages.StrictVarName); + tolerateError(Messages.StrictVarName); } if (kind === 'const') { @@ -7211,7 +7580,7 @@ parseStatement: true, parseSourceElement: true */ init = parseAssignmentExpression(); } - return delegate.markEnd(delegate.createVariableDeclarator(id, init), startToken); + return node.finishVariableDeclarator(id, init); } function parseVariableDeclarationList(kind) { @@ -7228,7 +7597,7 @@ parseStatement: true, parseSourceElement: true */ return list; } - function parseVariableStatement() { + function parseVariableStatement(node) { var declarations; expectKeyword('var'); @@ -7237,7 +7606,7 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return delegate.createVariableDeclaration(declarations, 'var'); + return node.finishVariableDeclaration(declarations, 'var'); } // kind may be `const` or `let` @@ -7245,9 +7614,7 @@ parseStatement: true, parseSourceElement: true */ // see http://wiki.ecmascript.org/doku.php?id=harmony:const // and http://wiki.ecmascript.org/doku.php?id=harmony:let function parseConstLetDeclaration(kind) { - var declarations, startToken; - - startToken = lookahead; + var declarations, node = new Node(); expectKeyword(kind); @@ -7255,27 +7622,28 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return delegate.markEnd(delegate.createVariableDeclaration(declarations, kind), startToken); + return node.finishVariableDeclaration(declarations, kind); } // 12.3 Empty Statement function parseEmptyStatement() { + var node = new Node(); expect(';'); - return delegate.createEmptyStatement(); + return node.finishEmptyStatement(); } // 12.4 Expression Statement - function parseExpressionStatement() { + function parseExpressionStatement(node) { var expr = parseExpression(); consumeSemicolon(); - return delegate.createExpressionStatement(expr); + return node.finishExpressionStatement(expr); } // 12.5 If statement - function parseIfStatement() { + function parseIfStatement(node) { var test, consequent, alternate; expectKeyword('if'); @@ -7295,12 +7663,12 @@ parseStatement: true, parseSourceElement: true */ alternate = null; } - return delegate.createIfStatement(test, consequent, alternate); + return node.finishIfStatement(test, consequent, alternate); } // 12.6 Iteration Statements - function parseDoWhileStatement() { + function parseDoWhileStatement(node) { var body, test, oldInIteration; expectKeyword('do'); @@ -7324,10 +7692,10 @@ parseStatement: true, parseSourceElement: true */ lex(); } - return delegate.createDoWhileStatement(body, test); + return node.finishDoWhileStatement(body, test); } - function parseWhileStatement() { + function parseWhileStatement(node) { var test, body, oldInIteration; expectKeyword('while'); @@ -7345,21 +7713,20 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; - return delegate.createWhileStatement(test, body); + return node.finishWhileStatement(test, body); } function parseForVariableDeclaration() { - var token, declarations, startToken; + var token, declarations, node = new Node(); - startToken = lookahead; token = lex(); declarations = parseVariableDeclarationList(); - return delegate.markEnd(delegate.createVariableDeclaration(declarations, token.value), startToken); + return node.finishVariableDeclaration(declarations, token.value); } - function parseForStatement() { - var init, test, update, left, right, body, oldInIteration; + function parseForStatement(node) { + var init, test, update, left, right, body, oldInIteration, previousAllowIn = state.allowIn; init = test = update = null; @@ -7373,7 +7740,7 @@ parseStatement: true, parseSourceElement: true */ if (matchKeyword('var') || matchKeyword('let')) { state.allowIn = false; init = parseForVariableDeclaration(); - state.allowIn = true; + state.allowIn = previousAllowIn; if (init.declarations.length === 1 && matchKeyword('in')) { lex(); @@ -7384,12 +7751,12 @@ parseStatement: true, parseSourceElement: true */ } else { state.allowIn = false; init = parseExpression(); - state.allowIn = true; + state.allowIn = previousAllowIn; if (matchKeyword('in')) { // LeftHandSideExpression if (!isLeftHandSide(init)) { - throwErrorTolerant({}, Messages.InvalidLHSInForIn); + tolerateError(Messages.InvalidLHSInForIn); } lex(); @@ -7426,13 +7793,13 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; return (typeof left === 'undefined') ? - delegate.createForStatement(init, test, update, body) : - delegate.createForInStatement(left, right, body); + node.finishForStatement(init, test, update, body) : + node.finishForInStatement(left, right, body); } // 12.7 The continue statement - function parseContinueStatement() { + function parseContinueStatement(node) { var label = null, key; expectKeyword('continue'); @@ -7442,18 +7809,18 @@ parseStatement: true, parseSourceElement: true */ lex(); if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); + throwError(Messages.IllegalContinue); } - return delegate.createContinueStatement(null); + return node.finishContinueStatement(null); } if (peekLineTerminator()) { if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); + throwError(Messages.IllegalContinue); } - return delegate.createContinueStatement(null); + return node.finishContinueStatement(null); } if (lookahead.type === Token.Identifier) { @@ -7461,22 +7828,22 @@ parseStatement: true, parseSourceElement: true */ key = '$' + label.name; if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); + throwError(Messages.UnknownLabel, label.name); } } consumeSemicolon(); if (label === null && !state.inIteration) { - throwError({}, Messages.IllegalContinue); + throwError(Messages.IllegalContinue); } - return delegate.createContinueStatement(label); + return node.finishContinueStatement(label); } // 12.8 The break statement - function parseBreakStatement() { + function parseBreakStatement(node) { var label = null, key; expectKeyword('break'); @@ -7486,18 +7853,18 @@ parseStatement: true, parseSourceElement: true */ lex(); if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); + throwError(Messages.IllegalBreak); } - return delegate.createBreakStatement(null); + return node.finishBreakStatement(null); } if (peekLineTerminator()) { if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); + throwError(Messages.IllegalBreak); } - return delegate.createBreakStatement(null); + return node.finishBreakStatement(null); } if (lookahead.type === Token.Identifier) { @@ -7505,28 +7872,28 @@ parseStatement: true, parseSourceElement: true */ key = '$' + label.name; if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); + throwError(Messages.UnknownLabel, label.name); } } consumeSemicolon(); if (label === null && !(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); + throwError(Messages.IllegalBreak); } - return delegate.createBreakStatement(label); + return node.finishBreakStatement(label); } // 12.9 The return statement - function parseReturnStatement() { + function parseReturnStatement(node) { var argument = null; expectKeyword('return'); if (!state.inFunctionBody) { - throwErrorTolerant({}, Messages.IllegalReturn); + tolerateError(Messages.IllegalReturn); } // 'return' followed by a space and an identifier is very common. @@ -7534,12 +7901,12 @@ parseStatement: true, parseSourceElement: true */ if (isIdentifierStart(source.charCodeAt(index + 1))) { argument = parseExpression(); consumeSemicolon(); - return delegate.createReturnStatement(argument); + return node.finishReturnStatement(argument); } } if (peekLineTerminator()) { - return delegate.createReturnStatement(null); + return node.finishReturnStatement(null); } if (!match(';')) { @@ -7550,18 +7917,18 @@ parseStatement: true, parseSourceElement: true */ consumeSemicolon(); - return delegate.createReturnStatement(argument); + return node.finishReturnStatement(argument); } // 12.10 The with statement - function parseWithStatement() { + function parseWithStatement(node) { var object, body; if (strict) { // TODO(ikarienator): Should we update the test cases instead? skipComment(); - throwErrorTolerant({}, Messages.StrictModeWith); + tolerateError(Messages.StrictModeWith); } expectKeyword('with'); @@ -7574,15 +7941,14 @@ parseStatement: true, parseSourceElement: true */ body = parseStatement(); - return delegate.createWithStatement(object, body); + return node.finishWithStatement(object, body); } // 12.10 The swith statement function parseSwitchCase() { - var test, consequent = [], statement, startToken; + var test, consequent = [], statement, node = new Node(); - startToken = lookahead; if (matchKeyword('default')) { lex(); test = null; @@ -7600,10 +7966,10 @@ parseStatement: true, parseSourceElement: true */ consequent.push(statement); } - return delegate.markEnd(delegate.createSwitchCase(test, consequent), startToken); + return node.finishSwitchCase(test, consequent); } - function parseSwitchStatement() { + function parseSwitchStatement(node) { var discriminant, cases, clause, oldInSwitch, defaultFound; expectKeyword('switch'); @@ -7620,7 +7986,7 @@ parseStatement: true, parseSourceElement: true */ if (match('}')) { lex(); - return delegate.createSwitchStatement(discriminant, cases); + return node.finishSwitchStatement(discriminant, cases); } oldInSwitch = state.inSwitch; @@ -7634,7 +8000,7 @@ parseStatement: true, parseSourceElement: true */ clause = parseSwitchCase(); if (clause.test === null) { if (defaultFound) { - throwError({}, Messages.MultipleDefaultsInSwitch); + throwError(Messages.MultipleDefaultsInSwitch); } defaultFound = true; } @@ -7645,52 +8011,51 @@ parseStatement: true, parseSourceElement: true */ expect('}'); - return delegate.createSwitchStatement(discriminant, cases); + return node.finishSwitchStatement(discriminant, cases); } // 12.13 The throw statement - function parseThrowStatement() { + function parseThrowStatement(node) { var argument; expectKeyword('throw'); if (peekLineTerminator()) { - throwError({}, Messages.NewlineAfterThrow); + throwError(Messages.NewlineAfterThrow); } argument = parseExpression(); consumeSemicolon(); - return delegate.createThrowStatement(argument); + return node.finishThrowStatement(argument); } // 12.14 The try statement function parseCatchClause() { - var param, body, startToken; + var param, body, node = new Node(); - startToken = lookahead; expectKeyword('catch'); expect('('); if (match(')')) { - throwUnexpected(lookahead); + throwUnexpectedToken(lookahead); } param = parseVariableIdentifier(); // 12.14.1 if (strict && isRestrictedWord(param.name)) { - throwErrorTolerant({}, Messages.StrictCatchVariable); + tolerateError(Messages.StrictCatchVariable); } expect(')'); body = parseBlock(); - return delegate.markEnd(delegate.createCatchClause(param, body), startToken); + return node.finishCatchClause(param, body); } - function parseTryStatement() { + function parseTryStatement(node) { var block, handlers = [], finalizer = null; expectKeyword('try'); @@ -7707,20 +8072,20 @@ parseStatement: true, parseSourceElement: true */ } if (handlers.length === 0 && !finalizer) { - throwError({}, Messages.NoCatchOrFinally); + throwError(Messages.NoCatchOrFinally); } - return delegate.createTryStatement(block, [], handlers, finalizer); + return node.finishTryStatement(block, [], handlers, finalizer); } // 12.15 The debugger statement - function parseDebuggerStatement() { + function parseDebuggerStatement(node) { expectKeyword('debugger'); consumeSemicolon(); - return delegate.createDebuggerStatement(); + return node.finishDebuggerStatement(); } // 12 Statements @@ -7730,59 +8095,57 @@ parseStatement: true, parseSourceElement: true */ expr, labeledBody, key, - startToken; + node; if (type === Token.EOF) { - throwUnexpected(lookahead); + throwUnexpectedToken(lookahead); } if (type === Token.Punctuator && lookahead.value === '{') { return parseBlock(); } - startToken = lookahead; + node = new Node(); if (type === Token.Punctuator) { switch (lookahead.value) { case ';': - return delegate.markEnd(parseEmptyStatement(), startToken); + return parseEmptyStatement(node); case '(': - return delegate.markEnd(parseExpressionStatement(), startToken); + return parseExpressionStatement(node); default: break; } - } - - if (type === Token.Keyword) { + } else if (type === Token.Keyword) { switch (lookahead.value) { case 'break': - return delegate.markEnd(parseBreakStatement(), startToken); + return parseBreakStatement(node); case 'continue': - return delegate.markEnd(parseContinueStatement(), startToken); + return parseContinueStatement(node); case 'debugger': - return delegate.markEnd(parseDebuggerStatement(), startToken); + return parseDebuggerStatement(node); case 'do': - return delegate.markEnd(parseDoWhileStatement(), startToken); + return parseDoWhileStatement(node); case 'for': - return delegate.markEnd(parseForStatement(), startToken); + return parseForStatement(node); case 'function': - return delegate.markEnd(parseFunctionDeclaration(), startToken); + return parseFunctionDeclaration(node); case 'if': - return delegate.markEnd(parseIfStatement(), startToken); + return parseIfStatement(node); case 'return': - return delegate.markEnd(parseReturnStatement(), startToken); + return parseReturnStatement(node); case 'switch': - return delegate.markEnd(parseSwitchStatement(), startToken); + return parseSwitchStatement(node); case 'throw': - return delegate.markEnd(parseThrowStatement(), startToken); + return parseThrowStatement(node); case 'try': - return delegate.markEnd(parseTryStatement(), startToken); + return parseTryStatement(node); case 'var': - return delegate.markEnd(parseVariableStatement(), startToken); + return parseVariableStatement(node); case 'while': - return delegate.markEnd(parseWhileStatement(), startToken); + return parseWhileStatement(node); case 'with': - return delegate.markEnd(parseWithStatement(), startToken); + return parseWithStatement(node); default: break; } @@ -7796,27 +8159,27 @@ parseStatement: true, parseSourceElement: true */ key = '$' + expr.name; if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.Redeclaration, 'Label', expr.name); + throwError(Messages.Redeclaration, 'Label', expr.name); } state.labelSet[key] = true; labeledBody = parseStatement(); delete state.labelSet[key]; - return delegate.markEnd(delegate.createLabeledStatement(expr, labeledBody), startToken); + return node.finishLabeledStatement(expr, labeledBody); } consumeSemicolon(); - return delegate.markEnd(delegate.createExpressionStatement(expr), startToken); + return node.finishExpressionStatement(expr); } // 13 Function Definition function parseFunctionSourceElements() { var sourceElement, sourceElements = [], token, directive, firstRestricted, - oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, startToken; + oldLabelSet, oldInIteration, oldInSwitch, oldInFunctionBody, oldParenthesisCount, + node = new Node(); - startToken = lookahead; expect('{'); while (index < length) { @@ -7835,7 +8198,7 @@ parseStatement: true, parseSourceElement: true */ if (directive === 'use strict') { strict = true; if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); } } else { if (!firstRestricted && token.octal) { @@ -7848,11 +8211,13 @@ parseStatement: true, parseSourceElement: true */ oldInIteration = state.inIteration; oldInSwitch = state.inSwitch; oldInFunctionBody = state.inFunctionBody; + oldParenthesisCount = state.parenthesizedCount; state.labelSet = {}; state.inIteration = false; state.inSwitch = false; state.inFunctionBody = true; + state.parenthesizedCount = 0; while (index < length) { if (match('}')) { @@ -7871,44 +8236,71 @@ parseStatement: true, parseSourceElement: true */ state.inIteration = oldInIteration; state.inSwitch = oldInSwitch; state.inFunctionBody = oldInFunctionBody; + state.parenthesizedCount = oldParenthesisCount; + + return node.finishBlockStatement(sourceElements); + } + + function validateParam(options, param, name) { + var key = '$' + name; + if (strict) { + if (isRestrictedWord(name)) { + options.stricted = param; + options.message = Messages.StrictParamName; + } + if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.stricted = param; + options.message = Messages.StrictParamDupe; + } + } else if (!options.firstRestricted) { + if (isRestrictedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictParamName; + } else if (isStrictModeReservedWord(name)) { + options.firstRestricted = param; + options.message = Messages.StrictReservedWord; + } else if (Object.prototype.hasOwnProperty.call(options.paramSet, key)) { + options.firstRestricted = param; + options.message = Messages.StrictParamDupe; + } + } + options.paramSet[key] = true; + } + + function parseParam(options) { + var token, param, def; + + token = lookahead; + param = parseVariableIdentifier(); + validateParam(options, token, token.value); + if (match('=')) { + lex(); + def = parseAssignmentExpression(); + ++options.defaultCount; + } + + options.params.push(param); + options.defaults.push(def); - return delegate.markEnd(delegate.createBlockStatement(sourceElements), startToken); + return !match(')'); } function parseParams(firstRestricted) { - var param, params = [], token, stricted, paramSet, key, message; + var options; + + options = { + params: [], + defaultCount: 0, + defaults: [], + firstRestricted: firstRestricted + }; + expect('('); if (!match(')')) { - paramSet = {}; + options.paramSet = {}; while (index < length) { - token = lookahead; - param = parseVariableIdentifier(); - key = '$' + token.value; - if (strict) { - if (isRestrictedWord(token.value)) { - stricted = token; - message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - stricted = token; - message = Messages.StrictParamDupe; - } - } else if (!firstRestricted) { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - firstRestricted = token; - message = Messages.StrictParamDupe; - } - } - params.push(param); - paramSet[key] = true; - if (match(')')) { + if (!parseParam(options)) { break; } expect(','); @@ -7917,25 +8309,28 @@ parseStatement: true, parseSourceElement: true */ expect(')'); + if (options.defaultCount === 0) { + options.defaults = []; + } + return { - params: params, - stricted: stricted, - firstRestricted: firstRestricted, - message: message + params: options.params, + defaults: options.defaults, + stricted: options.stricted, + firstRestricted: options.firstRestricted, + message: options.message }; } function parseFunctionDeclaration() { - var id, params = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, startToken; - - startToken = lookahead; + var id, params = [], defaults = [], body, token, stricted, tmp, firstRestricted, message, previousStrict, node = new Node(); expectKeyword('function'); token = lookahead; id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); + tolerateUnexpectedToken(token, Messages.StrictFunctionName); } } else { if (isRestrictedWord(token.value)) { @@ -7949,6 +8344,7 @@ parseStatement: true, parseSourceElement: true */ tmp = parseParams(firstRestricted); params = tmp.params; + defaults = tmp.defaults; stricted = tmp.stricted; firstRestricted = tmp.firstRestricted; if (tmp.message) { @@ -7958,20 +8354,20 @@ parseStatement: true, parseSourceElement: true */ previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { - throwError(firstRestricted, message); + throwUnexpectedToken(firstRestricted, message); } if (strict && stricted) { - throwErrorTolerant(stricted, message); + tolerateUnexpectedToken(stricted, message); } strict = previousStrict; - return delegate.markEnd(delegate.createFunctionDeclaration(id, params, [], body), startToken); + return node.finishFunctionDeclaration(id, params, defaults, body); } function parseFunctionExpression() { - var token, id = null, stricted, firstRestricted, message, tmp, params = [], body, previousStrict, startToken; + var token, id = null, stricted, firstRestricted, message, tmp, + params = [], defaults = [], body, previousStrict, node = new Node(); - startToken = lookahead; expectKeyword('function'); if (!match('(')) { @@ -7979,7 +8375,7 @@ parseStatement: true, parseSourceElement: true */ id = parseVariableIdentifier(); if (strict) { if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); + tolerateUnexpectedToken(token, Messages.StrictFunctionName); } } else { if (isRestrictedWord(token.value)) { @@ -7994,6 +8390,7 @@ parseStatement: true, parseSourceElement: true */ tmp = parseParams(firstRestricted); params = tmp.params; + defaults = tmp.defaults; stricted = tmp.stricted; firstRestricted = tmp.firstRestricted; if (tmp.message) { @@ -8003,14 +8400,14 @@ parseStatement: true, parseSourceElement: true */ previousStrict = strict; body = parseFunctionSourceElements(); if (strict && firstRestricted) { - throwError(firstRestricted, message); + throwUnexpectedToken(firstRestricted, message); } if (strict && stricted) { - throwErrorTolerant(stricted, message); + tolerateUnexpectedToken(stricted, message); } strict = previousStrict; - return delegate.markEnd(delegate.createFunctionExpression(id, params, [], body), startToken); + return node.finishFunctionExpression(id, params, defaults, body); } // 14 Program @@ -8052,7 +8449,7 @@ parseStatement: true, parseSourceElement: true */ if (directive === 'use strict') { strict = true; if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); + tolerateUnexpectedToken(firstRestricted, Messages.StrictOctalLiteral); } } else { if (!firstRestricted && token.octal) { @@ -8073,15 +8470,15 @@ parseStatement: true, parseSourceElement: true */ } function parseProgram() { - var body, startToken; + var body, node; skipComment(); peek(); - startToken = lookahead; + node = new Node(); strict = false; body = parseSourceElements(); - return delegate.markEnd(delegate.createProgram(body), startToken); + return node.finishProgram(body); } function filterTokenLocation() { @@ -8093,6 +8490,12 @@ parseStatement: true, parseSourceElement: true */ type: entry.type, value: entry.value }; + if (entry.regex) { + token.regex = { + pattern: entry.regex.pattern, + flags: entry.regex.flags + }; + } if (extra.range) { token.range = entry.range; } @@ -8107,7 +8510,6 @@ parseStatement: true, parseSourceElement: true */ function tokenize(code, options) { var toString, - token, tokens; toString = String; @@ -8115,7 +8517,6 @@ parseStatement: true, parseSourceElement: true */ code = toString(code); } - delegate = SyntaxTreeDelegate; source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; @@ -8160,12 +8561,11 @@ parseStatement: true, parseSourceElement: true */ return extra.tokens; } - token = lex(); + lex(); while (lookahead.type !== Token.EOF) { try { - token = lex(); + lex(); } catch (lexError) { - token = lookahead; if (extra.errors) { extra.errors.push(lexError); // We have to break on the first error @@ -8201,7 +8601,6 @@ parseStatement: true, parseSourceElement: true */ code = toString(code); } - delegate = SyntaxTreeDelegate; source = code; index = 0; lineNumber = (source.length > 0) ? 1 : 0; @@ -8211,6 +8610,7 @@ parseStatement: true, parseSourceElement: true */ state = { allowIn: true, labelSet: {}, + parenthesisCount: 0, inFunctionBody: false, inIteration: false, inSwitch: false, @@ -8267,7 +8667,7 @@ parseStatement: true, parseSourceElement: true */ } // Sync with *.json manifests. - exports.version = '1.2.2'; + exports.version = '2.0.0'; exports.tokenize = tokenize; From dbaacf6344aedec11f76181c062b303d1bd6b2b6 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sat, 7 Feb 2015 11:36:13 -0800 Subject: [PATCH 215/382] snapshot --- dist/r.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/r.js b/dist/r.js index fa456af7..f9fb7371 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15+ Sat, 07 Feb 2015 19:28:10 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Sat, 07 Feb 2015 19:35:38 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15+ Sat, 07 Feb 2015 19:28:10 GMT', + version = '2.1.15+ Sat, 07 Feb 2015 19:35:38 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -27924,7 +27924,7 @@ define('build', function (require) { } //Write the built module to disk, and build up the build output. - fileContents = ""; + fileContents = config.wrap ? config.wrap.start : ""; return prim.serial(layer.buildFilePaths.map(function (path) { return function () { var lineCount, @@ -28163,7 +28163,7 @@ define('build', function (require) { }).then(function () { return { text: config.wrap ? - config.wrap.start + fileContents + config.wrap.end : + fileContents + config.wrap.end : fileContents, buildText: buildFileContents, sourceMap: sourceMapGenerator ? From 8ed31fe58c98fedc900bf8ac5abcb961a9432c20 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 8 Feb 2015 13:42:19 -0800 Subject: [PATCH 216/382] Fixes #709, update to uglifyjs 2.4.16 --- .../jslib/source-map/source-map-generator.js | 3 + build/jslib/source-map/source-node.js | 37 +- build/jslib/uglifyjs2.js | 477 ++++++++++++++---- build/jslib/uglifyjs2/README.md | 2 +- build/jslib/x.js | 2 +- .../tests/lib/sourcemap/expected-main.js.map | 2 +- build/tests/lib/sourcemap/onejs/expected.map | 2 +- .../expected-main-built.js.map | 2 +- build/tests/lib/sourcemapSingle/main-built.js | 1 + .../lib/sourcemapSingle/main-built.js.map | 2 +- 10 files changed, 416 insertions(+), 114 deletions(-) diff --git a/build/jslib/source-map/source-map-generator.js b/build/jslib/source-map/source-map-generator.js index f0a315be..4b240c30 100644 --- a/build/jslib/source-map/source-map-generator.js +++ b/build/jslib/source-map/source-map-generator.js @@ -227,6 +227,9 @@ define(function (require, exports, module) { aSourceMapConsumer.sources.forEach(function (sourceFile) { var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content) { + if (aSourceMapPath) { + sourceFile = util.join(aSourceMapPath, sourceFile); + } if (sourceRoot) { sourceFile = util.relative(sourceRoot, sourceFile); } diff --git a/build/jslib/source-map/source-node.js b/build/jslib/source-map/source-node.js index b206c342..681e7ab3 100644 --- a/build/jslib/source-map/source-node.js +++ b/build/jslib/source-map/source-node.js @@ -10,6 +10,13 @@ define(function (require, exports, module) { var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; var util = require('./util'); + // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other + // operating systems these days (capturing the result). + var REGEX_NEWLINE = /(\r?\n)/g; + + // Matches a Windows-style newline, or any character. + var REGEX_CHARACTER = /\r\n|[\s\S]/g; + /** * SourceNodes provide a way to abstract over interpolating/concatenating * snippets of generated JavaScript source code while maintaining the line and @@ -44,9 +51,17 @@ define(function (require, exports, module) { // and the SourceMap var node = new SourceNode(); - // The generated code - // Processed fragments are removed from this array. - var remainingLines = aGeneratedCode.split('\n'); + // All even indices of this array are one line of the generated code, + // while all odd indices are the newlines between two adjacent lines + // (since `REGEX_NEWLINE` captures its match). + // Processed fragments are removed from this array, by calling `shiftNextLine`. + var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); + var shiftNextLine = function() { + var lineContents = remainingLines.shift(); + // The last line of a file might not have a newline. + var newLine = remainingLines.shift() || ""; + return lineContents + newLine; + }; // We need to remember the position of "remainingLines" var lastGeneratedLine = 1, lastGeneratedColumn = 0; @@ -63,7 +78,7 @@ define(function (require, exports, module) { if (lastGeneratedLine < mapping.generatedLine) { var code = ""; // Associate first line with "lastMapping" - addMappingWithCode(lastMapping, remainingLines.shift() + "\n"); + addMappingWithCode(lastMapping, shiftNextLine()); lastGeneratedLine++; lastGeneratedColumn = 0; // The remaining code is added without mapping @@ -87,7 +102,7 @@ define(function (require, exports, module) { // to the SourceNode without any mapping. // Each line is added as separate string. while (lastGeneratedLine < mapping.generatedLine) { - node.add(remainingLines.shift() + "\n"); + node.add(shiftNextLine()); lastGeneratedLine++; } if (lastGeneratedColumn < mapping.generatedColumn) { @@ -102,12 +117,10 @@ define(function (require, exports, module) { if (remainingLines.length > 0) { if (lastMapping) { // Associate the remaining code in the current line with "lastMapping" - var lastLine = remainingLines.shift(); - if (remainingLines.length > 0) lastLine += "\n"; - addMappingWithCode(lastMapping, lastLine); + addMappingWithCode(lastMapping, shiftNextLine()); } // and add the remaining lines without any mapping - node.add(remainingLines.join("\n")); + node.add(remainingLines.join("")); } // Copy sourcesContent into SourceNode @@ -346,8 +359,8 @@ define(function (require, exports, module) { lastOriginalSource = null; sourceMappingActive = false; } - chunk.split('').forEach(function (ch, idx, array) { - if (ch === '\n') { + chunk.match(REGEX_CHARACTER).forEach(function (ch, idx, array) { + if (REGEX_NEWLINE.test(ch)) { generated.line++; generated.column = 0; // Mappings end at eol @@ -369,7 +382,7 @@ define(function (require, exports, module) { }); } } else { - generated.column++; + generated.column += ch.length; } }); }); diff --git a/build/jslib/uglifyjs2.js b/build/jslib/uglifyjs2.js index e11de335..c7751be1 100644 --- a/build/jslib/uglifyjs2.js +++ b/build/jslib/uglifyjs2.js @@ -602,10 +602,10 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", { var parameters = []; arg_parameter_pairs.forEach(function(pair) { - var split = pair.split(":"); + var splitAt = pair.lastIndexOf(":"); - args.push(split[0]); - parameters.push(split[1]); + args.push(pair.substr(0, splitAt)); + parameters.push(pair.substr(splitAt + 1)); }); var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; @@ -1460,14 +1460,7 @@ function is_identifier_char(ch) { }; function is_identifier_string(str){ - var i = str.length; - if (i == 0) return false; - if (!is_identifier_start(str.charCodeAt(0))) return false; - while (--i >= 0) { - if (!is_identifier_char(str.charAt(i))) - return false; - } - return true; + return /^[a-z_$][a-z0-9_$]*$/i.test(str); }; function parse_js_number(num) { @@ -1908,6 +1901,7 @@ function parse($TEXT, options) { toplevel : null, expression : false, html5_comments : true, + bare_returns : false, }); var S = { @@ -2087,7 +2081,7 @@ function parse($TEXT, options) { return if_(); case "return": - if (S.in_function == 0) + if (S.in_function == 0 && !options.bare_returns) croak("'return' outside of function"); return new AST_Return({ value: ( is("punc", ";") @@ -3501,6 +3495,7 @@ AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ } if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) + && !(node instanceof AST_SymbolCatch) && node.unreferenced()) { AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { type: node instanceof AST_Label ? "Label" : "Symbol", @@ -3971,7 +3966,13 @@ function OutputStream(options) { /* -----[ PARENTHESES ]----- */ function PARENS(nodetype, func) { - nodetype.DEFMETHOD("needs_parens", func); + if (Array.isArray(nodetype)) { + nodetype.forEach(function(nodetype){ + PARENS(nodetype, func); + }); + } else { + nodetype.DEFMETHOD("needs_parens", func); + } }; PARENS(AST_Node, function(){ @@ -3990,7 +3991,7 @@ function OutputStream(options) { return first_in_statement(output); }); - PARENS(AST_Unary, function(output){ + PARENS([ AST_Unary, AST_Undefined ], function(output){ var p = output.parent(); return p instanceof AST_PropAccess && p.expression === this; }); @@ -4086,7 +4087,7 @@ function OutputStream(options) { return true; }); - function assign_and_conditional_paren_rules(output) { + PARENS([ AST_Assign, AST_Conditional ], function (output){ var p = output.parent(); // !(a = false) → true if (p instanceof AST_Unary) @@ -4103,10 +4104,7 @@ function OutputStream(options) { // (a = foo)["prop"] —or— (a = foo).prop if (p instanceof AST_PropAccess && p.expression === this) return true; - }; - - PARENS(AST_Assign, assign_and_conditional_paren_rules); - PARENS(AST_Conditional, assign_and_conditional_paren_rules); + }); /* -----[ PRINTERS ]----- */ @@ -4193,7 +4191,7 @@ function OutputStream(options) { output.print("for"); output.space(); output.with_parens(function(){ - if (self.init) { + if (self.init && !(self.init instanceof AST_EmptyStatement)) { if (self.init instanceof AST_Definitions) { self.init.print(output); } else { @@ -4533,8 +4531,12 @@ function OutputStream(options) { DEFPRINT(AST_UnaryPrefix, function(self, output){ var op = self.operator; output.print(op); - if (/^[a-z]/i.test(op)) + if (/^[a-z]/i.test(op) + || (/[+-]$/.test(op) + && self.expression instanceof AST_UnaryPrefix + && /^[+-]/.test(self.expression.operator))) { output.space(); + } self.expression.print(output); }); DEFPRINT(AST_UnaryPostfix, function(self, output){ @@ -5613,6 +5615,14 @@ merge(Compressor.prototype, { if (d && d.constant && d.init) return ev(d.init, compressor); throw def; }); + def(AST_Dot, function(compressor){ + if (compressor.option("unsafe") && this.property == "length") { + var str = ev(this.expression, compressor); + if (typeof str == "string") + return str.length; + } + throw def; + }); })(function(node, func){ node.DEFMETHOD("_eval", func); }); @@ -5727,7 +5737,9 @@ merge(Compressor.prototype, { || this.operator == "--" || this.expression.has_side_effects(compressor); }); - def(AST_SymbolRef, function(compressor){ return false }); + def(AST_SymbolRef, function(compressor){ + return this.global() && this.undeclared(); + }); def(AST_Object, function(compressor){ for (var i = this.properties.length; --i >= 0;) if (this.properties[i].has_side_effects(compressor)) @@ -6575,6 +6587,7 @@ merge(Compressor.prototype, { } catch(ex) { if (ex !== ast) throw ex; }; + if (!fun) return self; var args = fun.argnames.map(function(arg, i){ return make_node(AST_String, self.args[i], { value: arg.print_to_string() @@ -7150,6 +7163,17 @@ merge(Compressor.prototype, { alternative: alternative }); } + // x=y?1:1 --> x=1 + if (consequent instanceof AST_Constant + && alternative instanceof AST_Constant + && consequent.equivalent_to(alternative)) { + if (self.condition.has_side_effects(compressor)) { + return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent.value, self)]); + } else { + return make_node_from_constant(compressor, consequent.value, self); + + } + } return self; }); @@ -7187,7 +7211,7 @@ merge(Compressor.prototype, { return make_node(AST_Dot, self, { expression : self.expression, property : prop - }); + }).optimize(compressor); } var v = parseFloat(prop); if (!isNaN(v) && v.toString() == prop) { @@ -7199,6 +7223,19 @@ merge(Compressor.prototype, { return self; }); + OPT(AST_Dot, function(self, compressor){ + var prop = self.property; + if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) { + return make_node(AST_Sub, self, { + expression : self.expression, + property : make_node(AST_String, self, { + value: prop + }) + }).optimize(compressor); + } + return self.evaluate(compressor)[0]; + }); + function literals_in_boolean_context(self, compressor) { if (compressor.option("booleans") && compressor.in_boolean_context()) { return make_node(AST_True, self); @@ -7283,7 +7320,7 @@ function SourceMap(options) { source = info.source; orig_line = info.line; orig_col = info.column; - name = info.name; + name = info.name || name; } generator.addMapping({ generated : { line: gen_line + options.dest_line_diff, column: gen_col }, @@ -7347,53 +7384,68 @@ function SourceMap(options) { (function(){ var MOZ_TO_ME = { - TryStatement : function(M) { + ExpressionStatement: function(M) { + var expr = M.expression; + if (expr.type === "Literal" && typeof expr.value === "string") { + return new AST_Directive({ + start: my_start_token(M), + end: my_end_token(M), + value: expr.value + }); + } + return new AST_SimpleStatement({ + start: my_start_token(M), + end: my_end_token(M), + body: from_moz(expr) + }); + }, + TryStatement: function(M) { + var handlers = M.handlers || [M.handler]; + if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) { + throw new Error("Multiple catch clauses are not supported."); + } return new AST_Try({ start : my_start_token(M), end : my_end_token(M), body : from_moz(M.block).body, - bcatch : from_moz(M.handlers[0]), + bcatch : from_moz(handlers[0]), bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null }); }, - CatchClause : function(M) { - return new AST_Catch({ - start : my_start_token(M), - end : my_end_token(M), - argname : from_moz(M.param), - body : from_moz(M.body).body - }); + Property: function(M) { + var key = M.key; + var name = key.type == "Identifier" ? key.name : key.value; + var args = { + start : my_start_token(key), + end : my_end_token(M.value), + key : name, + value : from_moz(M.value) + }; + switch (M.kind) { + case "init": + return new AST_ObjectKeyVal(args); + case "set": + args.value.name = from_moz(key); + return new AST_ObjectSetter(args); + case "get": + args.value.name = from_moz(key); + return new AST_ObjectGetter(args); + } }, - ObjectExpression : function(M) { + ObjectExpression: function(M) { return new AST_Object({ start : my_start_token(M), end : my_end_token(M), properties : M.properties.map(function(prop){ - var key = prop.key; - var name = key.type == "Identifier" ? key.name : key.value; - var args = { - start : my_start_token(key), - end : my_end_token(prop.value), - key : name, - value : from_moz(prop.value) - }; - switch (prop.kind) { - case "init": - return new AST_ObjectKeyVal(args); - case "set": - args.value.name = from_moz(key); - return new AST_ObjectSetter(args); - case "get": - args.value.name = from_moz(key); - return new AST_ObjectGetter(args); - } + prop.type = "Property"; + return from_moz(prop) }) }); }, - SequenceExpression : function(M) { + SequenceExpression: function(M) { return AST_Seq.from_array(M.expressions.map(from_moz)); }, - MemberExpression : function(M) { + MemberExpression: function(M) { return new (M.computed ? AST_Sub : AST_Dot)({ start : my_start_token(M), end : my_end_token(M), @@ -7401,7 +7453,7 @@ function SourceMap(options) { expression : from_moz(M.object) }); }, - SwitchCase : function(M) { + SwitchCase: function(M) { return new (M.test ? AST_Case : AST_Default)({ start : my_start_token(M), end : my_end_token(M), @@ -7409,7 +7461,14 @@ function SourceMap(options) { body : M.consequent.map(from_moz) }); }, - Literal : function(M) { + VariableDeclaration: function(M) { + return new (M.kind === "const" ? AST_Const : AST_Var)({ + start : my_start_token(M), + end : my_end_token(M), + definitions : M.declarations.map(from_moz) + }); + }, + Literal: function(M) { var val = M.value, args = { start : my_start_token(M), end : my_end_token(M) @@ -7429,12 +7488,9 @@ function SourceMap(options) { return new AST_RegExp(args); } }, - UnaryExpression: From_Moz_Unary, - UpdateExpression: From_Moz_Unary, Identifier: function(M) { var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; - return new (M.name == "this" ? AST_This - : p.type == "LabeledStatement" ? AST_Label + return new ( p.type == "LabeledStatement" ? AST_Label : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar) : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) @@ -7448,7 +7504,8 @@ function SourceMap(options) { } }; - function From_Moz_Unary(M) { + MOZ_TO_ME.UpdateExpression = + MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) { var prefix = "prefix" in M ? M.prefix : M.type == "UnaryExpression" ? true : false; return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ @@ -7459,14 +7516,9 @@ function SourceMap(options) { }); }; - var ME_TO_MOZ = {}; - - map("Node", AST_Node); map("Program", AST_Toplevel, "body@body"); - map("Function", AST_Function, "id>name, params@argnames, body%body"); map("EmptyStatement", AST_EmptyStatement); map("BlockStatement", AST_BlockStatement, "body@body"); - map("ExpressionStatement", AST_SimpleStatement, "expression>body"); map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative"); map("LabeledStatement", AST_LabeledStatement, "label>label, body>body"); map("BreakStatement", AST_Break, "label>label"); @@ -7481,71 +7533,257 @@ function SourceMap(options) { map("ForInStatement", AST_ForIn, "left>init, right>object, body>body"); map("DebuggerStatement", AST_Debugger); map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body"); - map("VariableDeclaration", AST_Var, "declarations@definitions"); map("VariableDeclarator", AST_VarDef, "id>name, init>value"); + map("CatchClause", AST_Catch, "param>argname, body%body"); map("ThisExpression", AST_This); map("ArrayExpression", AST_Array, "elements@elements"); map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body"); map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); - map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); map("NewExpression", AST_New, "callee>expression, arguments@args"); map("CallExpression", AST_Call, "callee>expression, arguments@args"); + def_to_moz(AST_Directive, function To_Moz_Directive(M) { + return { + type: "ExpressionStatement", + expression: { + type: "Literal", + value: M.value + } + }; + }); + + def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) { + return { + type: "ExpressionStatement", + expression: to_moz(M.body) + }; + }); + + def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) { + return { + type: "SwitchCase", + test: to_moz(M.expression), + consequent: M.body.map(to_moz) + }; + }); + + def_to_moz(AST_Try, function To_Moz_TryStatement(M) { + return { + type: "TryStatement", + block: to_moz_block(M), + handler: to_moz(M.bcatch), + guardedHandlers: [], + finalizer: to_moz(M.bfinally) + }; + }); + + def_to_moz(AST_Catch, function To_Moz_CatchClause(M) { + return { + type: "CatchClause", + param: to_moz(M.argname), + guard: null, + body: to_moz_block(M) + }; + }); + + def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) { + return { + type: "VariableDeclaration", + kind: M instanceof AST_Const ? "const" : "var", + declarations: M.definitions.map(to_moz) + }; + }); + + def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) { + return { + type: "SequenceExpression", + expressions: M.to_array().map(to_moz) + }; + }); + + def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) { + var isComputed = M instanceof AST_Sub; + return { + type: "MemberExpression", + object: to_moz(M.expression), + computed: isComputed, + property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property} + }; + }); + + def_to_moz(AST_Unary, function To_Moz_Unary(M) { + return { + type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression", + operator: M.operator, + prefix: M instanceof AST_UnaryPrefix, + argument: to_moz(M.expression) + }; + }); + + def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) { + return { + type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression", + left: to_moz(M.left), + operator: M.operator, + right: to_moz(M.right) + }; + }); + + def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) { + return { + type: "ObjectExpression", + properties: M.properties.map(to_moz) + }; + }); + + def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) { + var key = ( + is_identifier(M.key) + ? {type: "Identifier", name: M.key} + : {type: "Literal", value: M.key} + ); + var kind; + if (M instanceof AST_ObjectKeyVal) { + kind = "init"; + } else + if (M instanceof AST_ObjectGetter) { + kind = "get"; + } else + if (M instanceof AST_ObjectSetter) { + kind = "set"; + } + return { + type: "Property", + kind: kind, + key: key, + value: to_moz(M.value) + }; + }); + + def_to_moz(AST_Symbol, function To_Moz_Identifier(M) { + var def = M.definition(); + return { + type: "Identifier", + name: def ? def.mangled_name || def.name : M.name + }; + }); + + def_to_moz(AST_Constant, function To_Moz_Literal(M) { + var value = M.value; + if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) { + return { + type: "UnaryExpression", + operator: "-", + prefix: true, + argument: { + type: "Literal", + value: -value + } + }; + } + return { + type: "Literal", + value: value + }; + }); + + def_to_moz(AST_Atom, function To_Moz_Atom(M) { + return { + type: "Identifier", + name: String(M.value) + }; + }); + + AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); + AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); + AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null }); + + AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast); + AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast); + /* -----[ tools ]----- */ function my_start_token(moznode) { + var loc = moznode.loc; + var range = moznode.range; return new AST_Token({ - file : moznode.loc && moznode.loc.source, - line : moznode.loc && moznode.loc.start.line, - col : moznode.loc && moznode.loc.start.column, - pos : moznode.start, - endpos : moznode.start + file : loc && loc.source, + line : loc && loc.start.line, + col : loc && loc.start.column, + pos : range ? range[0] : moznode.start, + endpos : range ? range[0] : moznode.start }); }; function my_end_token(moznode) { + var loc = moznode.loc; + var range = moznode.range; return new AST_Token({ - file : moznode.loc && moznode.loc.source, - line : moznode.loc && moznode.loc.end.line, - col : moznode.loc && moznode.loc.end.column, - pos : moznode.end, - endpos : moznode.end + file : loc && loc.source, + line : loc && loc.end.line, + col : loc && loc.end.column, + pos : range ? range[1] : moznode.end, + endpos : range ? range[1] : moznode.end }); }; function map(moztype, mytype, propmap) { var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; - moz_to_me += "return new mytype({\n" + + moz_to_me += "return new " + mytype.name + "({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)"; + var me_to_moz = "function To_Moz_" + moztype + "(M){\n"; + me_to_moz += "return {\n" + + "type: " + JSON.stringify(moztype); + if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){ var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); if (!m) throw new Error("Can't understand property map: " + prop); - var moz = "M." + m[1], how = m[2], my = m[3]; + var moz = m[1], how = m[2], my = m[3]; moz_to_me += ",\n" + my + ": "; - if (how == "@") { - moz_to_me += moz + ".map(from_moz)"; - } else if (how == ">") { - moz_to_me += "from_moz(" + moz + ")"; - } else if (how == "=") { - moz_to_me += moz; - } else if (how == "%") { - moz_to_me += "from_moz(" + moz + ").body"; - } else throw new Error("Can't understand operator in propmap: " + prop); + me_to_moz += ",\n" + moz + ": "; + switch (how) { + case "@": + moz_to_me += "M." + moz + ".map(from_moz)"; + me_to_moz += "M." + my + ".map(to_moz)"; + break; + case ">": + moz_to_me += "from_moz(M." + moz + ")"; + me_to_moz += "to_moz(M." + my + ")"; + break; + case "=": + moz_to_me += "M." + moz; + me_to_moz += "M." + my; + break; + case "%": + moz_to_me += "from_moz(M." + moz + ").body"; + me_to_moz += "to_moz_block(M)"; + break; + default: + throw new Error("Can't understand operator in propmap: " + prop); + } }); - moz_to_me += "\n})}"; - // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); - // console.log(moz_to_me); + moz_to_me += "\n})\n}"; + me_to_moz += "\n}\n}"; + + //moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); + //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true }); + //console.log(moz_to_me); - moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( - mytype, my_start_token, my_end_token, from_moz + moz_to_me = new Function("my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( + my_start_token, my_end_token, from_moz ); - return MOZ_TO_ME[moztype] = moz_to_me; + me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")( + to_moz, to_moz_block + ); + MOZ_TO_ME[moztype] = moz_to_me; + def_to_moz(mytype, me_to_moz); }; var FROM_MOZ_STACK = null; @@ -7565,6 +7803,48 @@ function SourceMap(options) { return ast; }; + function moz_sub_loc(token) { + return token.line ? { + line: token.line, + column: token.col + } : null; + }; + + function set_moz_loc(mynode, moznode) { + var start = mynode.start; + var end = mynode.end; + if (start.pos != null && end.pos != null) { + moznode.range = [start.pos, end.pos]; + } + if (start.line) { + moznode.loc = { + start: moz_sub_loc(start), + end: moz_sub_loc(end) + }; + if (start.file) { + moznode.loc.source = start.file; + } + } + return moznode; + }; + + function def_to_moz(mytype, handler) { + mytype.DEFMETHOD("to_mozilla_ast", function() { + return set_moz_loc(this, handler(this)); + }); + }; + + function to_moz(node) { + return node != null ? node.to_mozilla_ast() : null; + }; + + function to_moz_block(node) { + return { + type: "BlockStatement", + body: node.body.map(to_moz) + }; + }; + })(); AST_Node.warn_function = function(txt) { logger.error("uglifyjs2 WARN: " + txt); }; @@ -7634,7 +7914,7 @@ exports.minify = function(files, options, name) { if (options.sourceMapIncludeSources) { for (var file in sourcesContent) { if (sourcesContent.hasOwnProperty(file)) { - options.source_map.get().setSourceContent(file, sourcesContent[file]); + output.source_map.get().setSourceContent(file, sourcesContent[file]); } } } @@ -7645,6 +7925,11 @@ exports.minify = function(files, options, name) { } var stream = OutputStream(output); toplevel.print(stream); + + if(options.outSourceMap){ + stream += "\n//# sourceMappingURL=" + options.outSourceMap; + } + return { code : stream + "", map : output.source_map + "" diff --git a/build/jslib/uglifyjs2/README.md b/build/jslib/uglifyjs2/README.md index 4c507a81..fc76a765 100644 --- a/build/jslib/uglifyjs2/README.md +++ b/build/jslib/uglifyjs2/README.md @@ -1,6 +1,6 @@ Sets up uglifyjs2 for use in the optimizer. -Current embedded version: 2.4.13, source-map 0.1.33 +Current embedded version: 2.4.16, source-map 0.1.34 Steps: diff --git a/build/jslib/x.js b/build/jslib/x.js index 64c8672a..e434ad4c 100644 --- a/build/jslib/x.js +++ b/build/jslib/x.js @@ -420,7 +420,7 @@ var requirejs, require, define, xpcUtil; } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.4.13, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.4.16, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); diff --git a/build/tests/lib/sourcemap/expected-main.js.map b/build/tests/lib/sourcemap/expected-main.js.map index c5e82145..8c0181f4 100644 --- a/build/tests/lib/sourcemap/expected-main.js.map +++ b/build/tests/lib/sourcemap/expected-main.js.map @@ -1 +1 @@ -{"version":3,"file":"main.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n\n"]} \ No newline at end of file +{"version":3,"file":"main.js","sources":["a.js","b.js","main.js"],"names":["define","name","doSomething","console","log","require","a","b"],"mappings":"AAGAA,OAAA,KACAC,KAAA,IACAC,YAAA,SAAAD,GACAE,QAAAC,IAAA,SAAAH,MAGAE,QAAAC,IAAA,aCNAJ,OAAA,OAAA,WACA,GAAAC,GAAA,GACA,QACAA,KAAAA,KCHAI,SAAA,IAAA,KAAA,SAAAC,EAAAC,GACAJ,QAAAC,IAAA,oBACAE,EAAAJ,YAAA,SACAC,QAAAC,IAAA,WAAAG,EAAAN,QAGAD,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemap/onejs/expected.map b/build/tests/lib/sourcemap/onejs/expected.map index 25bfc440..9605eb69 100644 --- a/build/tests/lib/sourcemap/onejs/expected.map +++ b/build/tests/lib/sourcemap/onejs/expected.map @@ -1 +1 @@ -{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":[],"mappings":"AAUA,OAAA,QAAA,UAAA,SAAA,GAGA,GAAA,GAAA,EAAA,EAAA,EAAA,EACA,GAAA,iBAAA,oBAAA,sBACA,EAAA,2DACA,EAAA,uCACA,EAAA,mBAAA,WAAA,SAAA,KACA,EAAA,GAAA,SAAA,UAAA,SAAA,SAAA,QAAA,KAAA,IACA,EAAA,GAAA,SAAA,SACA,EAAA,IAAA,SAAA,MAAA,QACA,KACA,EAAA,EAAA,QAAA,EAAA,YA0WA,OAxWA,IACA,QAAA,SAEA,MAAA,SAAA,GAIA,GAAA,EAAA,CACA,EAAA,EAAA,QAAA,EAAA,GACA,IAAA,GAAA,EAAA,MAAA,EACA,KACA,EAAA,EAAA,QAGA,GAAA,EAEA,OAAA,IAGA,SAAA,SAAA,GACA,MAAA,GAAA,QAAA,WAAA,QACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,QAAA,OACA,QAAA,YAAA,WACA,QAAA,YAAA,YAGA,UAAA,EAAA,WAAA,WAEA,GAAA,GAAA,EAAA,CACA,IAAA,mBAAA,gBACA,MAAA,IAAA,eACA,IAAA,mBAAA,eACA,IAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,CACA,EAAA,EAAA,EACA,KACA,EAAA,GAAA,eAAA,GACA,MAAA,IAEA,GAAA,EAAA,CACA,GAAA,EACA,QAKA,MAAA,IAWA,UAAA,SAAA,GACA,GAAA,GAAA,EAAA,EACA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,EAAA,IAAA,EAAA,QAAA,OACA,IAAA,EAAA,QAAA,MAsBA,OApBA,KAAA,KAAA,GAAA,EAAA,IACA,EAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,EAAA,EAAA,SAEA,EAAA,EAGA,EAAA,GAAA,EACA,EAAA,EAAA,QAAA,KACA,KAAA,IAEA,EAAA,UAAA,EAAA,UAAA,EAAA,GACA,EAAA,EAAA,UAAA,EAAA,GACA,EACA,EAAA,EAEA,EAAA,IAKA,WAAA,EACA,IAAA,EACA,MAAA,IAIA,SAAA,4BAUA,OAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,EAAA,EAAA,SAAA,KAAA,EACA,OAAA,IAGA,EAAA,EAAA,GACA,EAAA,EAAA,GAEA,EAAA,EAAA,MAAA,KACA,EAAA,EAAA,GACA,EAAA,EAAA,KAEA,GAAA,IAAA,GACA,GAAA,EAAA,gBAAA,EAAA,gBACA,GAAA,IAAA,IAAA,KAXA,GAcA,WAAA,SAAA,EAAA,EAAA,EAAA,GACA,EAAA,EAAA,EAAA,MAAA,GAAA,EACA,EAAA,UACA,EAAA,GAAA,GAEA,EAAA,IAGA,KAAA,SAAA,EAAA,EAAA,EAAA,GAUA,GAAA,EAAA,UAAA,EAAA,WAEA,WADA,IAIA,GAAA,QAAA,EAAA,OAEA,IAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,YACA,EAAA,IAAA,IAAA,EAAA,IAAA,IACA,EAAA,EAAA,MAAA,GACA,EAAA,EAAA,QACA,EAAA,MAGA,OAAA,KAAA,EAAA,QAAA,cACA,WAKA,GAAA,EAAA,EAAA,EAAA,EAAA,GACA,EAAA,IAAA,EAAA,SAAA,GACA,EAAA,WAAA,EAAA,EAAA,MAAA,EAAA,IACA,SAAA,GACA,EAAA,OACA,EAAA,MAAA,KAQA,GAAA,GAAA,SAAA,GACA,EAAA,WAAA,EAAA,WAAA,IAAA,EAAA,IACA,EAAA,MAAA,EAAA,OAKA,MAAA,SAAA,EAAA,EAAA,GACA,GAAA,EAAA,eAAA,GAAA,CACA,GAAA,GAAA,EAAA,SAAA,EAAA,GACA,GAAA,SAAA,EAAA,IAAA,EACA,gCACA,EACA,aAIA,UAAA,SAAA,EAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,UAAA,GACA,EAAA,EAAA,IAAA,IAAA,EAAA,IAAA,GACA,EAAA,EAAA,WAAA,EAGA,EAAA,EAAA,MAAA,EAAA,WAAA,GAAA,KAKA,GAAA,KAAA,EAAA,EAAA,WAIA,GAAA,GAAA,SAAA,GACA,MAAA,GAAA,EAAA,GAEA,GAAA,SAAA,SAAA,EAAA,GACA,MAAA,GAAA,SAAA,EAAA,EAAA,IAGA,EAAA,MAAA,EAAA,EAAA,EAAA,IACA,KAIA,SAAA,EAAA,MAAA,EAAA,KACA,mBAAA,UACA,QAAA,UACA,QAAA,SAAA,OACA,QAAA,SAAA,gBAEA,EAAA,QAAA,YAAA,MAEA,EAAA,IAAA,SAAA,EAAA,EAAA,GACA,IACA,GAAA,GAAA,EAAA,aAAA,EAAA,OAEA,KAAA,EAAA,QAAA,OACA,EAAA,EAAA,UAAA,IAEA,EAAA,GACA,MAAA,GACA,EAAA,MAGA,QAAA,EAAA,MAAA,EAAA,KACA,EAAA,YACA,EAAA,IAAA,SAAA,EAAA,EAAA,EAAA,GACA,GAAA,GAAA,EAAA,EAAA,WAIA,IAHA,EAAA,KAAA,MAAA,GAAA,GAGA,EACA,IAAA,IAAA,GACA,EAAA,eAAA,IACA,EAAA,iBAAA,EAAA,cAAA,EAAA,GAMA,GAAA,OACA,EAAA,MAAA,EAAA,GAGA,EAAA,mBAAA,WACA,GAAA,GAAA,CAGA,KAAA,EAAA,aACA,EAAA,EAAA,OACA,EAAA,KAAA,IAAA,GAEA,EAAA,GAAA,OAAA,EAAA,iBAAA,GACA,EAAA,IAAA,EACA,EAAA,IAEA,EAAA,EAAA,cAGA,EAAA,eACA,EAAA,cAAA,EAAA,KAIA,EAAA,KAAA,OAEA,UAAA,EAAA,MAAA,EAAA,KACA,mBAAA,WAAA,mBAAA,MAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EACA,EAAA,QACA,EAAA,GAAA,MAAA,GAAA,KAAA,GACA,EAAA,KAAA,KAAA,OAAA,YAAA,kBACA,EAAA,GAAA,MAAA,GAAA,eAAA,GAAA,MAAA,GAAA,kBAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,IACA,EAAA,EACA,KAoBA,IAnBA,EAAA,GAAA,MAAA,KAAA,aACA,EAAA,EAAA,WAOA,GAAA,EAAA,UAAA,QAAA,EAAA,OAAA,KAIA,EAAA,EAAA,UAAA,IAGA,OAAA,GACA,EAAA,OAAA,GAGA,QAAA,EAAA,EAAA,aACA,EAAA,OAAA,GACA,EAAA,OAAA,EAGA,GAAA,OAAA,EAAA,YACA,QACA,EAAA,QAEA,EAAA,KAEA,cAAA,EAAA,MAAA,EAAA,KACA,mBAAA,aAAA,WAAA,SACA,WAAA,cAEA,EAAA,WAAA,QACA,EAAA,WAAA,WACA,WAAA,MAAA,UAAA,wCACA,EAAA,uCAAA,GAEA,EAAA,IAAA,SAAA,EAAA,GACA,GAAA,GAAA,EAAA,EACA,IAEA,KACA,EAAA,EAAA,QAAA,MAAA,OAGA,EAAA,GAAA,WAAA,KAAA,EAGA,KACA,EAAA,EAAA,4CACA,eAAA,EAAA,oBACA,EAAA,KAAA,EAAA,EAAA,GAAA,GAEA,EAAA,EAAA,8CACA,eAAA,EAAA,yBACA,EAAA,KAAA,EAAA,QAAA,EAAA,YACA,EAAA,wBAAA,+BAEA,EAAA,WAAA,EAAA,YAAA,GACA,EAAA,QACA,EAAA,QACA,EAAA,EAAA,OACA,MAAA,GACA,KAAA,IAAA,QAAA,GAAA,EAAA,MAAA,IAAA,KAAA,MAIA,IC/XA,OAAA,yBAAA,WAAA,MAAA,eCEA,OAAA,SACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,wBACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aAEA,OCZA,YAAA,UAAA,oBAAA,OAAA,SAAA,GACA,GAAA,GAAA,EAAA,qBACA,EAAA,EAAA,MAEA,QACA,KAAA,OACA,EAAA,EACA,KAAA,KCPA,QDYA,QCXA,QAAA,SACA,OACA,IAAA,SACA,KAAA,eAOA,SAAA,YAAA,SAAA,GACA,QAAA,IAAA,yBACA,QAAA,IAAA,EAAA,EAAA,YAAA,UACA,QAAA,IAAA,iCAGA,OAAA,MAAA","sourcesContent":["/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n\n","/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('starting doSomething');\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","define('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n\n","require.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main'], function (main) {\n console.log('in top level callback');\n console.log(main.a.doSomething('world'));\n console.log('finished top level callback');\n});\n\ndefine(\"app\", function(){});\n\n"]} \ No newline at end of file +{"version":3,"file":"built.js","sources":["text/text.js","../app/sample.txt!text","../app/a.js","../app/main.js","../app.js"],"names":["define","module","text","fs","Cc","Ci","xpcIsWindows","progIds","xmlRegExp","bodyRegExp","hasLocation","location","href","defaultProtocol","protocol","replace","defaultHostName","hostname","defaultPort","port","undefined","buildMap","masterConfig","config","version","strip","content","matches","match","jsEscape","createXhr","xhr","i","progId","XMLHttpRequest","ActiveXObject","e","parseName","name","modName","ext","temp","index","indexOf","isRelative","substring","length","moduleName","xdRegExp","useXhr","url","uProtocol","uHostName","uPort","exec","split","toLowerCase","finishLoad","onLoad","isBuild","load","req","inlineText","parsed","nonStripName","toUrl","get","err","error","write","pluginName","hasOwnProperty","asModule","writeFile","extPart","fileName","textWrite","contents","env","process","versions","node","require","nodeRequire","callback","errback","file","readFileSync","headers","header","open","setRequestHeader","onXhr","onreadystatechange","status","readyState","Error","responseText","onXhrComplete","send","Packages","java","stringBuffer","line","encoding","io","File","lineSeparator","lang","System","getProperty","input","BufferedReader","InputStreamReader","FileInputStream","StringBuffer","readLine","charAt","append","String","toString","close","Components","classes","interfaces","utils","inStream","convertStream","fileObj","readData","FileUtils","createInstance","nsIFileInputStream","init","nsIConverterInputStream","available","DEFAULT_REPLACEMENT_CHARACTER","readString","value","path","doSomething","console","log","a","baseUrl","paths","app","main"],"mappings":"AAUAA,OAAA,QAAA,UAAA,SAAAC,GAGA,GAAAC,GAAAC,EAAAC,EAAAC,EAAAC,EACAC,GAAA,iBAAA,oBAAA,sBACAC,EAAA,2DACAC,EAAA,uCACAC,EAAA,mBAAAC,WAAAA,SAAAC,KACAC,EAAAH,GAAAC,SAAAG,UAAAH,SAAAG,SAAAC,QAAA,KAAA,IACAC,EAAAN,GAAAC,SAAAM,SACAC,EAAAR,IAAAC,SAAAQ,MAAAC,QACAC,KACAC,EAAArB,EAAAsB,QAAAtB,EAAAsB,YA0WA,OAxWArB,IACAsB,QAAA,SAEAC,MAAA,SAAAC,GAIA,GAAAA,EAAA,CACAA,EAAAA,EAAAX,QAAAP,EAAA,GACA,IAAAmB,GAAAD,EAAAE,MAAAnB,EACAkB,KACAD,EAAAC,EAAA,QAGAD,GAAA,EAEA,OAAAA,IAGAG,SAAA,SAAAH,GACA,MAAAA,GAAAX,QAAA,WAAA,QACAA,QAAA,QAAA,OACAA,QAAA,QAAA,OACAA,QAAA,QAAA,OACAA,QAAA,QAAA,OACAA,QAAA,QAAA,OACAA,QAAA,YAAA,WACAA,QAAA,YAAA,YAGAe,UAAAR,EAAAQ,WAAA,WAEA,GAAAC,GAAAC,EAAAC,CACA,IAAA,mBAAAC,gBACA,MAAA,IAAAA,eACA,IAAA,mBAAAC,eACA,IAAAH,EAAA,EAAA,EAAAA,EAAAA,GAAA,EAAA,CACAC,EAAA1B,EAAAyB,EACA,KACAD,EAAA,GAAAI,eAAAF,GACA,MAAAG,IAEA,GAAAL,EAAA,CACAxB,GAAA0B,EACA,QAKA,MAAAF,IAWAM,UAAA,SAAAC,GACA,GAAAC,GAAAC,EAAAC,EACAhB,GAAA,EACAiB,EAAAJ,EAAAK,QAAA,KACAC,EAAA,IAAAN,EAAAK,QAAA,OACA,IAAAL,EAAAK,QAAA,MAsBA,OApBA,KAAAD,KAAAE,GAAAF,EAAA,IACAH,EAAAD,EAAAO,UAAA,EAAAH,GACAF,EAAAF,EAAAO,UAAAH,EAAA,EAAAJ,EAAAQ,SAEAP,EAAAD,EAGAG,EAAAD,GAAAD,EACAG,EAAAD,EAAAE,QAAA,KACA,KAAAD,IAEAjB,EAAA,UAAAgB,EAAAI,UAAAH,EAAA,GACAD,EAAAA,EAAAI,UAAA,EAAAH,GACAF,EACAA,EAAAC,EAEAF,EAAAE,IAKAM,WAAAR,EACAC,IAAAA,EACAf,MAAAA,IAIAuB,SAAA,4BAUAC,OAAA,SAAAC,EAAApC,EAAAG,EAAAE,GACA,GAAAgC,GAAAC,EAAAC,EACAzB,EAAA1B,EAAA8C,SAAAM,KAAAJ,EACA,OAAAtB,IAGAuB,EAAAvB,EAAA,GACAwB,EAAAxB,EAAA,GAEAwB,EAAAA,EAAAG,MAAA,KACAF,EAAAD,EAAA,GACAA,EAAAA,EAAA,KAEAD,GAAAA,IAAArC,GACAsC,GAAAA,EAAAI,gBAAAvC,EAAAuC,gBACAH,GAAAD,IAAAC,IAAAlC,KAXA,GAcAsC,WAAA,SAAAnB,EAAAb,EAAAC,EAAAgC,GACAhC,EAAAD,EAAAvB,EAAAuB,MAAAC,GAAAA,EACAJ,EAAAqC,UACAtC,EAAAiB,GAAAZ,GAEAgC,EAAAhC,IAGAkC,KAAA,SAAAtB,EAAAuB,EAAAH,EAAAnC,GAUA,GAAAA,EAAAoC,UAAApC,EAAAuC,WAEA,WADAJ,IAIApC,GAAAqC,QAAApC,EAAAoC,OAEA,IAAAI,GAAA7D,EAAAmC,UAAAC,GACA0B,EAAAD,EAAAhB,YACAgB,EAAAvB,IAAA,IAAAuB,EAAAvB,IAAA,IACAU,EAAAW,EAAAI,MAAAD,GACAf,EAAA3B,EAAA,QACApB,EAAA+C,MAGA,OAAA,KAAAC,EAAAP,QAAA,cACAe,WAKAhD,GAAAuC,EAAAC,EAAArC,EAAAG,EAAAE,GACAhB,EAAAgE,IAAAhB,EAAA,SAAAxB,GACAxB,EAAAuD,WAAAnB,EAAAyB,EAAAtC,MAAAC,EAAAgC,IACA,SAAAS,GACAT,EAAAU,OACAV,EAAAU,MAAAD,KAQAN,GAAAG,GAAA,SAAAtC,GACAxB,EAAAuD,WAAAM,EAAAhB,WAAA,IAAAgB,EAAAvB,IACAuB,EAAAtC,MAAAC,EAAAgC,OAKAW,MAAA,SAAAC,EAAAvB,EAAAsB,GACA,GAAAhD,EAAAkD,eAAAxB,GAAA,CACA,GAAArB,GAAAxB,EAAA2B,SAAAR,EAAA0B,GACAsB,GAAAG,SAAAF,EAAA,IAAAvB,EACA,gCACArB,EACA,aAIA+C,UAAA,SAAAH,EAAAvB,EAAAc,EAAAQ,EAAA9C,GACA,GAAAwC,GAAA7D,EAAAmC,UAAAU,GACA2B,EAAAX,EAAAvB,IAAA,IAAAuB,EAAAvB,IAAA,GACAwB,EAAAD,EAAAhB,WAAA2B,EAGAC,EAAAd,EAAAI,MAAAF,EAAAhB,WAAA2B,GAAA,KAKAxE,GAAA0D,KAAAI,EAAAH,EAAA,WAIA,GAAAe,GAAA,SAAAC,GACA,MAAAR,GAAAM,EAAAE,GAEAD,GAAAJ,SAAA,SAAAzB,EAAA8B,GACA,MAAAR,GAAAG,SAAAzB,EAAA4B,EAAAE,IAGA3E,EAAAmE,MAAAC,EAAAN,EAAAY,EAAArD,IACAA,KAIA,SAAAD,EAAAwD,MAAAxD,EAAAwD,KACA,mBAAAC,UACAA,QAAAC,UACAD,QAAAC,SAAAC,OACAF,QAAAC,SAAA,gBAEA7E,EAAA+E,QAAAC,YAAA,MAEAjF,EAAAgE,IAAA,SAAAhB,EAAAkC,EAAAC,GACA,IACA,GAAAC,GAAAnF,EAAAoF,aAAArC,EAAA,OAEA,KAAAoC,EAAA3C,QAAA,OACA2C,EAAAA,EAAAzC,UAAA,IAEAuC,EAAAE,GACA,MAAAlD,GACAiD,EAAAjD,MAGA,QAAAd,EAAAwD,MAAAxD,EAAAwD,KACA5E,EAAA4B,YACA5B,EAAAgE,IAAA,SAAAhB,EAAAkC,EAAAC,EAAAG,GACA,GAAAC,GAAA1D,EAAA7B,EAAA4B,WAIA,IAHAC,EAAA2D,KAAA,MAAAxC,GAAA,GAGAsC,EACA,IAAAC,IAAAD,GACAA,EAAAjB,eAAAkB,IACA1D,EAAA4D,iBAAAF,EAAAjC,cAAAgC,EAAAC,GAMAnE,GAAAsE,OACAtE,EAAAsE,MAAA7D,EAAAmB,GAGAnB,EAAA8D,mBAAA,WACA,GAAAC,GAAA3B,CAGA,KAAApC,EAAAgE,aACAD,EAAA/D,EAAA+D,OACAA,EAAA,KAAA,IAAAA,GAEA3B,EAAA,GAAA6B,OAAA9C,EAAA,iBAAA4C,GACA3B,EAAApC,IAAAA,EACAsD,EAAAlB,IAEAiB,EAAArD,EAAAkE,cAGA3E,EAAA4E,eACA5E,EAAA4E,cAAAnE,EAAAmB,KAIAnB,EAAAoE,KAAA,OAEA,UAAA7E,EAAAwD,MAAAxD,EAAAwD,KACA,mBAAAsB,WAAA,mBAAAC,MAEAnG,EAAAgE,IAAA,SAAAhB,EAAAkC,GACA,GAAAkB,GAAAC,EACAC,EAAA,QACAlB,EAAA,GAAAe,MAAAI,GAAAC,KAAAxD,GACAyD,EAAAN,KAAAO,KAAAC,OAAAC,YAAA,kBACAC,EAAA,GAAAV,MAAAI,GAAAO,eAAA,GAAAX,MAAAI,GAAAQ,kBAAA,GAAAZ,MAAAI,GAAAS,gBAAA5B,GAAAkB,IACA9E,EAAA,EACA,KAoBA,IAnBA4E,EAAA,GAAAD,MAAAO,KAAAO,aACAZ,EAAAQ,EAAAK,WAOAb,GAAAA,EAAAzD,UAAA,QAAAyD,EAAAc,OAAA,KAIAd,EAAAA,EAAA1D,UAAA,IAGA,OAAA0D,GACAD,EAAAgB,OAAAf,GAGA,QAAAA,EAAAQ,EAAAK,aACAd,EAAAgB,OAAAX,GACAL,EAAAgB,OAAAf,EAGA7E,GAAA6F,OAAAjB,EAAAkB,YACA,QACAT,EAAAU,QAEArC,EAAA1D,KAEA,cAAAJ,EAAAwD,MAAAxD,EAAAwD,KACA,mBAAA4C,aAAAA,WAAAC,SACAD,WAAAE,cAEAxH,EAAAsH,WAAAC,QACAtH,EAAAqH,WAAAE,WACAF,WAAAG,MAAA,UAAA,wCACAvH,EAAA,uCAAAF,GAEAF,EAAAgE,IAAA,SAAAhB,EAAAkC,GACA,GAAA0C,GAAAC,EAAAC,EACAC,IAEA3H,KACA4C,EAAAA,EAAAnC,QAAA,MAAA,OAGAiH,EAAA,GAAAE,WAAAxB,KAAAxD,EAGA,KACA4E,EAAA1H,EAAA,4CACA+H,eAAA9H,EAAA+H,oBACAN,EAAAO,KAAAL,EAAA,EAAA,GAAA,GAEAD,EAAA3H,EAAA,8CACA+H,eAAA9H,EAAAiI,yBACAP,EAAAM,KAAAP,EAAA,QAAAA,EAAAS,YACAlI,EAAAiI,wBAAAE,+BAEAT,EAAAU,WAAAX,EAAAS,YAAAN,GACAF,EAAAN,QACAK,EAAAL,QACArC,EAAA6C,EAAAS,OACA,MAAAtG,GACA,KAAA,IAAA4D,QAAAgC,GAAAA,EAAAW,MAAA,IAAA,KAAAvG,MAIAlC,IC/XAF,OAAA,yBAAA,WAAA,MAAA,eCEAA,OAAA,SACAsC,KAAA,IACAsG,YAAA,SAAAtG,GACAuG,QAAAC,IAAA,wBACAD,QAAAC,IAAA,SAAAxG,MAGAuG,QAAAC,IAAA,aAEA9I,OCZA,YAAA,UAAA,oBAAA,OAAA,SAAAkF,GACA,GAAAhF,GAAAgF,EAAA,qBACA6D,EAAA7D,EAAA,MAEA,QACA5C,KAAA,OACAyG,EAAAA,EACA7I,KAAAA,KCPAgF,QDYA3D,QCXAyH,QAAA,SACAC,OACAC,IAAA,SACAhJ,KAAA,eAOAgF,SAAA,YAAA,SAAAiE,GACAN,QAAAC,IAAA,yBACAD,QAAAC,IAAAK,EAAAJ,EAAAH,YAAA,UACAC,QAAAC,IAAA,iCAGA9I,OAAA,MAAA","sourcesContent":["/**\n * @license RequireJS text 2.0.10 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved.\n * Available via the MIT or new BSD license.\n * see: http://github.com/requirejs/text for details\n */\n/*jslint regexp: true */\n/*global require, XMLHttpRequest, ActiveXObject,\n define, window, process, Packages,\n java, location, Components, FileUtils */\n\ndefine('text',['module'], function (module) {\n 'use strict';\n\n var text, fs, Cc, Ci, xpcIsWindows,\n progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],\n xmlRegExp = /^\\s*<\\?xml(\\s)+version=[\\'\\\"](\\d)*.(\\d)*[\\'\\\"](\\s)*\\?>/im,\n bodyRegExp = /]*>\\s*([\\s\\S]+)\\s*<\\/body>/im,\n hasLocation = typeof location !== 'undefined' && location.href,\n defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\\:/, ''),\n defaultHostName = hasLocation && location.hostname,\n defaultPort = hasLocation && (location.port || undefined),\n buildMap = {},\n masterConfig = (module.config && module.config()) || {};\n\n text = {\n version: '2.0.10',\n\n strip: function (content) {\n //Strips declarations so that external SVG and XML\n //documents can be added to a document without worry. Also, if the string\n //is an HTML document, only the part inside the body tag is returned.\n if (content) {\n content = content.replace(xmlRegExp, \"\");\n var matches = content.match(bodyRegExp);\n if (matches) {\n content = matches[1];\n }\n } else {\n content = \"\";\n }\n return content;\n },\n\n jsEscape: function (content) {\n return content.replace(/(['\\\\])/g, '\\\\$1')\n .replace(/[\\f]/g, \"\\\\f\")\n .replace(/[\\b]/g, \"\\\\b\")\n .replace(/[\\n]/g, \"\\\\n\")\n .replace(/[\\t]/g, \"\\\\t\")\n .replace(/[\\r]/g, \"\\\\r\")\n .replace(/[\\u2028]/g, \"\\\\u2028\")\n .replace(/[\\u2029]/g, \"\\\\u2029\");\n },\n\n createXhr: masterConfig.createXhr || function () {\n //Would love to dump the ActiveX crap in here. Need IE 6 to die first.\n var xhr, i, progId;\n if (typeof XMLHttpRequest !== \"undefined\") {\n return new XMLHttpRequest();\n } else if (typeof ActiveXObject !== \"undefined\") {\n for (i = 0; i < 3; i += 1) {\n progId = progIds[i];\n try {\n xhr = new ActiveXObject(progId);\n } catch (e) {}\n\n if (xhr) {\n progIds = [progId]; // so faster next time\n break;\n }\n }\n }\n\n return xhr;\n },\n\n /**\n * Parses a resource name into its component parts. Resource names\n * look like: module/name.ext!strip, where the !strip part is\n * optional.\n * @param {String} name the resource name\n * @returns {Object} with properties \"moduleName\", \"ext\" and \"strip\"\n * where strip is a boolean.\n */\n parseName: function (name) {\n var modName, ext, temp,\n strip = false,\n index = name.indexOf(\".\"),\n isRelative = name.indexOf('./') === 0 ||\n name.indexOf('../') === 0;\n\n if (index !== -1 && (!isRelative || index > 1)) {\n modName = name.substring(0, index);\n ext = name.substring(index + 1, name.length);\n } else {\n modName = name;\n }\n\n temp = ext || modName;\n index = temp.indexOf(\"!\");\n if (index !== -1) {\n //Pull off the strip arg.\n strip = temp.substring(index + 1) === \"strip\";\n temp = temp.substring(0, index);\n if (ext) {\n ext = temp;\n } else {\n modName = temp;\n }\n }\n\n return {\n moduleName: modName,\n ext: ext,\n strip: strip\n };\n },\n\n xdRegExp: /^((\\w+)\\:)?\\/\\/([^\\/\\\\]+)/,\n\n /**\n * Is an URL on another domain. Only works for browser use, returns\n * false in non-browser environments. Only used to know if an\n * optimized .js version of a text resource should be loaded\n * instead.\n * @param {String} url\n * @returns Boolean\n */\n useXhr: function (url, protocol, hostname, port) {\n var uProtocol, uHostName, uPort,\n match = text.xdRegExp.exec(url);\n if (!match) {\n return true;\n }\n uProtocol = match[2];\n uHostName = match[3];\n\n uHostName = uHostName.split(':');\n uPort = uHostName[1];\n uHostName = uHostName[0];\n\n return (!uProtocol || uProtocol === protocol) &&\n (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&\n ((!uPort && !uHostName) || uPort === port);\n },\n\n finishLoad: function (name, strip, content, onLoad) {\n content = strip ? text.strip(content) : content;\n if (masterConfig.isBuild) {\n buildMap[name] = content;\n }\n onLoad(content);\n },\n\n load: function (name, req, onLoad, config) {\n //Name has format: some.module.filext!strip\n //The strip part is optional.\n //if strip is present, then that means only get the string contents\n //inside a body tag in an HTML string. For XML/SVG content it means\n //removing the declarations so the content can be inserted\n //into the current doc without problems.\n\n // Do not bother with the work if a build and text will\n // not be inlined.\n if (config.isBuild && !config.inlineText) {\n onLoad();\n return;\n }\n\n masterConfig.isBuild = config.isBuild;\n\n var parsed = text.parseName(name),\n nonStripName = parsed.moduleName +\n (parsed.ext ? '.' + parsed.ext : ''),\n url = req.toUrl(nonStripName),\n useXhr = (masterConfig.useXhr) ||\n text.useXhr;\n\n // Do not load if it is an empty: url\n if (url.indexOf('empty:') === 0) {\n onLoad();\n return;\n }\n\n //Load the text. Use XHR if possible and in a browser.\n if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {\n text.get(url, function (content) {\n text.finishLoad(name, parsed.strip, content, onLoad);\n }, function (err) {\n if (onLoad.error) {\n onLoad.error(err);\n }\n });\n } else {\n //Need to fetch the resource across domains. Assume\n //the resource has been optimized into a JS module. Fetch\n //by the module name + extension, but do not include the\n //!strip part to avoid file system issues.\n req([nonStripName], function (content) {\n text.finishLoad(parsed.moduleName + '.' + parsed.ext,\n parsed.strip, content, onLoad);\n });\n }\n },\n\n write: function (pluginName, moduleName, write, config) {\n if (buildMap.hasOwnProperty(moduleName)) {\n var content = text.jsEscape(buildMap[moduleName]);\n write.asModule(pluginName + \"!\" + moduleName,\n \"define(function () { return '\" +\n content +\n \"';});\\n\");\n }\n },\n\n writeFile: function (pluginName, moduleName, req, write, config) {\n var parsed = text.parseName(moduleName),\n extPart = parsed.ext ? '.' + parsed.ext : '',\n nonStripName = parsed.moduleName + extPart,\n //Use a '.js' file name so that it indicates it is a\n //script that can be loaded across domains.\n fileName = req.toUrl(parsed.moduleName + extPart) + '.js';\n\n //Leverage own load() method to load plugin value, but only\n //write out values that do not have the strip argument,\n //to avoid any potential issues with ! in file names.\n text.load(nonStripName, req, function (value) {\n //Use own write() method to construct full module value.\n //But need to create shell that translates writeFile's\n //write() to the right interface.\n var textWrite = function (contents) {\n return write(fileName, contents);\n };\n textWrite.asModule = function (moduleName, contents) {\n return write.asModule(moduleName, fileName, contents);\n };\n\n text.write(pluginName, nonStripName, textWrite, config);\n }, config);\n }\n };\n\n if (masterConfig.env === 'node' || (!masterConfig.env &&\n typeof process !== \"undefined\" &&\n process.versions &&\n !!process.versions.node &&\n !process.versions['node-webkit'])) {\n //Using special require.nodeRequire, something added by r.js.\n fs = require.nodeRequire('fs');\n\n text.get = function (url, callback, errback) {\n try {\n var file = fs.readFileSync(url, 'utf8');\n //Remove BOM (Byte Mark Order) from utf8 files if it is there.\n if (file.indexOf('\\uFEFF') === 0) {\n file = file.substring(1);\n }\n callback(file);\n } catch (e) {\n errback(e);\n }\n };\n } else if (masterConfig.env === 'xhr' || (!masterConfig.env &&\n text.createXhr())) {\n text.get = function (url, callback, errback, headers) {\n var xhr = text.createXhr(), header;\n xhr.open('GET', url, true);\n\n //Allow plugins direct access to xhr headers\n if (headers) {\n for (header in headers) {\n if (headers.hasOwnProperty(header)) {\n xhr.setRequestHeader(header.toLowerCase(), headers[header]);\n }\n }\n }\n\n //Allow overrides specified in config\n if (masterConfig.onXhr) {\n masterConfig.onXhr(xhr, url);\n }\n\n xhr.onreadystatechange = function (evt) {\n var status, err;\n //Do not explicitly handle errors, those should be\n //visible via console output in the browser.\n if (xhr.readyState === 4) {\n status = xhr.status;\n if (status > 399 && status < 600) {\n //An http 4xx or 5xx error. Signal an error.\n err = new Error(url + ' HTTP status: ' + status);\n err.xhr = xhr;\n errback(err);\n } else {\n callback(xhr.responseText);\n }\n\n if (masterConfig.onXhrComplete) {\n masterConfig.onXhrComplete(xhr, url);\n }\n }\n };\n xhr.send(null);\n };\n } else if (masterConfig.env === 'rhino' || (!masterConfig.env &&\n typeof Packages !== 'undefined' && typeof java !== 'undefined')) {\n //Why Java, why is this so awkward?\n text.get = function (url, callback) {\n var stringBuffer, line,\n encoding = \"utf-8\",\n file = new java.io.File(url),\n lineSeparator = java.lang.System.getProperty(\"line.separator\"),\n input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),\n content = '';\n try {\n stringBuffer = new java.lang.StringBuffer();\n line = input.readLine();\n\n // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324\n // http://www.unicode.org/faq/utf_bom.html\n\n // Note that when we use utf-8, the BOM should appear as \"EF BB BF\", but it doesn't due to this bug in the JDK:\n // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058\n if (line && line.length() && line.charAt(0) === 0xfeff) {\n // Eat the BOM, since we've already found the encoding on this file,\n // and we plan to concatenating this buffer with others; the BOM should\n // only appear at the top of a file.\n line = line.substring(1);\n }\n\n if (line !== null) {\n stringBuffer.append(line);\n }\n\n while ((line = input.readLine()) !== null) {\n stringBuffer.append(lineSeparator);\n stringBuffer.append(line);\n }\n //Make sure we return a JavaScript string and not a Java string.\n content = String(stringBuffer.toString()); //String\n } finally {\n input.close();\n }\n callback(content);\n };\n } else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&\n typeof Components !== 'undefined' && Components.classes &&\n Components.interfaces)) {\n //Avert your gaze!\n Cc = Components.classes,\n Ci = Components.interfaces;\n Components.utils['import']('resource://gre/modules/FileUtils.jsm');\n xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);\n\n text.get = function (url, callback) {\n var inStream, convertStream, fileObj,\n readData = {};\n\n if (xpcIsWindows) {\n url = url.replace(/\\//g, '\\\\');\n }\n\n fileObj = new FileUtils.File(url);\n\n //XPCOM, you so crazy\n try {\n inStream = Cc['@mozilla.org/network/file-input-stream;1']\n .createInstance(Ci.nsIFileInputStream);\n inStream.init(fileObj, 1, 0, false);\n\n convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']\n .createInstance(Ci.nsIConverterInputStream);\n convertStream.init(inStream, \"utf-8\", inStream.available(),\n Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);\n\n convertStream.readString(inStream.available(), readData);\n convertStream.close();\n inStream.close();\n callback(readData.value);\n } catch (e) {\n throw new Error((fileObj && fileObj.path || '') + ': ' + e);\n }\n };\n }\n return text;\n});\n\n","\ndefine('text!app/sample.txt',[],function () { return 'sample\\n\\n';});\n\n","/**\n * Module A\n */\ndefine('app/a',{\n name: 'a',\n doSomething: function (name) {\n console.log('starting doSomething');\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","define('app/main',['require','text!./sample.txt','./a'],function (require) {\n var text = require('text!./sample.txt'),\n a = require('./a');\n\n return {\n name: 'main',\n a: a,\n text: text \n };\n});\n\n\n","require.config({\n baseUrl: 'js/lib',\n paths: {\n app: '../app',\n text: 'text/text'\n }\n});\n\n/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['app/main'], function (main) {\n console.log('in top level callback');\n console.log(main.a.doSomething('world'));\n console.log('finished top level callback');\n});\n\ndefine(\"app\", function(){});\n\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/expected-main-built.js.map b/build/tests/lib/sourcemapSingle/expected-main-built.js.map index 0b7965c9..72b80917 100644 --- a/build/tests/lib/sourcemapSingle/expected-main-built.js.map +++ b/build/tests/lib/sourcemapSingle/expected-main-built.js.map @@ -1 +1 @@ -{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n\n"]} \ No newline at end of file +{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":["define","name","doSomething","console","log","require","a","b"],"mappings":"AAGAA,OAAA,KACAC,KAAA,IACAC,YAAA,SAAAD,GACAE,QAAAC,IAAA,SAAAH,MAGAE,QAAAC,IAAA,aCNAJ,OAAA,OAAA,WACA,GAAAC,GAAA,GACA,QACAA,KAAAA,KCHAI,SAAA,IAAA,KAAA,SAAAC,EAAAC,GACAJ,QAAAC,IAAA,oBACAE,EAAAJ,YAAA,SACAC,QAAAC,IAAA,WAAAG,EAAAN,QAGAD,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n\n"]} \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/main-built.js b/build/tests/lib/sourcemapSingle/main-built.js index 735d9197..d14a04e2 100644 --- a/build/tests/lib/sourcemapSingle/main-built.js +++ b/build/tests/lib/sourcemapSingle/main-built.js @@ -1,2 +1,3 @@ define("a",{name:"a",doSomething:function(e){console.log("Hello "+e)}}),console.log("a is done"),define("b",[],function(){var e="b";return{name:e}}),require(["a","b"],function(e,n){console.log("a message below:"),e.doSomething("world"),console.log("b name: "+n.name)}),define("main",function(){}); +//# sourceMappingURL=main-built.js //# sourceMappingURL=main-built.js.map \ No newline at end of file diff --git a/build/tests/lib/sourcemapSingle/main-built.js.map b/build/tests/lib/sourcemapSingle/main-built.js.map index 0b7965c9..72b80917 100644 --- a/build/tests/lib/sourcemapSingle/main-built.js.map +++ b/build/tests/lib/sourcemapSingle/main-built.js.map @@ -1 +1 @@ -{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":[],"mappings":"AAGA,OAAA,KACA,KAAA,IACA,YAAA,SAAA,GACA,QAAA,IAAA,SAAA,MAGA,QAAA,IAAA,aCNA,OAAA,OAAA,WACA,GAAA,GAAA,GACA,QACA,KAAA,KCHA,SAAA,IAAA,KAAA,SAAA,EAAA,GACA,QAAA,IAAA,oBACA,EAAA,YAAA,SACA,QAAA,IAAA,WAAA,EAAA,QAGA,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n\n"]} \ No newline at end of file +{"version":3,"file":"main-built.js","sources":["a.js","b.js","main.js"],"names":["define","name","doSomething","console","log","require","a","b"],"mappings":"AAGAA,OAAA,KACAC,KAAA,IACAC,YAAA,SAAAD,GACAE,QAAAC,IAAA,SAAAH,MAGAE,QAAAC,IAAA,aCNAJ,OAAA,OAAA,WACA,GAAAC,GAAA,GACA,QACAA,KAAAA,KCHAI,SAAA,IAAA,KAAA,SAAAC,EAAAC,GACAJ,QAAAC,IAAA,oBACAE,EAAAJ,YAAA,SACAC,QAAAC,IAAA,WAAAG,EAAAN,QAGAD,OAAA,OAAA","sourcesContent":["/**\n * Module A\n */\ndefine('a',{\n name: 'a',\n doSomething: function (name) {\n console.log('Hello ' + name);\n }\n});\nconsole.log('a is done');\n\n","/**\n * Module B\n */\ndefine('b',[],function () {\n var name = 'b';\n return {\n name: name\n };\n});\n\n","/**\n * A test of source maps on a concatenated, but not minified file.\n */\nrequire(['a', 'b'], function (a, b) {\n console.log('a message below:');\n a.doSomething('world');\n console.log('b name: ' + b.name);\n});\n\ndefine(\"main\", function(){});\n\n"]} \ No newline at end of file From b62d7e43037e2baafb26d6bb031fb3df20cad5b0 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 8 Feb 2015 13:43:03 -0800 Subject: [PATCH 217/382] snapshot --- dist/r.js | 523 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 412 insertions(+), 111 deletions(-) diff --git a/dist/r.js b/dist/r.js index f9fb7371..f6b39f54 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15+ Sat, 07 Feb 2015 19:35:38 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Sun, 08 Feb 2015 21:42:36 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15+ Sat, 07 Feb 2015 19:35:38 GMT', + version = '2.1.15+ Sun, 08 Feb 2015 21:42:36 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -14588,6 +14588,9 @@ define('source-map/source-map-generator', function (require, exports, module) { aSourceMapConsumer.sources.forEach(function (sourceFile) { var content = aSourceMapConsumer.sourceContentFor(sourceFile); if (content) { + if (aSourceMapPath) { + sourceFile = util.join(aSourceMapPath, sourceFile); + } if (sourceRoot) { sourceFile = util.relative(sourceRoot, sourceFile); } @@ -14766,6 +14769,13 @@ define('source-map/source-node', function (require, exports, module) { var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; var util = require('./util'); + // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other + // operating systems these days (capturing the result). + var REGEX_NEWLINE = /(\r?\n)/g; + + // Matches a Windows-style newline, or any character. + var REGEX_CHARACTER = /\r\n|[\s\S]/g; + /** * SourceNodes provide a way to abstract over interpolating/concatenating * snippets of generated JavaScript source code while maintaining the line and @@ -14800,9 +14810,17 @@ define('source-map/source-node', function (require, exports, module) { // and the SourceMap var node = new SourceNode(); - // The generated code - // Processed fragments are removed from this array. - var remainingLines = aGeneratedCode.split('\n'); + // All even indices of this array are one line of the generated code, + // while all odd indices are the newlines between two adjacent lines + // (since `REGEX_NEWLINE` captures its match). + // Processed fragments are removed from this array, by calling `shiftNextLine`. + var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); + var shiftNextLine = function() { + var lineContents = remainingLines.shift(); + // The last line of a file might not have a newline. + var newLine = remainingLines.shift() || ""; + return lineContents + newLine; + }; // We need to remember the position of "remainingLines" var lastGeneratedLine = 1, lastGeneratedColumn = 0; @@ -14819,7 +14837,7 @@ define('source-map/source-node', function (require, exports, module) { if (lastGeneratedLine < mapping.generatedLine) { var code = ""; // Associate first line with "lastMapping" - addMappingWithCode(lastMapping, remainingLines.shift() + "\n"); + addMappingWithCode(lastMapping, shiftNextLine()); lastGeneratedLine++; lastGeneratedColumn = 0; // The remaining code is added without mapping @@ -14843,7 +14861,7 @@ define('source-map/source-node', function (require, exports, module) { // to the SourceNode without any mapping. // Each line is added as separate string. while (lastGeneratedLine < mapping.generatedLine) { - node.add(remainingLines.shift() + "\n"); + node.add(shiftNextLine()); lastGeneratedLine++; } if (lastGeneratedColumn < mapping.generatedColumn) { @@ -14858,12 +14876,10 @@ define('source-map/source-node', function (require, exports, module) { if (remainingLines.length > 0) { if (lastMapping) { // Associate the remaining code in the current line with "lastMapping" - var lastLine = remainingLines.shift(); - if (remainingLines.length > 0) lastLine += "\n"; - addMappingWithCode(lastMapping, lastLine); + addMappingWithCode(lastMapping, shiftNextLine()); } // and add the remaining lines without any mapping - node.add(remainingLines.join("\n")); + node.add(remainingLines.join("")); } // Copy sourcesContent into SourceNode @@ -15102,8 +15118,8 @@ define('source-map/source-node', function (require, exports, module) { lastOriginalSource = null; sourceMappingActive = false; } - chunk.split('').forEach(function (ch, idx, array) { - if (ch === '\n') { + chunk.match(REGEX_CHARACTER).forEach(function (ch, idx, array) { + if (REGEX_NEWLINE.test(ch)) { generated.line++; generated.column = 0; // Mappings end at eol @@ -15125,7 +15141,7 @@ define('source-map/source-node', function (require, exports, module) { }); } } else { - generated.column++; + generated.column += ch.length; } }); }); @@ -16056,10 +16072,10 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", { var parameters = []; arg_parameter_pairs.forEach(function(pair) { - var split = pair.split(":"); + var splitAt = pair.lastIndexOf(":"); - args.push(split[0]); - parameters.push(split[1]); + args.push(pair.substr(0, splitAt)); + parameters.push(pair.substr(splitAt + 1)); }); var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")"; @@ -16914,14 +16930,7 @@ function is_identifier_char(ch) { }; function is_identifier_string(str){ - var i = str.length; - if (i == 0) return false; - if (!is_identifier_start(str.charCodeAt(0))) return false; - while (--i >= 0) { - if (!is_identifier_char(str.charAt(i))) - return false; - } - return true; + return /^[a-z_$][a-z0-9_$]*$/i.test(str); }; function parse_js_number(num) { @@ -17362,6 +17371,7 @@ function parse($TEXT, options) { toplevel : null, expression : false, html5_comments : true, + bare_returns : false, }); var S = { @@ -17541,7 +17551,7 @@ function parse($TEXT, options) { return if_(); case "return": - if (S.in_function == 0) + if (S.in_function == 0 && !options.bare_returns) croak("'return' outside of function"); return new AST_Return({ value: ( is("punc", ";") @@ -18955,6 +18965,7 @@ AST_Toplevel.DEFMETHOD("scope_warnings", function(options){ } if (options.unreferenced && (node instanceof AST_SymbolDeclaration || node instanceof AST_Label) + && !(node instanceof AST_SymbolCatch) && node.unreferenced()) { AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", { type: node instanceof AST_Label ? "Label" : "Symbol", @@ -19425,7 +19436,13 @@ function OutputStream(options) { /* -----[ PARENTHESES ]----- */ function PARENS(nodetype, func) { - nodetype.DEFMETHOD("needs_parens", func); + if (Array.isArray(nodetype)) { + nodetype.forEach(function(nodetype){ + PARENS(nodetype, func); + }); + } else { + nodetype.DEFMETHOD("needs_parens", func); + } }; PARENS(AST_Node, function(){ @@ -19444,7 +19461,7 @@ function OutputStream(options) { return first_in_statement(output); }); - PARENS(AST_Unary, function(output){ + PARENS([ AST_Unary, AST_Undefined ], function(output){ var p = output.parent(); return p instanceof AST_PropAccess && p.expression === this; }); @@ -19540,7 +19557,7 @@ function OutputStream(options) { return true; }); - function assign_and_conditional_paren_rules(output) { + PARENS([ AST_Assign, AST_Conditional ], function (output){ var p = output.parent(); // !(a = false) → true if (p instanceof AST_Unary) @@ -19557,10 +19574,7 @@ function OutputStream(options) { // (a = foo)["prop"] —or— (a = foo).prop if (p instanceof AST_PropAccess && p.expression === this) return true; - }; - - PARENS(AST_Assign, assign_and_conditional_paren_rules); - PARENS(AST_Conditional, assign_and_conditional_paren_rules); + }); /* -----[ PRINTERS ]----- */ @@ -19647,7 +19661,7 @@ function OutputStream(options) { output.print("for"); output.space(); output.with_parens(function(){ - if (self.init) { + if (self.init && !(self.init instanceof AST_EmptyStatement)) { if (self.init instanceof AST_Definitions) { self.init.print(output); } else { @@ -19987,8 +20001,12 @@ function OutputStream(options) { DEFPRINT(AST_UnaryPrefix, function(self, output){ var op = self.operator; output.print(op); - if (/^[a-z]/i.test(op)) + if (/^[a-z]/i.test(op) + || (/[+-]$/.test(op) + && self.expression instanceof AST_UnaryPrefix + && /^[+-]/.test(self.expression.operator))) { output.space(); + } self.expression.print(output); }); DEFPRINT(AST_UnaryPostfix, function(self, output){ @@ -21067,6 +21085,14 @@ merge(Compressor.prototype, { if (d && d.constant && d.init) return ev(d.init, compressor); throw def; }); + def(AST_Dot, function(compressor){ + if (compressor.option("unsafe") && this.property == "length") { + var str = ev(this.expression, compressor); + if (typeof str == "string") + return str.length; + } + throw def; + }); })(function(node, func){ node.DEFMETHOD("_eval", func); }); @@ -21181,7 +21207,9 @@ merge(Compressor.prototype, { || this.operator == "--" || this.expression.has_side_effects(compressor); }); - def(AST_SymbolRef, function(compressor){ return false }); + def(AST_SymbolRef, function(compressor){ + return this.global() && this.undeclared(); + }); def(AST_Object, function(compressor){ for (var i = this.properties.length; --i >= 0;) if (this.properties[i].has_side_effects(compressor)) @@ -22029,6 +22057,7 @@ merge(Compressor.prototype, { } catch(ex) { if (ex !== ast) throw ex; }; + if (!fun) return self; var args = fun.argnames.map(function(arg, i){ return make_node(AST_String, self.args[i], { value: arg.print_to_string() @@ -22604,6 +22633,17 @@ merge(Compressor.prototype, { alternative: alternative }); } + // x=y?1:1 --> x=1 + if (consequent instanceof AST_Constant + && alternative instanceof AST_Constant + && consequent.equivalent_to(alternative)) { + if (self.condition.has_side_effects(compressor)) { + return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent.value, self)]); + } else { + return make_node_from_constant(compressor, consequent.value, self); + + } + } return self; }); @@ -22641,7 +22681,7 @@ merge(Compressor.prototype, { return make_node(AST_Dot, self, { expression : self.expression, property : prop - }); + }).optimize(compressor); } var v = parseFloat(prop); if (!isNaN(v) && v.toString() == prop) { @@ -22653,6 +22693,19 @@ merge(Compressor.prototype, { return self; }); + OPT(AST_Dot, function(self, compressor){ + var prop = self.property; + if (RESERVED_WORDS(prop) && !compressor.option("screw_ie8")) { + return make_node(AST_Sub, self, { + expression : self.expression, + property : make_node(AST_String, self, { + value: prop + }) + }).optimize(compressor); + } + return self.evaluate(compressor)[0]; + }); + function literals_in_boolean_context(self, compressor) { if (compressor.option("booleans") && compressor.in_boolean_context()) { return make_node(AST_True, self); @@ -22737,7 +22790,7 @@ function SourceMap(options) { source = info.source; orig_line = info.line; orig_col = info.column; - name = info.name; + name = info.name || name; } generator.addMapping({ generated : { line: gen_line + options.dest_line_diff, column: gen_col }, @@ -22801,53 +22854,68 @@ function SourceMap(options) { (function(){ var MOZ_TO_ME = { - TryStatement : function(M) { + ExpressionStatement: function(M) { + var expr = M.expression; + if (expr.type === "Literal" && typeof expr.value === "string") { + return new AST_Directive({ + start: my_start_token(M), + end: my_end_token(M), + value: expr.value + }); + } + return new AST_SimpleStatement({ + start: my_start_token(M), + end: my_end_token(M), + body: from_moz(expr) + }); + }, + TryStatement: function(M) { + var handlers = M.handlers || [M.handler]; + if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) { + throw new Error("Multiple catch clauses are not supported."); + } return new AST_Try({ start : my_start_token(M), end : my_end_token(M), body : from_moz(M.block).body, - bcatch : from_moz(M.handlers[0]), + bcatch : from_moz(handlers[0]), bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null }); }, - CatchClause : function(M) { - return new AST_Catch({ - start : my_start_token(M), - end : my_end_token(M), - argname : from_moz(M.param), - body : from_moz(M.body).body - }); + Property: function(M) { + var key = M.key; + var name = key.type == "Identifier" ? key.name : key.value; + var args = { + start : my_start_token(key), + end : my_end_token(M.value), + key : name, + value : from_moz(M.value) + }; + switch (M.kind) { + case "init": + return new AST_ObjectKeyVal(args); + case "set": + args.value.name = from_moz(key); + return new AST_ObjectSetter(args); + case "get": + args.value.name = from_moz(key); + return new AST_ObjectGetter(args); + } }, - ObjectExpression : function(M) { + ObjectExpression: function(M) { return new AST_Object({ start : my_start_token(M), end : my_end_token(M), properties : M.properties.map(function(prop){ - var key = prop.key; - var name = key.type == "Identifier" ? key.name : key.value; - var args = { - start : my_start_token(key), - end : my_end_token(prop.value), - key : name, - value : from_moz(prop.value) - }; - switch (prop.kind) { - case "init": - return new AST_ObjectKeyVal(args); - case "set": - args.value.name = from_moz(key); - return new AST_ObjectSetter(args); - case "get": - args.value.name = from_moz(key); - return new AST_ObjectGetter(args); - } + prop.type = "Property"; + return from_moz(prop) }) }); }, - SequenceExpression : function(M) { + SequenceExpression: function(M) { return AST_Seq.from_array(M.expressions.map(from_moz)); }, - MemberExpression : function(M) { + MemberExpression: function(M) { return new (M.computed ? AST_Sub : AST_Dot)({ start : my_start_token(M), end : my_end_token(M), @@ -22855,7 +22923,7 @@ function SourceMap(options) { expression : from_moz(M.object) }); }, - SwitchCase : function(M) { + SwitchCase: function(M) { return new (M.test ? AST_Case : AST_Default)({ start : my_start_token(M), end : my_end_token(M), @@ -22863,7 +22931,14 @@ function SourceMap(options) { body : M.consequent.map(from_moz) }); }, - Literal : function(M) { + VariableDeclaration: function(M) { + return new (M.kind === "const" ? AST_Const : AST_Var)({ + start : my_start_token(M), + end : my_end_token(M), + definitions : M.declarations.map(from_moz) + }); + }, + Literal: function(M) { var val = M.value, args = { start : my_start_token(M), end : my_end_token(M) @@ -22883,12 +22958,9 @@ function SourceMap(options) { return new AST_RegExp(args); } }, - UnaryExpression: From_Moz_Unary, - UpdateExpression: From_Moz_Unary, Identifier: function(M) { var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; - return new (M.name == "this" ? AST_This - : p.type == "LabeledStatement" ? AST_Label + return new ( p.type == "LabeledStatement" ? AST_Label : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar) : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) @@ -22902,7 +22974,8 @@ function SourceMap(options) { } }; - function From_Moz_Unary(M) { + MOZ_TO_ME.UpdateExpression = + MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) { var prefix = "prefix" in M ? M.prefix : M.type == "UnaryExpression" ? true : false; return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ @@ -22913,14 +22986,9 @@ function SourceMap(options) { }); }; - var ME_TO_MOZ = {}; - - map("Node", AST_Node); map("Program", AST_Toplevel, "body@body"); - map("Function", AST_Function, "id>name, params@argnames, body%body"); map("EmptyStatement", AST_EmptyStatement); map("BlockStatement", AST_BlockStatement, "body@body"); - map("ExpressionStatement", AST_SimpleStatement, "expression>body"); map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative"); map("LabeledStatement", AST_LabeledStatement, "label>label, body>body"); map("BreakStatement", AST_Break, "label>label"); @@ -22935,71 +23003,257 @@ function SourceMap(options) { map("ForInStatement", AST_ForIn, "left>init, right>object, body>body"); map("DebuggerStatement", AST_Debugger); map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body"); - map("VariableDeclaration", AST_Var, "declarations@definitions"); map("VariableDeclarator", AST_VarDef, "id>name, init>value"); + map("CatchClause", AST_Catch, "param>argname, body%body"); map("ThisExpression", AST_This); map("ArrayExpression", AST_Array, "elements@elements"); map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body"); map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); - map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right"); + map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); map("NewExpression", AST_New, "callee>expression, arguments@args"); map("CallExpression", AST_Call, "callee>expression, arguments@args"); + def_to_moz(AST_Directive, function To_Moz_Directive(M) { + return { + type: "ExpressionStatement", + expression: { + type: "Literal", + value: M.value + } + }; + }); + + def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) { + return { + type: "ExpressionStatement", + expression: to_moz(M.body) + }; + }); + + def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) { + return { + type: "SwitchCase", + test: to_moz(M.expression), + consequent: M.body.map(to_moz) + }; + }); + + def_to_moz(AST_Try, function To_Moz_TryStatement(M) { + return { + type: "TryStatement", + block: to_moz_block(M), + handler: to_moz(M.bcatch), + guardedHandlers: [], + finalizer: to_moz(M.bfinally) + }; + }); + + def_to_moz(AST_Catch, function To_Moz_CatchClause(M) { + return { + type: "CatchClause", + param: to_moz(M.argname), + guard: null, + body: to_moz_block(M) + }; + }); + + def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) { + return { + type: "VariableDeclaration", + kind: M instanceof AST_Const ? "const" : "var", + declarations: M.definitions.map(to_moz) + }; + }); + + def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) { + return { + type: "SequenceExpression", + expressions: M.to_array().map(to_moz) + }; + }); + + def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) { + var isComputed = M instanceof AST_Sub; + return { + type: "MemberExpression", + object: to_moz(M.expression), + computed: isComputed, + property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property} + }; + }); + + def_to_moz(AST_Unary, function To_Moz_Unary(M) { + return { + type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression", + operator: M.operator, + prefix: M instanceof AST_UnaryPrefix, + argument: to_moz(M.expression) + }; + }); + + def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) { + return { + type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression", + left: to_moz(M.left), + operator: M.operator, + right: to_moz(M.right) + }; + }); + + def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) { + return { + type: "ObjectExpression", + properties: M.properties.map(to_moz) + }; + }); + + def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) { + var key = ( + is_identifier(M.key) + ? {type: "Identifier", name: M.key} + : {type: "Literal", value: M.key} + ); + var kind; + if (M instanceof AST_ObjectKeyVal) { + kind = "init"; + } else + if (M instanceof AST_ObjectGetter) { + kind = "get"; + } else + if (M instanceof AST_ObjectSetter) { + kind = "set"; + } + return { + type: "Property", + kind: kind, + key: key, + value: to_moz(M.value) + }; + }); + + def_to_moz(AST_Symbol, function To_Moz_Identifier(M) { + var def = M.definition(); + return { + type: "Identifier", + name: def ? def.mangled_name || def.name : M.name + }; + }); + + def_to_moz(AST_Constant, function To_Moz_Literal(M) { + var value = M.value; + if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) { + return { + type: "UnaryExpression", + operator: "-", + prefix: true, + argument: { + type: "Literal", + value: -value + } + }; + } + return { + type: "Literal", + value: value + }; + }); + + def_to_moz(AST_Atom, function To_Moz_Atom(M) { + return { + type: "Identifier", + name: String(M.value) + }; + }); + + AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); + AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); + AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null }); + + AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast); + AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast); + /* -----[ tools ]----- */ function my_start_token(moznode) { + var loc = moznode.loc; + var range = moznode.range; return new AST_Token({ - file : moznode.loc && moznode.loc.source, - line : moznode.loc && moznode.loc.start.line, - col : moznode.loc && moznode.loc.start.column, - pos : moznode.start, - endpos : moznode.start + file : loc && loc.source, + line : loc && loc.start.line, + col : loc && loc.start.column, + pos : range ? range[0] : moznode.start, + endpos : range ? range[0] : moznode.start }); }; function my_end_token(moznode) { + var loc = moznode.loc; + var range = moznode.range; return new AST_Token({ - file : moznode.loc && moznode.loc.source, - line : moznode.loc && moznode.loc.end.line, - col : moznode.loc && moznode.loc.end.column, - pos : moznode.end, - endpos : moznode.end + file : loc && loc.source, + line : loc && loc.end.line, + col : loc && loc.end.column, + pos : range ? range[1] : moznode.end, + endpos : range ? range[1] : moznode.end }); }; function map(moztype, mytype, propmap) { var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; - moz_to_me += "return new mytype({\n" + + moz_to_me += "return new " + mytype.name + "({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)"; + var me_to_moz = "function To_Moz_" + moztype + "(M){\n"; + me_to_moz += "return {\n" + + "type: " + JSON.stringify(moztype); + if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){ var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop); if (!m) throw new Error("Can't understand property map: " + prop); - var moz = "M." + m[1], how = m[2], my = m[3]; + var moz = m[1], how = m[2], my = m[3]; moz_to_me += ",\n" + my + ": "; - if (how == "@") { - moz_to_me += moz + ".map(from_moz)"; - } else if (how == ">") { - moz_to_me += "from_moz(" + moz + ")"; - } else if (how == "=") { - moz_to_me += moz; - } else if (how == "%") { - moz_to_me += "from_moz(" + moz + ").body"; - } else throw new Error("Can't understand operator in propmap: " + prop); + me_to_moz += ",\n" + moz + ": "; + switch (how) { + case "@": + moz_to_me += "M." + moz + ".map(from_moz)"; + me_to_moz += "M." + my + ".map(to_moz)"; + break; + case ">": + moz_to_me += "from_moz(M." + moz + ")"; + me_to_moz += "to_moz(M." + my + ")"; + break; + case "=": + moz_to_me += "M." + moz; + me_to_moz += "M." + my; + break; + case "%": + moz_to_me += "from_moz(M." + moz + ").body"; + me_to_moz += "to_moz_block(M)"; + break; + default: + throw new Error("Can't understand operator in propmap: " + prop); + } }); - moz_to_me += "\n})}"; - // moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); - // console.log(moz_to_me); + moz_to_me += "\n})\n}"; + me_to_moz += "\n}\n}"; - moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( - mytype, my_start_token, my_end_token, from_moz + //moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); + //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true }); + //console.log(moz_to_me); + + moz_to_me = new Function("my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( + my_start_token, my_end_token, from_moz + ); + me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")( + to_moz, to_moz_block ); - return MOZ_TO_ME[moztype] = moz_to_me; + MOZ_TO_ME[moztype] = moz_to_me; + def_to_moz(mytype, me_to_moz); }; var FROM_MOZ_STACK = null; @@ -23019,6 +23273,48 @@ function SourceMap(options) { return ast; }; + function moz_sub_loc(token) { + return token.line ? { + line: token.line, + column: token.col + } : null; + }; + + function set_moz_loc(mynode, moznode) { + var start = mynode.start; + var end = mynode.end; + if (start.pos != null && end.pos != null) { + moznode.range = [start.pos, end.pos]; + } + if (start.line) { + moznode.loc = { + start: moz_sub_loc(start), + end: moz_sub_loc(end) + }; + if (start.file) { + moznode.loc.source = start.file; + } + } + return moznode; + }; + + function def_to_moz(mytype, handler) { + mytype.DEFMETHOD("to_mozilla_ast", function() { + return set_moz_loc(this, handler(this)); + }); + }; + + function to_moz(node) { + return node != null ? node.to_mozilla_ast() : null; + }; + + function to_moz_block(node) { + return { + type: "BlockStatement", + body: node.body.map(to_moz) + }; + }; + })(); AST_Node.warn_function = function(txt) { logger.error("uglifyjs2 WARN: " + txt); }; @@ -23088,7 +23384,7 @@ exports.minify = function(files, options, name) { if (options.sourceMapIncludeSources) { for (var file in sourcesContent) { if (sourcesContent.hasOwnProperty(file)) { - options.source_map.get().setSourceContent(file, sourcesContent[file]); + output.source_map.get().setSourceContent(file, sourcesContent[file]); } } } @@ -23099,6 +23395,11 @@ exports.minify = function(files, options, name) { } var stream = OutputStream(output); toplevel.print(stream); + + if(options.outSourceMap){ + stream += "\n//# sourceMappingURL=" + options.outSourceMap; + } + return { code : stream + "", map : output.source_map + "" @@ -28370,7 +28671,7 @@ function (args, quit, logger, build) { } else if (commandOption === 'v') { console.log('r.js: ' + version + ', RequireJS: ' + this.requirejsVars.require.version + - ', UglifyJS2: 2.4.13, UglifyJS: 1.3.4'); + ', UglifyJS2: 2.4.16, UglifyJS: 1.3.4'); } else if (commandOption === 'convert') { loadLib(); From 1271aa77232ba0b5e64d3c114a88a6b0a91dfc9a Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 8 Feb 2015 14:02:21 -0800 Subject: [PATCH 218/382] Relates to #740, how to run in nashorn --- README.md | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e9dded45..42d06fce 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ the RequireJS implementation of AMD. r.js is a single script that has two major functions: -* Run AMD-based projects [in Node](http://requirejs.org/docs/node.html) and Rhino. +* Run AMD-based projects [in Node](http://requirejs.org/docs/node.html) and Nashorn, Rhino and xpcshell. * Includes the [RequireJS Optimizer](http://requirejs.org/docs/optimization.html) that combines scripts for optimal browser delivery. @@ -21,7 +21,7 @@ that combines scripts for optimal browser delivery. From then on, you can use `r.js` on the command line to run the optimizer. -## Rhino/Browser +## Nashorn/Rhino/Browser Download the latest release from the [RequireJS download page](http://requirejs.org/docs/download.html#rjs). @@ -66,7 +66,32 @@ r.js allows using Node modules installed via npm. For more info see the ## Java -Java requires some JAR files in the CLASSPATH for it to work: +### Nashorn + +As of r.js 2.1.16, r.js can run in [Nashorn](http://www.oracle.com/technetwork/articles/java/jf14-nashorn-2126515.html), Java 8+'s JavaScript engine, via the `jjs` command line tool that is installed with Java. + +Then general format of the command: + +``` +jjs -scripting path/to/r.js -- [r.js command line arguments here] +``` + +Examples: + +``` +# Calling r.js to optimize a project using the build config in build.js +jjs -scripting path/to/r.js -- -o build.js + +# Calling r.js to run AMD modules, where the main app program is main.js +jjs -scripting path/to/r.js -- main.js + +``` + +All further examples will use the Node notation, but substitute the **r.js** references below with the command line structure mentioned above (`jjs -scripting path/to/r.js -- `). + +### Rhino + +Using Rhino requires some JAR files in the CLASSPATH for it to work: * [rhino.jar](https://github.com/jrburke/r.js/blob/master/lib/rhino/js.jar?raw=true) from the [Rhino project](http://www.mozilla.org/rhino/). * [compiler.jar](https://github.com/jrburke/r.js/blob/master/lib/closure/compiler.jar?raw=true) if you are using the optimizer and want to use @@ -87,7 +112,7 @@ If you want to run it in the debugger, replace org.mozilla.javascript.tools.shell.Main with **org.mozilla.javascript.tools.debugger.Main**. -All further examples will use the Node notation, but substitute **r.js** in the commands with the appropriate java command. +All further examples will use the Node notation, but substitute the **r.js** references below with the appropriate java command. ## xpcshell From 389854ea0ed0a230a7895faec38f5f8cd40c7448 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 8 Feb 2015 17:21:33 -0800 Subject: [PATCH 219/382] Fixes #725, write adapter modules for multisegment package IDs --- build/jslib/build.js | 32 +++++++++++++++++--------------- build/tests/builds.js | 21 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/build/jslib/build.js b/build/jslib/build.js index 97993641..c6732589 100644 --- a/build/jslib/build.js +++ b/build/jslib/build.js @@ -1687,12 +1687,13 @@ define(function (require) { return prim().start(function () { var reqIndex, currContents, fileForSourceMap, - moduleName, shim, packageMain, packageName, + moduleName, shim, packageName, parts, builder, writeApi, namespace, namespaceWithDot, stubModulesByName, context = layer.context, onLayerEnds = [], - onLayerEndAdded = {}; + onLayerEndAdded = {}, + pkgsMainMap = {}; //Use override settings, particularly for pragmas //Do this before the var readings since it reads config values. @@ -1734,6 +1735,13 @@ define(function (require) { }); } + //Create a reverse lookup for packages main module IDs to their package + //names, useful for knowing when to write out define() package main ID + //adapters. + lang.eachProp(layer.context.config.pkgs, function(value, prop) { + pkgsMainMap[value] = prop; + }); + //Write the built module to disk, and build up the build output. fileContents = config.wrap ? config.wrap.start : ""; return prim.serial(layer.buildFilePaths.map(function (path) { @@ -1742,16 +1750,10 @@ define(function (require) { singleContents = ''; moduleName = layer.buildFileToModule[path]; - packageName = moduleName.split('/').shift(); - - //If the moduleName is for a package main, then update it to the - //real main value. - packageMain = layer.context.config.pkgs && - getOwn(layer.context.config.pkgs, packageName); - if (packageMain !== moduleName) { - // Not a match, clear packageMain - packageMain = undefined; - } + + //If the moduleName is a package main, then hold on to the + //packageName in case an adapter needs to be written. + packageName = getOwn(pkgsMainMap, moduleName); return prim().start(function () { //Figure out if the module is a result of a build plugin, and if so, @@ -1813,7 +1815,7 @@ define(function (require) { currContents = config.onBuildRead(moduleName, path, currContents); } - if (packageMain) { + if (packageName) { hasPackageName = (packageName === parse.getNamedDefine(currContents)); } @@ -1825,7 +1827,7 @@ define(function (require) { useSourceUrl: config.useSourceUrl }); - if (packageMain && !hasPackageName) { + if (packageName && !hasPackageName) { currContents = addSemiColon(currContents, config) + '\n'; currContents += namespaceWithDot + "define('" + packageName + "', ['" + moduleName + @@ -1854,7 +1856,7 @@ define(function (require) { //after the module is processed. //If we have a name, but no defined module, then add in the placeholder. if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) { - shim = config.shim && (getOwn(config.shim, moduleName) || (packageMain && getOwn(config.shim, moduleName) || getOwn(config.shim, packageName))); + shim = config.shim && (getOwn(config.shim, moduleName) || (packageName && getOwn(config.shim, packageName))); if (shim) { if (config.wrapShim) { singleContents = '(function(root) {\n' + diff --git a/build/tests/builds.js b/build/tests/builds.js index 15233be9..486b6e22 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -1739,6 +1739,27 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + + doh.register("packagesMultiLevel", + [ + function packagesMultiLevel(t) { + var startPath = "../../../requirejs/tests/packagesMultiLevel/", + builtPath = startPath + "packagesMultiLevel-tests-built.js"; + file.deleteFile(builtPath); + + build([startPath + "build.js"]); + + t.is(nol(c(startPath + "expected-built.js")), nol(c(builtPath))); + + //Reset require internal state for the contexts so future + //builds in these tests will work correctly. + require._buildReset(); + } + ] + ); + doh.run(); + + //Make sure pluginBuilder works. //https://github.com/jrburke/r.js/issues/175 doh.register("pluginBuilder", From f088e51377e50477af2252d3d3a54f24820aa156 Mon Sep 17 00:00:00 2001 From: jrburke Date: Sun, 8 Feb 2015 17:21:47 -0800 Subject: [PATCH 220/382] snapshot --- dist/r.js | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/dist/r.js b/dist/r.js index f6b39f54..11a86577 100644 --- a/dist/r.js +++ b/dist/r.js @@ -1,5 +1,5 @@ /** - * @license r.js 2.1.15+ Sun, 08 Feb 2015 21:42:36 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. + * @license r.js 2.1.15+ Mon, 09 Feb 2015 01:21:41 GMT Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved. * Available via the MIT or new BSD license. * see: http://github.com/jrburke/requirejs for details */ @@ -20,7 +20,7 @@ var requirejs, require, define, xpcUtil; (function (console, args, readFileFunc) { var fileName, env, fs, vm, path, exec, rhinoContext, dir, nodeRequire, nodeDefine, exists, reqMain, loadedOptimizedLib, existsForNode, Cc, Ci, - version = '2.1.15+ Sun, 08 Feb 2015 21:42:36 GMT', + version = '2.1.15+ Mon, 09 Feb 2015 01:21:41 GMT', jsSuffixRegExp = /\.js$/, commandOption = '', useLibLoaded = {}, @@ -28177,12 +28177,13 @@ define('build', function (require) { return prim().start(function () { var reqIndex, currContents, fileForSourceMap, - moduleName, shim, packageMain, packageName, + moduleName, shim, packageName, parts, builder, writeApi, namespace, namespaceWithDot, stubModulesByName, context = layer.context, onLayerEnds = [], - onLayerEndAdded = {}; + onLayerEndAdded = {}, + pkgsMainMap = {}; //Use override settings, particularly for pragmas //Do this before the var readings since it reads config values. @@ -28224,6 +28225,13 @@ define('build', function (require) { }); } + //Create a reverse lookup for packages main module IDs to their package + //names, useful for knowing when to write out define() package main ID + //adapters. + lang.eachProp(layer.context.config.pkgs, function(value, prop) { + pkgsMainMap[value] = prop; + }); + //Write the built module to disk, and build up the build output. fileContents = config.wrap ? config.wrap.start : ""; return prim.serial(layer.buildFilePaths.map(function (path) { @@ -28232,16 +28240,10 @@ define('build', function (require) { singleContents = ''; moduleName = layer.buildFileToModule[path]; - packageName = moduleName.split('/').shift(); - - //If the moduleName is for a package main, then update it to the - //real main value. - packageMain = layer.context.config.pkgs && - getOwn(layer.context.config.pkgs, packageName); - if (packageMain !== moduleName) { - // Not a match, clear packageMain - packageMain = undefined; - } + + //If the moduleName is a package main, then hold on to the + //packageName in case an adapter needs to be written. + packageName = getOwn(pkgsMainMap, moduleName); return prim().start(function () { //Figure out if the module is a result of a build plugin, and if so, @@ -28303,7 +28305,7 @@ define('build', function (require) { currContents = config.onBuildRead(moduleName, path, currContents); } - if (packageMain) { + if (packageName) { hasPackageName = (packageName === parse.getNamedDefine(currContents)); } @@ -28315,7 +28317,7 @@ define('build', function (require) { useSourceUrl: config.useSourceUrl }); - if (packageMain && !hasPackageName) { + if (packageName && !hasPackageName) { currContents = addSemiColon(currContents, config) + '\n'; currContents += namespaceWithDot + "define('" + packageName + "', ['" + moduleName + @@ -28344,7 +28346,7 @@ define('build', function (require) { //after the module is processed. //If we have a name, but no defined module, then add in the placeholder. if (moduleName && falseProp(layer.modulesWithNames, moduleName) && !config.skipModuleInsertion) { - shim = config.shim && (getOwn(config.shim, moduleName) || (packageMain && getOwn(config.shim, moduleName) || getOwn(config.shim, packageName))); + shim = config.shim && (getOwn(config.shim, moduleName) || (packageName && getOwn(config.shim, packageName))); if (shim) { if (config.wrapShim) { singleContents = '(function(root) {\n' + From 215255341e4f44d2a30122b886231f354a8eae62 Mon Sep 17 00:00:00 2001 From: jrburke Date: Mon, 9 Feb 2015 00:21:51 -0800 Subject: [PATCH 221/382] Fixes #733, detect unary function expression used for UMD wrappers --- .gitignore | 1 + build/jslib/parse.js | 24 +- build/tests/builds.js | 19 + build/tests/lib/umd2/build.js | 5 + build/tests/lib/umd2/emmet.js | 17441 ++++++++++++++++++++++++++++ build/tests/lib/umd2/expected.js | 17442 +++++++++++++++++++++++++++++ 6 files changed, 34923 insertions(+), 9 deletions(-) create mode 100644 build/tests/lib/umd2/build.js create mode 100644 build/tests/lib/umd2/emmet.js create mode 100644 build/tests/lib/umd2/expected.js diff --git a/.gitignore b/.gitignore index 63ba660e..b835a69c 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ build/tests/lib/stubModules/main-built.js build/tests/lib/stubModules/perModule/built build/tests/lib/transportBeforeMinify/www-built build/tests/lib/umd/main-built.js +build/tests/lib/umd2/built.js build/tests/lib/umdNested/main-built.js build/tests/lib/unicode/main-built.js build/tests/lib/urlToEmpty/main-built.js diff --git a/build/jslib/parse.js b/build/jslib/parse.js index d3525fef..160466f5 100644 --- a/build/jslib/parse.js +++ b/build/jslib/parse.js @@ -241,19 +241,25 @@ define(['./esprimaAdapter', 'lang'], function (esprima, lang) { //Build up a "scope" object that informs nested recurse calls if //the define call references an identifier that is likely a UMD //wrapped function expression argument. + //Catch (function(a) {... wrappers if (object.type === 'ExpressionStatement' && object.expression && object.expression.type === 'CallExpression' && object.expression.callee && object.expression.callee.type === 'FunctionExpression') { tempObject = object.expression.callee; - - if (tempObject.params && tempObject.params.length) { - params = tempObject.params; - fnExpScope = mixin({}, fnExpScope, true); - for (i = 0; i < params.length; i++) { - param = params[i]; - if (param.type === 'Identifier') { - fnExpScope[param.name] = true; - } + } + // Catch !function(a) {... wrappers + if (object.type === 'UnaryExpression' && object.argument && + object.argument.type === 'CallExpression' && object.argument.callee && + object.argument.callee.type === 'FunctionExpression') { + tempObject = object.argument.callee; + } + if (tempObject && tempObject.params && tempObject.params.length) { + params = tempObject.params; + fnExpScope = mixin({}, fnExpScope, true); + for (i = 0; i < params.length; i++) { + param = params[i]; + if (param.type === 'Identifier') { + fnExpScope[param.name] = true; } } } diff --git a/build/tests/builds.js b/build/tests/builds.js index 486b6e22..3a248656 100644 --- a/build/tests/builds.js +++ b/build/tests/builds.js @@ -2353,6 +2353,25 @@ define(['build', 'env!env/file', 'env', 'lang'], function (build, file, env, lan ); doh.run(); + //Detect !function(e) {... UMD wrappers + //https://github.com/jrburke/requirejs/issues/733 + doh.register("umd2", + [ + function umd2(t) { + file.deleteFile("lib/umd2/built.js"); + + build(["lib/umd2/build.js"]); + + t.is(nol(c("lib/umd2/expected.js")), + nol(c("lib/umd2/built.js"))); + + require._buildReset(); + } + + ] + ); + doh.run(); + //Do not not find nested deps in a UMD wrapper //https://github.com/jrburke/requirejs/issues/651 doh.register("umdNested", diff --git a/build/tests/lib/umd2/build.js b/build/tests/lib/umd2/build.js new file mode 100644 index 00000000..2f8f5cb9 --- /dev/null +++ b/build/tests/lib/umd2/build.js @@ -0,0 +1,5 @@ +{ + name: 'emmet', + out: 'built.js', + optimize: 'none' +} diff --git a/build/tests/lib/umd2/emmet.js b/build/tests/lib/umd2/emmet.js new file mode 100644 index 00000000..47a15b59 --- /dev/null +++ b/build/tests/lib/umd2/emmet.js @@ -0,0 +1,17441 @@ +!function(e){ + if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e(); + else if("function"==typeof define&&define.amd)define([],e); + else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.emmet=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;ofile module of IEmmetFile + * interface to be implemented. + * @memberOf bootstrap + */ + loadExtensions: function(fileList) { + var payload = {}; + var userSnippets = null; + var that = this; + + // make sure file list contians only valid extension files + fileList = fileList.filter(function(f) { + var ext = file.getExt(f); + return ext === 'json' || ext === 'js'; + }); + + var reader = (file.readText || file.read).bind(file); + var next = function() { + if (fileList.length) { + var f = fileList.shift(); + reader(f, function(err, content) { + if (err) { + logger.log('Unable to read "' + f + '" file: '+ err); + return next(); + } + + switch (file.getExt(f)) { + case 'js': + try { + eval(content); + } catch (e) { + logger.log('Unable to eval "' + f + '" file: '+ e); + } + break; + case 'json': + var fileName = getFileName(f).toLowerCase().replace(/\.json$/, ''); + if (/^snippets/.test(fileName)) { + if (fileName === 'snippets') { + // data in snippets.json is more important to user + userSnippets = utils.parseJSON(content); + } else { + payload.snippets = utils.deepMerge(payload.snippets || {}, utils.parseJSON(content)); + } + } else { + payload[fileName] = content; + } + + break; + } + + next(); + }); + } else { + // complete + if (userSnippets) { + payload.snippets = utils.deepMerge(payload.snippets || {}, userSnippets); + } + + that.loadUserData(payload); + } + }; + + next(); + }, + + /** + * Loads preferences from JSON object (or string representation of JSON) + * @param {Object} data + * @returns + */ + loadPreferences: function(data) { + preferences.load(utils.parseJSON(data)); + }, + + /** + * Loads user snippets and abbreviations. It doesn’t replace current + * user resource vocabulary but merges it with passed one. If you need + * to replaces user snippets you should call + * resetSnippets() method first + */ + loadSnippets: function(data) { + data = utils.parseJSON(data); + + var userData = resources.getVocabulary('user') || {}; + resources.setVocabulary(utils.deepMerge(userData, data), 'user'); + }, + + /** + * Helper function that loads default snippets, defined in project’s + * snippets.json + * @param {Object} data + */ + loadSystemSnippets: function(data) { + resources.setVocabulary(utils.parseJSON(data), 'system'); + }, + + /** + * Helper function that loads Can I Use database + * @param {Object} data + */ + loadCIU: function(data) { + ciu.load(utils.parseJSON(data)); + }, + + /** + * Removes all user-defined snippets + */ + resetSnippets: function() { + resources.setVocabulary({}, 'user'); + }, + + /** + * Helper function that loads all user data (snippets and preferences) + * defined as a single JSON object. This is useful for loading data + * stored in a common storage, for example NSUserDefaults + * @param {Object} data + */ + loadUserData: function(data) { + data = utils.parseJSON(data); + if (data.snippets) { + this.loadSnippets(data.snippets); + } + + if (data.preferences) { + this.loadPreferences(data.preferences); + } + + if (data.profiles) { + this.loadProfiles(data.profiles); + } + + if (data.caniuse) { + this.loadCIU(data.caniuse); + } + + var profiles = data.syntaxProfiles || data.syntaxprofiles; + if (profiles) { + this.loadSyntaxProfiles(profiles); + } + }, + + /** + * Resets all user-defined data: preferences, snippets etc. + * @returns + */ + resetUserData: function() { + this.resetSnippets(); + preferences.reset(); + profile.reset(); + }, + + /** + * Load syntax-specific output profiles. These are essentially + * an extension to syntax snippets + * @param {Object} profiles Dictionary of profiles + */ + loadSyntaxProfiles: function(profiles) { + profiles = utils.parseJSON(profiles); + var snippets = {}; + Object.keys(profiles).forEach(function(syntax) { + var options = profiles[syntax]; + if (!(syntax in snippets)) { + snippets[syntax] = {}; + } + snippets[syntax].profile = normalizeProfile(options); + }); + + this.loadSnippets(snippets); + }, + + /** + * Load named profiles + * @param {Object} profiles + */ + loadProfiles: function(profiles) { + profiles = utils.parseJSON(profiles); + Object.keys(profiles).forEach(function(name) { + profile.create(name, normalizeProfile(profiles[name])); + }); + }, + require: require, + + // expose some useful data for plugin authors + file: file, + preferences: preferences, + resources: resources, + profile: profile, + tabStops: require('./assets/tabStops'), + htmlMatcher: require('./assets/htmlMatcher'), + utils: { + common: utils, + action: require('./utils/action'), + editor: require('./utils/editor') + } + }; +}); +},{"./action/main":"action/main.js","./assets/caniuse":"assets/caniuse.js","./assets/htmlMatcher":"assets/htmlMatcher.js","./assets/logger":"assets/logger.js","./assets/preferences":"assets/preferences.js","./assets/profile":"assets/profile.js","./assets/resources":"assets/resources.js","./assets/tabStops":"assets/tabStops.js","./parser/abbreviation":"parser/abbreviation.js","./plugin/file":"plugin/file.js","./utils/action":"utils/action.js","./utils/common":"utils/common.js","./utils/editor":"utils/editor.js"}],"action/balance.js":[function(require,module,exports){ +/** + * HTML pair matching (balancing) actions + * @constructor + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var htmlMatcher = require('../assets/htmlMatcher'); + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var actionUtils = require('../utils/action'); + var range = require('../assets/range'); + var cssEditTree = require('../editTree/css'); + var cssSections = require('../utils/cssSections'); + var lastMatch = null; + + function last(arr) { + return arr[arr.length - 1]; + } + + function balanceHTML(editor, direction) { + var info = editorUtils.outputInfo(editor); + var content = info.content; + var sel = range(editor.getSelectionRange()); + + // validate previous match + if (lastMatch && !lastMatch.range.equal(sel)) { + lastMatch = null; + } + + if (lastMatch && sel.length()) { + if (direction == 'in') { + // user has previously selected tag and wants to move inward + if (lastMatch.type == 'tag' && !lastMatch.close) { + // unary tag was selected, can't move inward + return false; + } else { + if (lastMatch.range.equal(lastMatch.outerRange)) { + lastMatch.range = lastMatch.innerRange; + } else { + var narrowed = utils.narrowToNonSpace(content, lastMatch.innerRange); + lastMatch = htmlMatcher.find(content, narrowed.start + 1); + if (lastMatch && lastMatch.range.equal(sel) && lastMatch.outerRange.equal(sel)) { + lastMatch.range = lastMatch.innerRange; + } + } + } + } else { + if ( + !lastMatch.innerRange.equal(lastMatch.outerRange) + && lastMatch.range.equal(lastMatch.innerRange) + && sel.equal(lastMatch.range)) { + lastMatch.range = lastMatch.outerRange; + } else { + lastMatch = htmlMatcher.find(content, sel.start); + if (lastMatch && lastMatch.range.equal(sel) && lastMatch.innerRange.equal(sel)) { + lastMatch.range = lastMatch.outerRange; + } + } + } + } else { + lastMatch = htmlMatcher.find(content, sel.start); + } + + if (lastMatch) { + if (lastMatch.innerRange.equal(sel)) { + lastMatch.range = lastMatch.outerRange; + } + + if (!lastMatch.range.equal(sel)) { + editor.createSelection(lastMatch.range.start, lastMatch.range.end); + return true; + } + } + + lastMatch = null; + return false; + } + + function rangesForCSSRule(rule, pos) { + // find all possible ranges + var ranges = [rule.range(true)]; + + // braces content + ranges.push(rule.valueRange(true)); + + // find nested sections + var nestedSections = cssSections.nestedSectionsInRule(rule); + + // real content, e.g. from first property name to + // last property value + var items = rule.list(); + if (items.length || nestedSections.length) { + var start = Number.POSITIVE_INFINITY, end = -1; + if (items.length) { + start = items[0].namePosition(true); + end = last(items).range(true).end; + } + + if (nestedSections.length) { + if (nestedSections[0].start < start) { + start = nestedSections[0].start; + } + + if (last(nestedSections).end > end) { + end = last(nestedSections).end; + } + } + + ranges.push(range.create2(start, end)); + } + + ranges = ranges.concat(nestedSections); + + var prop = cssEditTree.propertyFromPosition(rule, pos) || items[0]; + if (prop) { + ranges.push(prop.range(true)); + var valueRange = prop.valueRange(true); + if (!prop.end()) { + valueRange._unterminated = true; + } + ranges.push(valueRange); + } + + return ranges; + } + + /** + * Returns all possible selection ranges for given caret position + * @param {String} content CSS content + * @param {Number} pos Caret position(where to start searching) + * @return {Array} + */ + function getCSSRanges(content, pos) { + var rule; + if (typeof content === 'string') { + var ruleRange = cssSections.matchEnclosingRule(content, pos); + if (ruleRange) { + rule = cssEditTree.parse(ruleRange.substring(content), { + offset: ruleRange.start + }); + } + } else { + // passed parsed CSS rule + rule = content; + } + + if (!rule) { + return null; + } + + // find all possible ranges + var ranges = rangesForCSSRule(rule, pos); + + // remove empty ranges + ranges = ranges.filter(function(item) { + return !!item.length; + }); + + return utils.unique(ranges, function(item) { + return item.valueOf(); + }); + } + + function balanceCSS(editor, direction) { + var info = editorUtils.outputInfo(editor); + var content = info.content; + var sel = range(editor.getSelectionRange()); + + var ranges = getCSSRanges(info.content, sel.start); + if (!ranges && sel.length()) { + // possible reason: user has already selected + // CSS rule from last match + try { + var rule = cssEditTree.parse(sel.substring(info.content), { + offset: sel.start + }); + ranges = getCSSRanges(rule, sel.start); + } catch(e) {} + } + + if (!ranges) { + return false; + } + + ranges = range.sort(ranges, true); + + // edge case: find match that equals current selection, + // in case if user moves inward after selecting full CSS rule + var bestMatch = utils.find(ranges, function(r) { + return r.equal(sel); + }); + + if (!bestMatch) { + bestMatch = utils.find(ranges, function(r) { + // Check for edge case: caret right after CSS value + // but it doesn‘t contains terminating semicolon. + // In this case we have to check full value range + return r._unterminated ? r.include(sel.start) : r.inside(sel.start); + }); + } + + if (!bestMatch) { + return false; + } + + // if best match equals to current selection, move index + // one position up or down, depending on direction + var bestMatchIx = ranges.indexOf(bestMatch); + if (bestMatch.equal(sel)) { + bestMatchIx += direction == 'out' ? 1 : -1; + } + + if (bestMatchIx < 0 || bestMatchIx >= ranges.length) { + if (bestMatchIx >= ranges.length && direction == 'out') { + pos = bestMatch.start - 1; + + var outerRanges = getCSSRanges(content, pos); + if (outerRanges) { + bestMatch = last(outerRanges.filter(function(r) { + return r.inside(pos); + })); + } + } else if (bestMatchIx < 0 && direction == 'in') { + bestMatch = null; + } else { + bestMatch = null; + } + } else { + bestMatch = ranges[bestMatchIx]; + } + + if (bestMatch) { + editor.createSelection(bestMatch.start, bestMatch.end); + return true; + } + + return false; + } + + return { + /** + * Find and select HTML tag pair + * @param {IEmmetEditor} editor Editor instance + * @param {String} direction Direction of pair matching: 'in' or 'out'. + * Default is 'out' + */ + balance: function(editor, direction) { + direction = String((direction || 'out').toLowerCase()); + var info = editorUtils.outputInfo(editor); + if (actionUtils.isSupportedCSS(info.syntax)) { + return balanceCSS(editor, direction); + } + + return balanceHTML(editor, direction); + }, + + balanceInwardAction: function(editor) { + return this.balance(editor, 'in'); + }, + + balanceOutwardAction: function(editor) { + return this.balance(editor, 'out'); + }, + + /** + * Moves caret to matching opening or closing tag + * @param {IEmmetEditor} editor + */ + goToMatchingPairAction: function(editor) { + var content = String(editor.getContent()); + var caretPos = editor.getCaretPos(); + + if (content.charAt(caretPos) == '<') + // looks like caret is outside of tag pair + caretPos++; + + var tag = htmlMatcher.tag(content, caretPos); + if (tag && tag.close) { // exclude unary tags + if (tag.open.range.inside(caretPos)) { + editor.setCaretPos(tag.close.range.start); + } else { + editor.setCaretPos(tag.open.range.start); + } + + return true; + } + + return false; + } + }; +}); +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../assets/range":"assets/range.js","../editTree/css":"editTree/css.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/cssSections":"utils/cssSections.js","../utils/editor":"utils/editor.js"}],"action/base64.js":[function(require,module,exports){ +/** + * Encodes/decodes image under cursor to/from base64 + * @param {IEmmetEditor} editor + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var file = require('../plugin/file'); + var base64 = require('../utils/base64'); + var actionUtils = require('../utils/action'); + var editorUtils = require('../utils/editor'); + + /** + * Test if text starts with token at pos + * position. If pos is omitted, search from beginning of text + * @param {String} token Token to test + * @param {String} text Where to search + * @param {Number} pos Position where to start search + * @return {Boolean} + * @since 0.65 + */ + function startsWith(token, text, pos) { + pos = pos || 0; + return text.charAt(pos) == token.charAt(0) && text.substr(pos, token.length) == token; + } + + /** + * Encodes image to base64 + * + * @param {IEmmetEditor} editor + * @param {String} imgPath Path to image + * @param {Number} pos Caret position where image is located in the editor + * @return {Boolean} + */ + function encodeToBase64(editor, imgPath, pos) { + var editorFile = editor.getFilePath(); + var defaultMimeType = 'application/octet-stream'; + + if (editorFile === null) { + throw "You should save your file before using this action"; + } + + // locate real image path + var realImgPath = file.locateFile(editorFile, imgPath); + if (realImgPath === null) { + throw "Can't find " + imgPath + ' file'; + } + + file.read(realImgPath, function(err, content) { + if (err) { + throw 'Unable to read ' + realImgPath + ': ' + err; + } + + var b64 = base64.encode(String(content)); + if (!b64) { + throw "Can't encode file content to base64"; + } + + b64 = 'data:' + (actionUtils.mimeTypes[String(file.getExt(realImgPath))] || defaultMimeType) + + ';base64,' + b64; + + editor.replaceContent('$0' + b64, pos, pos + imgPath.length); + }); + + return true; + } + + /** + * Decodes base64 string back to file. + * @param {IEmmetEditor} editor + * @param {String} data Base64-encoded file content + * @param {Number} pos Caret position where image is located in the editor + */ + function decodeFromBase64(editor, data, pos) { + // ask user to enter path to file + var filePath = String(editor.prompt('Enter path to file (absolute or relative)')); + if (!filePath) + return false; + + var absPath = file.createPath(editor.getFilePath(), filePath); + if (!absPath) { + throw "Can't save file"; + } + + file.save(absPath, base64.decode( data.replace(/^data\:.+?;.+?,/, '') )); + editor.replaceContent('$0' + filePath, pos, pos + data.length); + return true; + } + + return { + /** + * Action to encode or decode file to data:url + * @param {IEmmetEditor} editor Editor instance + * @param {String} syntax Current document syntax + * @param {String} profile Output profile name + * @return {Boolean} + */ + encodeDecodeDataUrlAction: function(editor) { + var data = String(editor.getSelection()); + var caretPos = editor.getCaretPos(); + var info = editorUtils.outputInfo(editor); + + if (!data) { + // no selection, try to find image bounds from current caret position + var text = info.content, m; + while (caretPos-- >= 0) { + if (startsWith('src=', text, caretPos)) { // found + if ((m = text.substr(caretPos).match(/^(src=(["'])?)([^'"<>\s]+)\1?/))) { + data = m[3]; + caretPos += m[1].length; + } + break; + } else if (startsWith('url(', text, caretPos)) { // found CSS url() pattern + if ((m = text.substr(caretPos).match(/^(url\((['"])?)([^'"\)\s]+)\1?/))) { + data = m[3]; + caretPos += m[1].length; + } + break; + } + } + } + + if (data) { + if (startsWith('data:', data)) { + return decodeFromBase64(editor, data, caretPos); + } else { + return encodeToBase64(editor, data, caretPos); + } + } + + return false; + } + }; +}); + +},{"../plugin/file":"plugin/file.js","../utils/action":"utils/action.js","../utils/base64":"utils/base64.js","../utils/editor":"utils/editor.js"}],"action/editPoints.js":[function(require,module,exports){ +/** + * Move between next/prev edit points. 'Edit points' are places between tags + * and quotes of empty attributes in html + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + /** + * Search for new caret insertion point + * @param {IEmmetEditor} editor Editor instance + * @param {Number} inc Search increment: -1 — search left, 1 — search right + * @param {Number} offset Initial offset relative to current caret position + * @return {Number} Returns -1 if insertion point wasn't found + */ + function findNewEditPoint(editor, inc, offset) { + inc = inc || 1; + offset = offset || 0; + + var curPoint = editor.getCaretPos() + offset; + var content = String(editor.getContent()); + var maxLen = content.length; + var nextPoint = -1; + var reEmptyLine = /^\s+$/; + + function getLine(ix) { + var start = ix; + while (start >= 0) { + var c = content.charAt(start); + if (c == '\n' || c == '\r') + break; + start--; + } + + return content.substring(start, ix); + } + + while (curPoint <= maxLen && curPoint >= 0) { + curPoint += inc; + var curChar = content.charAt(curPoint); + var nextChar = content.charAt(curPoint + 1); + var prevChar = content.charAt(curPoint - 1); + + switch (curChar) { + case '"': + case '\'': + if (nextChar == curChar && prevChar == '=') { + // empty attribute + nextPoint = curPoint + 1; + } + break; + case '>': + if (nextChar == '<') { + // between tags + nextPoint = curPoint + 1; + } + break; + case '\n': + case '\r': + // empty line + if (reEmptyLine.test(getLine(curPoint - 1))) { + nextPoint = curPoint; + } + break; + } + + if (nextPoint != -1) + break; + } + + return nextPoint; + } + + return { + /** + * Move to previous edit point + * @param {IEmmetEditor} editor Editor instance + * @param {String} syntax Current document syntax + * @param {String} profile Output profile name + * @return {Boolean} + */ + previousEditPointAction: function(editor, syntax, profile) { + var curPos = editor.getCaretPos(); + var newPoint = findNewEditPoint(editor, -1); + + if (newPoint == curPos) + // we're still in the same point, try searching from the other place + newPoint = findNewEditPoint(editor, -1, -2); + + if (newPoint != -1) { + editor.setCaretPos(newPoint); + return true; + } + + return false; + }, + + /** + * Move to next edit point + * @param {IEmmetEditor} editor Editor instance + * @param {String} syntax Current document syntax + * @param {String} profile Output profile name + * @return {Boolean} + */ + nextEditPointAction: function(editor, syntax, profile) { + var newPoint = findNewEditPoint(editor, 1); + if (newPoint != -1) { + editor.setCaretPos(newPoint); + return true; + } + + return false; + } + }; +}); +},{}],"action/evaluateMath.js":[function(require,module,exports){ +/** + * Evaluates simple math expression under caret + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var actionUtils = require('../utils/action'); + var utils = require('../utils/common'); + var math = require('../utils/math'); + var range = require('../assets/range'); + + return { + /** + * Evaluates math expression under the caret + * @param {IEmmetEditor} editor + * @return {Boolean} + */ + evaluateMathAction: function(editor) { + var content = editor.getContent(); + var chars = '.+-*/\\'; + + /** @type Range */ + var sel = range(editor.getSelectionRange()); + if (!sel.length()) { + sel = actionUtils.findExpressionBounds(editor, function(ch) { + return utils.isNumeric(ch) || chars.indexOf(ch) != -1; + }); + } + + if (sel && sel.length()) { + var expr = sel.substring(content); + + // replace integral division: 11\2 => Math.round(11/2) + expr = expr.replace(/([\d\.\-]+)\\([\d\.\-]+)/g, 'round($1/$2)'); + + try { + var result = utils.prettifyNumber(math.evaluate(expr)); + editor.replaceContent(result, sel.start, sel.end); + editor.setCaretPos(sel.start + result.length); + return true; + } catch (e) {} + } + + return false; + } + }; +}); + +},{"../assets/range":"assets/range.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/math":"utils/math.js"}],"action/expandAbbreviation.js":[function(require,module,exports){ +/** + * 'Expand abbreviation' editor action: extracts abbreviation from current caret + * position and replaces it with formatted output. + *

+ * This behavior can be overridden with custom handlers which can perform + * different actions when 'Expand Abbreviation' action is called. + * For example, a CSS gradient handler that produces vendor-prefixed gradient + * definitions registers its own expand abbreviation handler. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var handlerList = require('../assets/handlerList'); + var range = require('../assets/range'); + var prefs = require('../assets/preferences'); + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var actionUtils = require('../utils/action'); + var cssGradient = require('../resolver/cssGradient'); + var parser = require('../parser/abbreviation'); + + /** + * Search for abbreviation in editor from current caret position + * @param {IEmmetEditor} editor Editor instance + * @return {String} + */ + function findAbbreviation(editor) { + var r = range(editor.getSelectionRange()); + var content = String(editor.getContent()); + if (r.length()) { + // abbreviation is selected by user + return r.substring(content); + } + + // search for new abbreviation from current caret position + var curLine = editor.getCurrentLineRange(); + return actionUtils.extractAbbreviation(content.substring(curLine.start, r.start)); + } + + /** + * @type HandlerList List of registered handlers + */ + var handlers = handlerList.create(); + + // XXX setup default expand handlers + + /** + * Extracts abbreviation from current caret + * position and replaces it with formatted output + * @param {IEmmetEditor} editor Editor instance + * @param {String} syntax Syntax type (html, css, etc.) + * @param {String} profile Output profile name (html, xml, xhtml) + * @return {Boolean} Returns true if abbreviation was expanded + * successfully + */ + handlers.add(function(editor, syntax, profile) { + var caretPos = editor.getSelectionRange().end; + var abbr = findAbbreviation(editor); + + if (abbr) { + var content = parser.expand(abbr, { + syntax: syntax, + profile: profile, + contextNode: actionUtils.captureContext(editor) + }); + + if (content) { + var replaceFrom = caretPos - abbr.length; + var replaceTo = caretPos; + + // a special case for CSS: if editor already contains + // semicolon right after current caret position — replace it too + var cssSyntaxes = prefs.getArray('css.syntaxes'); + if (cssSyntaxes && ~cssSyntaxes.indexOf(syntax)) { + var curContent = editor.getContent(); + if (curContent.charAt(caretPos) == ';' && content.charAt(content.length - 1) == ';') { + replaceTo++; + } + } + + editor.replaceContent(content, replaceFrom, replaceTo); + return true; + } + } + + return false; + }, {order: -1}); + handlers.add(cssGradient.expandAbbreviationHandler.bind(cssGradient)); + + return { + /** + * The actual “Expand Abbreviation“ action routine + * @param {IEmmetEditor} editor Editor instance + * @param {String} syntax Current document syntax + * @param {String} profile Output profile name + * @return {Boolean} + */ + expandAbbreviationAction: function(editor, syntax, profile) { + var args = utils.toArray(arguments); + + // normalize incoming arguments + var info = editorUtils.outputInfo(editor, syntax, profile); + args[1] = info.syntax; + args[2] = info.profile; + + return handlers.exec(false, args); + }, + + /** + * A special case of “Expand Abbreviation“ action, invoked by Tab key. + * In this case if abbreviation wasn’t expanded successfully or there’s a selecetion, + * the current line/selection will be indented. + * @param {IEmmetEditor} editor Editor instance + * @param {String} syntax Current document syntax + * @param {String} profile Output profile name + * @return {Boolean} + */ + expandAbbreviationWithTabAction: function(editor, syntax, profile) { + var sel = editor.getSelection(); + var indent = '\t'; + + // if something is selected in editor, + // we should indent the selected content + if (sel) { + var selRange = range(editor.getSelectionRange()); + var content = utils.padString(sel, indent); + + editor.replaceContent(indent + '${0}', editor.getCaretPos()); + var replaceRange = range(editor.getCaretPos(), selRange.length()); + editor.replaceContent(content, replaceRange.start, replaceRange.end, true); + editor.createSelection(replaceRange.start, replaceRange.start + content.length); + return true; + } + + // nothing selected, try to expand + if (!this.expandAbbreviationAction(editor, syntax, profile)) { + editor.replaceContent(indent, editor.getCaretPos()); + } + + return true; + }, + + + _defaultHandler: function(editor, syntax, profile) { + var caretPos = editor.getSelectionRange().end; + var abbr = this.findAbbreviation(editor); + + if (abbr) { + var ctx = actionUtils.captureContext(editor); + var content = parser.expand(abbr, syntax, profile, ctx); + if (content) { + editor.replaceContent(content, caretPos - abbr.length, caretPos); + return true; + } + } + + return false; + }, + + /** + * Adds custom expand abbreviation handler. The passed function should + * return true if it was performed successfully, + * false otherwise. + * + * Added handlers will be called when 'Expand Abbreviation' is called + * in order they were added + * @memberOf expandAbbreviation + * @param {Function} fn + * @param {Object} options + */ + addHandler: function(fn, options) { + handlers.add(fn, options); + }, + + /** + * Removes registered handler + * @returns + */ + removeHandler: function(fn) { + handlers.remove(fn); + }, + + findAbbreviation: findAbbreviation + }; +}); +},{"../assets/handlerList":"assets/handlerList.js","../assets/preferences":"assets/preferences.js","../assets/range":"assets/range.js","../parser/abbreviation":"parser/abbreviation.js","../resolver/cssGradient":"resolver/cssGradient.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/incrementDecrement.js":[function(require,module,exports){ +/** + * Increment/decrement number under cursor + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var actionUtils = require('../utils/action'); + + /** + * Returns length of integer part of number + * @param {String} num + */ + function intLength(num) { + num = num.replace(/^\-/, ''); + if (~num.indexOf('.')) { + return num.split('.')[0].length; + } + + return num.length; + } + + return { + increment01Action: function(editor) { + return this.incrementNumber(editor, .1); + }, + + increment1Action: function(editor) { + return this.incrementNumber(editor, 1); + }, + + increment10Action: function(editor) { + return this.incrementNumber(editor, 10); + }, + + decrement01Action: function(editor) { + return this.incrementNumber(editor, -.1); + }, + + decrement1Action: function(editor) { + return this.incrementNumber(editor, -1); + }, + + decrement10Action: function(editor) { + return this.incrementNumber(editor, -10); + }, + + /** + * Default method to increment/decrement number under + * caret with given step + * @param {IEmmetEditor} editor + * @param {Number} step + * @return {Boolean} + */ + incrementNumber: function(editor, step) { + var hasSign = false; + var hasDecimal = false; + + var r = actionUtils.findExpressionBounds(editor, function(ch, pos, content) { + if (utils.isNumeric(ch)) + return true; + if (ch == '.') { + // make sure that next character is numeric too + if (!utils.isNumeric(content.charAt(pos + 1))) + return false; + + return hasDecimal ? false : hasDecimal = true; + } + if (ch == '-') + return hasSign ? false : hasSign = true; + + return false; + }); + + if (r && r.length()) { + var strNum = r.substring(String(editor.getContent())); + var num = parseFloat(strNum); + if (!isNaN(num)) { + num = utils.prettifyNumber(num + step); + + // do we have zero-padded number? + if (/^(\-?)0+[1-9]/.test(strNum)) { + var minus = ''; + if (RegExp.$1) { + minus = '-'; + num = num.substring(1); + } + + var parts = num.split('.'); + parts[0] = utils.zeroPadString(parts[0], intLength(strNum)); + num = minus + parts.join('.'); + } + + editor.replaceContent(num, r.start, r.end); + editor.createSelection(r.start, r.start + num.length); + return true; + } + } + + return false; + } + }; +}); +},{"../utils/action":"utils/action.js","../utils/common":"utils/common.js"}],"action/lineBreaks.js":[function(require,module,exports){ +/** + * Actions to insert line breaks. Some simple editors (like browser's + * <textarea>, for example) do not provide such simple things + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + var utils = require('../utils/common'); + var resources = require('../assets/resources'); + var htmlMatcher = require('../assets/htmlMatcher'); + var editorUtils = require('../utils/editor'); + + var xmlSyntaxes = ['html', 'xml', 'xsl']; + + // setup default preferences + prefs.define('css.closeBraceIndentation', '\n', + 'Indentation before closing brace of CSS rule. Some users prefere ' + + 'indented closing brace of CSS rule for better readability. ' + + 'This preference’s value will be automatically inserted before ' + + 'closing brace when user adds newline in newly created CSS rule ' + + '(e.g. when “Insert formatted linebreak” action will be performed ' + + 'in CSS file). If you’re such user, you may want to write put a value ' + + 'like \\n\\t in this preference.'); + + return { + /** + * Inserts newline character with proper indentation. This action is used in + * editors that doesn't have indentation control (like textarea element) to + * provide proper indentation for inserted newlines + * @param {IEmmetEditor} editor Editor instance + */ + insertLineBreakAction: function(editor) { + if (!this.insertLineBreakOnlyAction(editor)) { + var curPadding = editorUtils.getCurrentLinePadding(editor); + var content = String(editor.getContent()); + var caretPos = editor.getCaretPos(); + var len = content.length; + var nl = '\n'; + + // check out next line padding + var lineRange = editor.getCurrentLineRange(); + var nextPadding = ''; + + for (var i = lineRange.end + 1, ch; i < len; i++) { + ch = content.charAt(i); + if (ch == ' ' || ch == '\t') + nextPadding += ch; + else + break; + } + + if (nextPadding.length > curPadding.length) { + editor.replaceContent(nl + nextPadding, caretPos, caretPos, true); + } else { + editor.replaceContent(nl, caretPos); + } + } + + return true; + }, + + /** + * Inserts newline character with proper indentation in specific positions only. + * @param {IEmmetEditor} editor + * @return {Boolean} Returns true if line break was inserted + */ + insertLineBreakOnlyAction: function(editor) { + var info = editorUtils.outputInfo(editor); + var caretPos = editor.getCaretPos(); + var nl = '\n'; + var pad = '\t'; + + if (~xmlSyntaxes.indexOf(info.syntax)) { + // let's see if we're breaking newly created tag + var tag = htmlMatcher.tag(info.content, caretPos); + if (tag && !tag.innerRange.length()) { + editor.replaceContent(nl + pad + utils.getCaretPlaceholder() + nl, caretPos); + return true; + } + } else if (info.syntax == 'css') { + /** @type String */ + var content = info.content; + if (caretPos && content.charAt(caretPos - 1) == '{') { + var append = prefs.get('css.closeBraceIndentation'); + + var hasCloseBrace = content.charAt(caretPos) == '}'; + if (!hasCloseBrace) { + // do we really need special formatting here? + // check if this is really a newly created rule, + // look ahead for a closing brace + for (var i = caretPos, il = content.length, ch; i < il; i++) { + ch = content.charAt(i); + if (ch == '{') { + // ok, this is a new rule without closing brace + break; + } + + if (ch == '}') { + // not a new rule, just add indentation + append = ''; + hasCloseBrace = true; + break; + } + } + } + + if (!hasCloseBrace) { + append += '}'; + } + + // defining rule set + var insValue = nl + pad + utils.getCaretPlaceholder() + append; + editor.replaceContent(insValue, caretPos); + return true; + } + } + + return false; + } + }; +}); +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../assets/preferences":"assets/preferences.js","../assets/resources":"assets/resources.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/main.js":[function(require,module,exports){ +/** + * Module describes and performs Emmet actions. The actions themselves are + * defined in actions folder + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + + // all registered actions + var actions = {}; + + // load all default actions + var actionModules = { + base64: require('./base64'), + editPoints: require('./editPoints'), + evaluateMath: require('./evaluateMath'), + expandAbbreviation: require('./expandAbbreviation'), + incrementDecrement: require('./incrementDecrement'), + lineBreaks: require('./lineBreaks'), + balance: require('./balance'), + mergeLines: require('./mergeLines'), + reflectCSSValue: require('./reflectCSSValue'), + removeTag: require('./removeTag'), + selectItem: require('./selectItem'), + selectLine: require('./selectLine'), + splitJoinTag: require('./splitJoinTag'), + toggleComment: require('./toggleComment'), + updateImageSize: require('./updateImageSize'), + wrapWithAbbreviation: require('./wrapWithAbbreviation'), + updateTag: require('./updateTag') + }; + + function addAction(name, fn, options) { + name = name.toLowerCase(); + options = options || {}; + + if (typeof options === 'string') { + options = {label: options}; + } + + if (!options.label) { + options.label = humanizeActionName(name); + } + + actions[name] = { + name: name, + fn: fn, + options: options + }; + } + + /** + * “Humanizes” action name, makes it more readable for people + * @param {String} name Action name (like 'expand_abbreviation') + * @return Humanized name (like 'Expand Abbreviation') + */ + function humanizeActionName(name) { + return utils.trim(name.charAt(0).toUpperCase() + + name.substring(1).replace(/_[a-z]/g, function(str) { + return ' ' + str.charAt(1).toUpperCase(); + })); + } + + var bind = function(name, method) { + var m = actionModules[name]; + return m[method].bind(m); + }; + + // XXX register default actions + addAction('encode_decode_data_url', bind('base64', 'encodeDecodeDataUrlAction'), 'Encode\\Decode data:URL image'); + addAction('prev_edit_point', bind('editPoints', 'previousEditPointAction'), 'Previous Edit Point'); + addAction('next_edit_point', bind('editPoints', 'nextEditPointAction'), 'Next Edit Point'); + addAction('evaluate_math_expression', bind('evaluateMath', 'evaluateMathAction'), 'Numbers/Evaluate Math Expression'); + addAction('expand_abbreviation_with_tab', bind('expandAbbreviation', 'expandAbbreviationWithTabAction'), {hidden: true}); + addAction('expand_abbreviation', bind('expandAbbreviation', 'expandAbbreviationAction'), 'Expand Abbreviation'); + addAction('insert_formatted_line_break_only', bind('lineBreaks', 'insertLineBreakOnlyAction'), {hidden: true}); + addAction('insert_formatted_line_break', bind('lineBreaks', 'insertLineBreakAction'), {hidden: true}); + addAction('balance_inward', bind('balance', 'balanceInwardAction'), 'Balance (inward)'); + addAction('balance_outward', bind('balance', 'balanceOutwardAction'), 'Balance (outward)'); + addAction('matching_pair', bind('balance', 'goToMatchingPairAction'), 'HTML/Go To Matching Tag Pair'); + addAction('merge_lines', bind('mergeLines', 'mergeLinesAction'), 'Merge Lines'); + addAction('reflect_css_value', bind('reflectCSSValue', 'reflectCSSValueAction'), 'CSS/Reflect Value'); + addAction('remove_tag', bind('removeTag', 'removeTagAction'), 'HTML/Remove Tag'); + addAction('select_next_item', bind('selectItem', 'selectNextItemAction'), 'Select Next Item'); + addAction('select_previous_item', bind('selectItem', 'selectPreviousItemAction'), 'Select Previous Item'); + addAction('split_join_tag', bind('splitJoinTag', 'splitJoinTagAction'), 'HTML/Split\\Join Tag Declaration'); + addAction('toggle_comment', bind('toggleComment', 'toggleCommentAction'), 'Toggle Comment'); + addAction('update_image_size', bind('updateImageSize', 'updateImageSizeAction'), 'Update Image Size'); + addAction('wrap_with_abbreviation', bind('wrapWithAbbreviation', 'wrapWithAbbreviationAction'), 'Wrap With Abbreviation'); + addAction('update_tag', bind('updateTag', 'updateTagAction'), 'HTML/Update Tag'); + + [1, -1, 10, -10, 0.1, -0.1].forEach(function(num) { + var prefix = num > 0 ? 'increment' : 'decrement'; + var suffix = String(Math.abs(num)).replace('.', '').substring(0, 2); + var actionId = prefix + '_number_by_' + suffix; + var actionMethod = prefix + suffix + 'Action'; + var actionLabel = 'Numbers/' + prefix.charAt(0).toUpperCase() + prefix.substring(1) + ' number by ' + Math.abs(num); + addAction(actionId, bind('incrementDecrement', actionMethod), actionLabel); + }); + + return { + /** + * Registers new action + * @param {String} name Action name + * @param {Function} fn Action function + * @param {Object} options Custom action options:
+ * label : (String) – Human-readable action name. + * May contain '/' symbols as submenu separators
+ * hidden : (Boolean) – Indicates whether action + * should be displayed in menu (getMenu() method) + */ + add: addAction, + + /** + * Returns action object + * @param {String} name Action name + * @returns {Object} + */ + get: function(name) { + return actions[name.toLowerCase()]; + }, + + /** + * Runs Emmet action. For list of available actions and their + * arguments see actions folder. + * @param {String} name Action name + * @param {Array} args Additional arguments. It may be array of arguments + * or inline arguments. The first argument should be IEmmetEditor instance + * @returns {Boolean} Status of performed operation, true + * means action was performed successfully. + * @example + * require('action/main').run('expand_abbreviation', editor); + * require('action/main').run('wrap_with_abbreviation', [editor, 'div']); + */ + run: function(name, args) { + if (!Array.isArray(args)) { + args = utils.toArray(arguments, 1); + } + + var action = this.get(name); + if (!action) { + throw new Error('Action "' + name + '" is not defined'); + } + + return action.fn.apply(action, args); + }, + + /** + * Returns all registered actions as object + * @returns {Object} + */ + getAll: function() { + return actions; + }, + + /** + * Returns all registered actions as array + * @returns {Array} + */ + getList: function() { + var all = this.getAll(); + return Object.keys(all).map(function(key) { + return all[key]; + }); + }, + + /** + * Returns actions list as structured menu. If action has label, + * it will be splitted by '/' symbol into submenus (for example: + * CSS/Reflect Value) and grouped with other items + * @param {Array} skipActions List of action identifiers that should be + * skipped from menu + * @returns {Array} + */ + getMenu: function(skipActions) { + var result = []; + skipActions = skipActions || []; + this.getList().forEach(function(action) { + if (action.options.hidden || ~skipActions.indexOf(action.name)) + return; + + var actionName = humanizeActionName(action.name); + var ctx = result; + if (action.options.label) { + var parts = action.options.label.split('/'); + actionName = parts.pop(); + + // create submenus, if needed + var menuName, submenu; + while ((menuName = parts.shift())) { + submenu = utils.find(ctx, function(item) { + return item.type == 'submenu' && item.name == menuName; + }); + + if (!submenu) { + submenu = { + name: menuName, + type: 'submenu', + items: [] + }; + ctx.push(submenu); + } + + ctx = submenu.items; + } + } + + ctx.push({ + type: 'action', + name: action.name, + label: actionName + }); + }); + + return result; + }, + + /** + * Returns action name associated with menu item title + * @param {String} title + * @returns {String} + */ + getActionNameForMenuTitle: function(title, menu) { + return utils.find(menu || this.getMenu(), function(val) { + if (val.type == 'action') { + if (val.label == title || val.name == title) { + return val.name; + } + } else { + return this.getActionNameForMenuTitle(title, val.items); + } + }, this); + } + }; +}); +},{"../utils/common":"utils/common.js","./balance":"action/balance.js","./base64":"action/base64.js","./editPoints":"action/editPoints.js","./evaluateMath":"action/evaluateMath.js","./expandAbbreviation":"action/expandAbbreviation.js","./incrementDecrement":"action/incrementDecrement.js","./lineBreaks":"action/lineBreaks.js","./mergeLines":"action/mergeLines.js","./reflectCSSValue":"action/reflectCSSValue.js","./removeTag":"action/removeTag.js","./selectItem":"action/selectItem.js","./selectLine":"action/selectLine.js","./splitJoinTag":"action/splitJoinTag.js","./toggleComment":"action/toggleComment.js","./updateImageSize":"action/updateImageSize.js","./updateTag":"action/updateTag.js","./wrapWithAbbreviation":"action/wrapWithAbbreviation.js"}],"action/mergeLines.js":[function(require,module,exports){ +/** + * Merges selected lines or lines between XHTML tag pairs + * @param {Function} require + * @param {Underscore} _ + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var htmlMatcher = require('../assets/htmlMatcher'); + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var range = require('../assets/range'); + + return { + mergeLinesAction: function(editor) { + var info = editorUtils.outputInfo(editor); + + var selection = range(editor.getSelectionRange()); + if (!selection.length()) { + // find matching tag + var pair = htmlMatcher.find(info.content, editor.getCaretPos()); + if (pair) { + selection = pair.outerRange; + } + } + + if (selection.length()) { + // got range, merge lines + var text = selection.substring(info.content); + var lines = utils.splitByLines(text); + + for (var i = 1; i < lines.length; i++) { + lines[i] = lines[i].replace(/^\s+/, ''); + } + + text = lines.join('').replace(/\s{2,}/, ' '); + var textLen = text.length; + text = utils.escapeText(text); + editor.replaceContent(text, selection.start, selection.end); + editor.createSelection(selection.start, selection.start + textLen); + + return true; + } + + return false; + } + }; +}); +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../assets/range":"assets/range.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/reflectCSSValue.js":[function(require,module,exports){ +/** + * Reflect CSS value: takes rule's value under caret and pastes it for the same + * rules with vendor prefixes + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var handlerList = require('../assets/handlerList'); + var prefs = require('../assets/preferences'); + var cssResolver = require('../resolver/css'); + var cssEditTree = require('../editTree/css'); + var utils = require('../utils/common'); + var actionUtils = require('../utils/action'); + var editorUtils = require('../utils/editor'); + var cssGradient = require('../resolver/cssGradient'); + + prefs.define('css.reflect.oldIEOpacity', false, 'Support IE6/7/8 opacity notation, e.g. filter:alpha(opacity=...).\ + Note that CSS3 and SVG also provides filter property so this option is disabled by default.') + + /** + * @type HandlerList List of registered handlers + */ + var handlers = handlerList.create(); + + function doCSSReflection(editor) { + var outputInfo = editorUtils.outputInfo(editor); + var caretPos = editor.getCaretPos(); + + var cssRule = cssEditTree.parseFromPosition(outputInfo.content, caretPos); + if (!cssRule) return; + + var property = cssRule.itemFromPosition(caretPos, true); + // no property under cursor, nothing to reflect + if (!property) return; + + var oldRule = cssRule.source; + var offset = cssRule.options.offset; + var caretDelta = caretPos - offset - property.range().start; + + handlers.exec(false, [property]); + + if (oldRule !== cssRule.source) { + return { + data: cssRule.source, + start: offset, + end: offset + oldRule.length, + caret: offset + property.range().start + caretDelta + }; + } + } + + /** + * Returns regexp that should match reflected CSS property names + * @param {String} name Current CSS property name + * @return {RegExp} + */ + function getReflectedCSSName(name) { + name = cssEditTree.baseName(name); + var vendorPrefix = '^(?:\\-\\w+\\-)?', m; + + if ((name == 'opacity' || name == 'filter') && prefs.get('css.reflect.oldIEOpacity')) { + return new RegExp(vendorPrefix + '(?:opacity|filter)$'); + } else if ((m = name.match(/^border-radius-(top|bottom)(left|right)/))) { + // Mozilla-style border radius + return new RegExp(vendorPrefix + '(?:' + name + '|border-' + m[1] + '-' + m[2] + '-radius)$'); + } else if ((m = name.match(/^border-(top|bottom)-(left|right)-radius/))) { + return new RegExp(vendorPrefix + '(?:' + name + '|border-radius-' + m[1] + m[2] + ')$'); + } + + return new RegExp(vendorPrefix + name + '$'); + } + + /** + * Reflects inner CSS properites in given value + * agains name‘s vendor prefix. In other words, it tries + * to modify `transform 0.2s linear` value for `-webkit-transition` + * property + * @param {String} name Reciever CSS property name + * @param {String} value New property value + * @return {String} + */ + function reflectValueParts(name, value) { + // detects and updates vendor-specific properties in value, + // e.g. -webkit-transition: -webkit-transform + + var reVendor = /^\-(\w+)\-/; + var propPrefix = reVendor.test(name) ? RegExp.$1.toLowerCase() : ''; + var parts = cssEditTree.findParts(value); + + parts.reverse(); + parts.forEach(function(part) { + var partValue = part.substring(value).replace(reVendor, ''); + var prefixes = cssResolver.vendorPrefixes(partValue); + if (prefixes) { + // if prefixes are not null then given value can + // be resolved against Can I Use database and may or + // may not contain prefixed variant + if (propPrefix && ~prefixes.indexOf(propPrefix)) { + partValue = '-' + propPrefix + '-' + partValue; + } + + value = utils.replaceSubstring(value, partValue, part); + } + }); + + return value; + } + + /** + * Reflects value from donor into receiver + * @param {CSSProperty} donor Donor CSS property from which value should + * be reflected + * @param {CSSProperty} receiver Property that should receive reflected + * value from donor + */ + function reflectValue(donor, receiver) { + var value = getReflectedValue(donor.name(), donor.value(), + receiver.name(), receiver.value()); + + value = reflectValueParts(receiver.name(), value); + receiver.value(value); + } + + /** + * Returns value that should be reflected for refName CSS property + * from curName property. This function is used for special cases, + * when the same result must be achieved with different properties for different + * browsers. For example: opаcity:0.5; → filter:alpha(opacity=50);

+ * + * This function does value conversion between different CSS properties + * + * @param {String} curName Current CSS property name + * @param {String} curValue Current CSS property value + * @param {String} refName Receiver CSS property's name + * @param {String} refValue Receiver CSS property's value + * @return {String} New value for receiver property + */ + function getReflectedValue(curName, curValue, refName, refValue) { + curName = cssEditTree.baseName(curName); + refName = cssEditTree.baseName(refName); + + if (curName == 'opacity' && refName == 'filter') { + return refValue.replace(/opacity=[^)]*/i, 'opacity=' + Math.floor(parseFloat(curValue) * 100)); + } else if (curName == 'filter' && refName == 'opacity') { + var m = curValue.match(/opacity=([^)]*)/i); + return m ? utils.prettifyNumber(parseInt(m[1], 10) / 100) : refValue; + } + + return curValue; + } + + module = module || {}; + module.exports = { + reflectCSSValueAction: function(editor) { + if (editor.getSyntax() != 'css') { + return false; + } + + return actionUtils.compoundUpdate(editor, doCSSReflection(editor)); + }, + + _defaultHandler: function(property) { + var reName = getReflectedCSSName(property.name()); + property.parent.list().forEach(function(p) { + if (reName.test(p.name())) { + reflectValue(property, p); + } + }); + }, + + /** + * Adds custom reflect handler. The passed function will receive matched + * CSS property (as CSSEditElement object) and should + * return true if it was performed successfully (handled + * reflection), false otherwise. + * @param {Function} fn + * @param {Object} options + */ + addHandler: function(fn, options) { + handlers.add(fn, options); + }, + + /** + * Removes registered handler + * @returns + */ + removeHandler: function(fn) { + handlers.remove(fn); + } + }; + + // XXX add default handlers + handlers.add(module.exports._defaultHandler.bind(module.exports), {order: -1}); + handlers.add(cssGradient.reflectValueHandler.bind(cssGradient)); + + return module.exports; +}); +},{"../assets/handlerList":"assets/handlerList.js","../assets/preferences":"assets/preferences.js","../editTree/css":"editTree/css.js","../resolver/css":"resolver/css.js","../resolver/cssGradient":"resolver/cssGradient.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/removeTag.js":[function(require,module,exports){ +/** + * Gracefully removes tag under cursor + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var htmlMatcher = require('../assets/htmlMatcher'); + + return { + removeTagAction: function(editor) { + var info = editorUtils.outputInfo(editor); + + // search for tag + var tag = htmlMatcher.tag(info.content, editor.getCaretPos()); + if (tag) { + if (!tag.close) { + // simply remove unary tag + editor.replaceContent(utils.getCaretPlaceholder(), tag.range.start, tag.range.end); + } else { + // remove tag and its newlines + /** @type Range */ + var tagContentRange = utils.narrowToNonSpace(info.content, tag.innerRange); + /** @type Range */ + var startLineBounds = utils.findNewlineBounds(info.content, tagContentRange.start); + var startLinePad = utils.getLinePadding(startLineBounds.substring(info.content)); + var tagContent = tagContentRange.substring(info.content); + + tagContent = utils.unindentString(tagContent, startLinePad); + editor.replaceContent(utils.getCaretPlaceholder() + utils.escapeText(tagContent), tag.outerRange.start, tag.outerRange.end); + } + + return true; + } + + return false; + } + }; +}); + +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/selectItem.js":[function(require,module,exports){ +/** + * Actions that use stream parsers and tokenizers for traversing: + * -- Search for next/previous items in HTML + * -- Search for next/previous items in CSS + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var range = require('../assets/range'); + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var actionUtils = require('../utils/action'); + var stringStream = require('../assets/stringStream'); + var xmlParser = require('../parser/xml'); + var cssEditTree = require('../editTree/css'); + var cssSections = require('../utils/cssSections'); + + var startTag = /^<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; + + /** + * Generic function for searching for items to select + * @param {IEmmetEditor} editor + * @param {Boolean} isBackward Search backward (search forward otherwise) + * @param {Function} extractFn Function that extracts item content + * @param {Function} rangeFn Function that search for next token range + */ + function findItem(editor, isBackward, extractFn, rangeFn) { + var content = editorUtils.outputInfo(editor).content; + + var contentLength = content.length; + var itemRange, rng; + /** @type Range */ + var prevRange = range(-1, 0); + /** @type Range */ + var sel = range(editor.getSelectionRange()); + + var searchPos = sel.start, loop = 100000; // endless loop protection + while (searchPos >= 0 && searchPos < contentLength && --loop > 0) { + if ( (itemRange = extractFn(content, searchPos, isBackward)) ) { + if (prevRange.equal(itemRange)) { + break; + } + + prevRange = itemRange.clone(); + rng = rangeFn(itemRange.substring(content), itemRange.start, sel.clone()); + + if (rng) { + editor.createSelection(rng.start, rng.end); + return true; + } else { + searchPos = isBackward ? itemRange.start : itemRange.end - 1; + } + } + + searchPos += isBackward ? -1 : 1; + } + + return false; + } + + // XXX HTML section + + /** + * Find next HTML item + * @param {IEmmetEditor} editor + */ + function findNextHTMLItem(editor) { + var isFirst = true; + return findItem(editor, false, function(content, searchPos){ + if (isFirst) { + isFirst = false; + return findOpeningTagFromPosition(content, searchPos); + } else { + return getOpeningTagFromPosition(content, searchPos); + } + }, function(tag, offset, selRange) { + return getRangeForHTMLItem(tag, offset, selRange, false); + }); + } + + /** + * Find previous HTML item + * @param {IEmmetEditor} editor + */ + function findPrevHTMLItem(editor) { + return findItem(editor, true, getOpeningTagFromPosition, function (tag, offset, selRange) { + return getRangeForHTMLItem(tag, offset, selRange, true); + }); + } + + /** + * Creates possible selection ranges for HTML tag + * @param {String} source Original HTML source for tokens + * @param {Array} tokens List of HTML tokens + * @returns {Array} + */ + function makePossibleRangesHTML(source, tokens, offset) { + offset = offset || 0; + var result = []; + var attrStart = -1, attrName = '', attrValue = '', attrValueRange, tagName; + tokens.forEach(function(tok) { + switch (tok.type) { + case 'tag': + tagName = source.substring(tok.start, tok.end); + if (/^<[\w\:\-]/.test(tagName)) { + // add tag name + result.push(range({ + start: tok.start + 1, + end: tok.end + })); + } + break; + case 'attribute': + attrStart = tok.start; + attrName = source.substring(tok.start, tok.end); + break; + + case 'string': + // attribute value + // push full attribute first + result.push(range(attrStart, tok.end - attrStart)); + + attrValueRange = range(tok); + attrValue = attrValueRange.substring(source); + + // is this a quoted attribute? + if (isQuote(attrValue.charAt(0))) + attrValueRange.start++; + + if (isQuote(attrValue.charAt(attrValue.length - 1))) + attrValueRange.end--; + + result.push(attrValueRange); + + if (attrName == 'class') { + result = result.concat(classNameRanges(attrValueRange.substring(source), attrValueRange.start)); + } + + break; + } + }); + + // offset ranges + result = result.filter(function(item) { + if (item.length()) { + item.shift(offset); + return true; + } + }); + + // remove duplicates + return utils.unique(result, function(item) { + return item.toString(); + }); + } + + /** + * Returns ranges of class names in "class" attribute value + * @param {String} className + * @returns {Array} + */ + function classNameRanges(className, offset) { + offset = offset || 0; + var result = []; + /** @type StringStream */ + var stream = stringStream.create(className); + + // skip whitespace + stream.eatSpace(); + stream.start = stream.pos; + + var ch; + while ((ch = stream.next())) { + if (/[\s\u00a0]/.test(ch)) { + result.push(range(stream.start + offset, stream.pos - stream.start - 1)); + stream.eatSpace(); + stream.start = stream.pos; + } + } + + result.push(range(stream.start + offset, stream.pos - stream.start)); + return result; + } + + /** + * Returns best HTML tag range match for current selection + * @param {String} tag Tag declaration + * @param {Number} offset Tag's position index inside content + * @param {Range} selRange Selection range + * @return {Range} Returns range if next item was found, null otherwise + */ + function getRangeForHTMLItem(tag, offset, selRange, isBackward) { + var ranges = makePossibleRangesHTML(tag, xmlParser.parse(tag), offset); + + if (isBackward) + ranges.reverse(); + + // try to find selected range + var curRange = utils.find(ranges, function(r) { + return r.equal(selRange); + }); + + if (curRange) { + var ix = ranges.indexOf(curRange); + if (ix < ranges.length - 1) + return ranges[ix + 1]; + + return null; + } + + // no selected range, find nearest one + if (isBackward) + // search backward + return utils.find(ranges, function(r) { + return r.start < selRange.start; + }); + + // search forward + // to deal with overlapping ranges (like full attribute definition + // and attribute value) let's find range under caret first + if (!curRange) { + var matchedRanges = ranges.filter(function(r) { + return r.inside(selRange.end); + }); + + if (matchedRanges.length > 1) + return matchedRanges[1]; + } + + + return utils.find(ranges, function(r) { + return r.end > selRange.end; + }); + } + + /** + * Search for opening tag in content, starting at specified position + * @param {String} html Where to search tag + * @param {Number} pos Character index where to start searching + * @return {Range} Returns range if valid opening tag was found, + * null otherwise + */ + function findOpeningTagFromPosition(html, pos) { + var tag; + while (pos >= 0) { + if ((tag = getOpeningTagFromPosition(html, pos))) + return tag; + pos--; + } + + return null; + } + + /** + * @param {String} html Where to search tag + * @param {Number} pos Character index where to start searching + * @return {Range} Returns range if valid opening tag was found, + * null otherwise + */ + function getOpeningTagFromPosition(html, pos) { + var m; + if (html.charAt(pos) == '<' && (m = html.substring(pos, html.length).match(startTag))) { + return range(pos, m[0]); + } + } + + function isQuote(ch) { + return ch == '"' || ch == "'"; + } + + /** + * Returns all ranges inside given rule, available for selection + * @param {CSSEditContainer} rule + * @return {Array} + */ + function findInnerRanges(rule) { + // rule selector + var ranges = [rule.nameRange(true)]; + + // find nested sections, keep selectors only + var nestedSections = cssSections.nestedSectionsInRule(rule); + nestedSections.forEach(function(section) { + ranges.push(range.create2(section.start, section._selectorEnd)); + }); + + // add full property ranges and values + rule.list().forEach(function(property) { + ranges = ranges.concat(makePossibleRangesCSS(property)); + }); + + ranges = range.sort(ranges); + + // optimize result: remove empty ranges and duplicates + ranges = ranges.filter(function(item) { + return !!item.length(); + }); + return utils.unique(ranges, function(item) { + return item.toString(); + }); + } + + /** + * Makes all possible selection ranges for specified CSS property + * @param {CSSProperty} property + * @returns {Array} + */ + function makePossibleRangesCSS(property) { + // find all possible ranges, sorted by position and size + var valueRange = property.valueRange(true); + var result = [property.range(true), valueRange]; + + // locate parts of complex values. + // some examples: + // – 1px solid red: 3 parts + // – arial, sans-serif: enumeration, 2 parts + // – url(image.png): function value part + var value = property.value(); + property.valueParts().forEach(function(r) { + // add absolute range + var clone = r.clone(); + result.push(clone.shift(valueRange.start)); + + /** @type StringStream */ + var stream = stringStream.create(r.substring(value)); + if (stream.match(/^[\w\-]+\(/, true)) { + // we have a function, find values in it. + // but first add function contents + stream.start = stream.pos; + stream.backUp(1); + stream.skipToPair('(', ')'); + stream.backUp(1); + var fnBody = stream.current(); + result.push(range(clone.start + stream.start, fnBody)); + + // find parts + cssEditTree.findParts(fnBody).forEach(function(part) { + result.push(range(clone.start + stream.start + part.start, part.substring(fnBody))); + }); + } + }); + + return result; + } + + /** + * Tries to find matched CSS property and nearest range for selection + * @param {CSSRule} rule + * @param {Range} selRange + * @param {Boolean} isBackward + * @returns {Range} + */ + function matchedRangeForCSSProperty(rule, selRange, isBackward) { + var ranges = findInnerRanges(rule); + if (isBackward) { + ranges.reverse(); + } + + // return next to selected range, if possible + var r = utils.find(ranges, function(item) { + return item.equal(selRange); + }); + + if (r) { + return ranges[ranges.indexOf(r) + 1]; + } + + // find matched and (possibly) overlapping ranges + var nested = ranges.filter(function(item) { + return item.inside(selRange.end); + }); + + if (nested.length) { + return nested.sort(function(a, b) { + return a.length() - b.length(); + })[0]; + } + + // return range next to caret + var test = + r = utils.find(ranges, isBackward + ? function(item) {return item.end < selRange.start;} + : function(item) {return item.end > selRange.start;} + ); + + if (!r) { + // can’t find anything, just pick first one + r = ranges[0]; + } + + return r; + } + + function findNextCSSItem(editor) { + return findItem(editor, false, cssSections.locateRule.bind(cssSections), getRangeForNextItemInCSS); + } + + function findPrevCSSItem(editor) { + return findItem(editor, true, cssSections.locateRule.bind(cssSections), getRangeForPrevItemInCSS); + } + + /** + * Returns range for item to be selected in CSS after current caret + * (selection) position + * @param {String} rule CSS rule declaration + * @param {Number} offset Rule's position index inside content + * @param {Range} selRange Selection range + * @return {Range} Returns range if next item was found, null otherwise + */ + function getRangeForNextItemInCSS(rule, offset, selRange) { + var tree = cssEditTree.parse(rule, { + offset: offset + }); + + return matchedRangeForCSSProperty(tree, selRange, false); + } + + /** + * Returns range for item to be selected in CSS before current caret + * (selection) position + * @param {String} rule CSS rule declaration + * @param {Number} offset Rule's position index inside content + * @param {Range} selRange Selection range + * @return {Range} Returns range if previous item was found, null otherwise + */ + function getRangeForPrevItemInCSS(rule, offset, selRange) { + var tree = cssEditTree.parse(rule, { + offset: offset + }); + + return matchedRangeForCSSProperty(tree, selRange, true); + } + + return { + selectNextItemAction: function(editor) { + if (actionUtils.isSupportedCSS(editor.getSyntax())) { + return findNextCSSItem(editor); + } else { + return findNextHTMLItem(editor); + } + }, + + selectPreviousItemAction: function(editor) { + if (actionUtils.isSupportedCSS(editor.getSyntax())) { + return findPrevCSSItem(editor); + } else { + return findPrevHTMLItem(editor); + } + } + }; +}); +},{"../assets/range":"assets/range.js","../assets/stringStream":"assets/stringStream.js","../editTree/css":"editTree/css.js","../parser/xml":"parser/xml.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/cssSections":"utils/cssSections.js","../utils/editor":"utils/editor.js"}],"action/selectLine.js":[function(require,module,exports){ +/** + * Select current line (for simple editors like browser's <textarea>) + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + return { + selectLineAction: function(editor) { + var range = editor.getCurrentLineRange(); + editor.createSelection(range.start, range.end); + return true; + } + }; +}); +},{}],"action/splitJoinTag.js":[function(require,module,exports){ +/** + * Splits or joins tag, e.g. transforms it into a short notation and vice versa:
+ * <div></div> → <div /> : join
+ * <div /> → <div></div> : split + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var resources = require('../assets/resources'); + var matcher = require('../assets/htmlMatcher'); + var editorUtils = require('../utils/editor'); + var profile = require('../assets/profile'); + + /** + * @param {IEmmetEditor} editor + * @param {Object} profile + * @param {Object} tag + */ + function joinTag(editor, profile, tag) { + // empty closing slash is a nonsense for this action + var slash = profile.selfClosing() || ' /'; + var content = tag.open.range.substring(tag.source).replace(/\s*>$/, slash + '>'); + + var caretPos = editor.getCaretPos(); + + // update caret position + if (content.length + tag.outerRange.start < caretPos) { + caretPos = content.length + tag.outerRange.start; + } + + content = utils.escapeText(content); + editor.replaceContent(content, tag.outerRange.start, tag.outerRange.end); + editor.setCaretPos(caretPos); + return true; + } + + function splitTag(editor, profile, tag) { + var caretPos = editor.getCaretPos(); + + // define tag content depending on profile + var tagContent = (profile.tag_nl === true) ? '\n\t\n' : ''; + var content = tag.outerContent().replace(/\s*\/>$/, '>'); + caretPos = tag.outerRange.start + content.length; + content += tagContent + ''; + + content = utils.escapeText(content); + editor.replaceContent(content, tag.outerRange.start, tag.outerRange.end); + editor.setCaretPos(caretPos); + return true; + } + + return { + splitJoinTagAction: function(editor, profileName) { + var info = editorUtils.outputInfo(editor, null, profileName); + var curProfile = profile.get(info.profile); + + // find tag at current position + var tag = matcher.tag(info.content, editor.getCaretPos()); + if (tag) { + return tag.close + ? joinTag(editor, curProfile, tag) + : splitTag(editor, curProfile, tag); + } + + return false; + } + }; +}); +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../assets/profile":"assets/profile.js","../assets/resources":"assets/resources.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/toggleComment.js":[function(require,module,exports){ +/** + * Toggles HTML and CSS comments depending on current caret context. Unlike + * the same action in most editors, this action toggles comment on currently + * matched item—HTML tag or CSS selector—when nothing is selected. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + var range = require('../assets/range'); + var utils = require('../utils/common'); + var actionUtils = require('../utils/action'); + var editorUtils = require('../utils/editor'); + var htmlMatcher = require('../assets/htmlMatcher'); + var cssEditTree = require('../editTree/css'); + + /** + * Toggle HTML comment on current selection or tag + * @param {IEmmetEditor} editor + * @return {Boolean} Returns true if comment was toggled + */ + function toggleHTMLComment(editor) { + /** @type Range */ + var r = range(editor.getSelectionRange()); + var info = editorUtils.outputInfo(editor); + + if (!r.length()) { + // no selection, find matching tag + var tag = htmlMatcher.tag(info.content, editor.getCaretPos()); + if (tag) { // found pair + r = tag.outerRange; + } + } + + return genericCommentToggle(editor, '', r); + } + + /** + * Simple CSS commenting + * @param {IEmmetEditor} editor + * @return {Boolean} Returns true if comment was toggled + */ + function toggleCSSComment(editor) { + /** @type Range */ + var rng = range(editor.getSelectionRange()); + var info = editorUtils.outputInfo(editor); + + if (!rng.length()) { + // no selection, try to get current rule + /** @type CSSRule */ + var rule = cssEditTree.parseFromPosition(info.content, editor.getCaretPos()); + if (rule) { + var property = cssItemFromPosition(rule, editor.getCaretPos()); + rng = property + ? property.range(true) + : range(rule.nameRange(true).start, rule.source); + } + } + + if (!rng.length()) { + // still no selection, get current line + rng = range(editor.getCurrentLineRange()); + utils.narrowToNonSpace(info.content, rng); + } + + return genericCommentToggle(editor, '/*', '*/', rng); + } + + /** + * Returns CSS property from rule that matches passed position + * @param {EditContainer} rule + * @param {Number} absPos + * @returns {EditElement} + */ + function cssItemFromPosition(rule, absPos) { + // do not use default EditContainer.itemFromPosition() here, because + // we need to make a few assumptions to make CSS commenting more reliable + var relPos = absPos - (rule.options.offset || 0); + var reSafeChar = /^[\s\n\r]/; + return utils.find(rule.list(), function(item) { + if (item.range().end === relPos) { + // at the end of property, but outside of it + // if there’s a space character at current position, + // use current property + return reSafeChar.test(rule.source.charAt(relPos)); + } + + return item.range().inside(relPos); + }); + } + + /** + * Search for nearest comment in str, starting from index from + * @param {String} text Where to search + * @param {Number} from Search start index + * @param {String} start_token Comment start string + * @param {String} end_token Comment end string + * @return {Range} Returns null if comment wasn't found + */ + function searchComment(text, from, startToken, endToken) { + var commentStart = -1; + var commentEnd = -1; + + var hasMatch = function(str, start) { + return text.substr(start, str.length) == str; + }; + + // search for comment start + while (from--) { + if (hasMatch(startToken, from)) { + commentStart = from; + break; + } + } + + if (commentStart != -1) { + // search for comment end + from = commentStart; + var contentLen = text.length; + while (contentLen >= from++) { + if (hasMatch(endToken, from)) { + commentEnd = from + endToken.length; + break; + } + } + } + + return (commentStart != -1 && commentEnd != -1) + ? range(commentStart, commentEnd - commentStart) + : null; + } + + /** + * Generic comment toggling routine + * @param {IEmmetEditor} editor + * @param {String} commentStart Comment start token + * @param {String} commentEnd Comment end token + * @param {Range} range Selection range + * @return {Boolean} + */ + function genericCommentToggle(editor, commentStart, commentEnd, range) { + var content = editorUtils.outputInfo(editor).content; + var caretPos = editor.getCaretPos(); + var newContent = null; + + /** + * Remove comment markers from string + * @param {Sting} str + * @return {String} + */ + function removeComment(str) { + return str + .replace(new RegExp('^' + utils.escapeForRegexp(commentStart) + '\\s*'), function(str){ + caretPos -= str.length; + return ''; + }).replace(new RegExp('\\s*' + utils.escapeForRegexp(commentEnd) + '$'), ''); + } + + // first, we need to make sure that this substring is not inside + // comment + var commentRange = searchComment(content, caretPos, commentStart, commentEnd); + if (commentRange && commentRange.overlap(range)) { + // we're inside comment, remove it + range = commentRange; + newContent = removeComment(range.substring(content)); + } else { + // should add comment + // make sure that there's no comment inside selection + newContent = commentStart + ' ' + + range.substring(content) + .replace(new RegExp(utils.escapeForRegexp(commentStart) + '\\s*|\\s*' + utils.escapeForRegexp(commentEnd), 'g'), '') + + ' ' + commentEnd; + + // adjust caret position + caretPos += commentStart.length + 1; + } + + // replace editor content + if (newContent !== null) { + newContent = utils.escapeText(newContent); + editor.setCaretPos(range.start); + editor.replaceContent(editorUtils.unindent(editor, newContent), range.start, range.end); + editor.setCaretPos(caretPos); + return true; + } + + return false; + } + + return { + /** + * Toggle comment on current editor's selection or HTML tag/CSS rule + * @param {IEmmetEditor} editor + */ + toggleCommentAction: function(editor) { + var info = editorUtils.outputInfo(editor); + if (actionUtils.isSupportedCSS(info.syntax)) { + // in case our editor is good enough and can recognize syntax from + // current token, we have to make sure that cursor is not inside + // 'style' attribute of html element + var caretPos = editor.getCaretPos(); + var tag = htmlMatcher.tag(info.content, caretPos); + if (tag && tag.open.range.inside(caretPos)) { + info.syntax = 'html'; + } + } + + var cssSyntaxes = prefs.getArray('css.syntaxes'); + if (~cssSyntaxes.indexOf(info.syntax)) { + return toggleCSSComment(editor); + } + + return toggleHTMLComment(editor); + } + }; +}); +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../assets/preferences":"assets/preferences.js","../assets/range":"assets/range.js","../editTree/css":"editTree/css.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/updateImageSize.js":[function(require,module,exports){ +/** + * Automatically updates image size attributes in HTML's <img> element or + * CSS rule + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var actionUtils = require('../utils/action'); + var xmlEditTree = require('../editTree/xml'); + var cssEditTree = require('../editTree/css'); + var base64 = require('../utils/base64'); + var file = require('../plugin/file'); + + /** + * Updates image size of <img src=""> tag + * @param {IEmmetEditor} editor + */ + function updateImageSizeHTML(editor) { + var offset = editor.getCaretPos(); + + // find tag from current caret position + var info = editorUtils.outputInfo(editor); + var xmlElem = xmlEditTree.parseFromPosition(info.content, offset, true); + if (xmlElem && (xmlElem.name() || '').toLowerCase() == 'img') { + getImageSizeForSource(editor, xmlElem.value('src'), function(size) { + if (size) { + var compoundData = xmlElem.range(true); + xmlElem.value('width', size.width); + xmlElem.value('height', size.height, xmlElem.indexOf('width') + 1); + + actionUtils.compoundUpdate(editor, utils.extend(compoundData, { + data: xmlElem.toString(), + caret: offset + })); + } + }); + } + } + + /** + * Updates image size of CSS property + * @param {IEmmetEditor} editor + */ + function updateImageSizeCSS(editor) { + var offset = editor.getCaretPos(); + + // find tag from current caret position + var info = editorUtils.outputInfo(editor); + var cssRule = cssEditTree.parseFromPosition(info.content, offset, true); + if (cssRule) { + // check if there is property with image under caret + var prop = cssRule.itemFromPosition(offset, true), m; + if (prop && (m = /url\((["']?)(.+?)\1\)/i.exec(prop.value() || ''))) { + getImageSizeForSource(editor, m[2], function(size) { + if (size) { + var compoundData = cssRule.range(true); + cssRule.value('width', size.width + 'px'); + cssRule.value('height', size.height + 'px', cssRule.indexOf('width') + 1); + + actionUtils.compoundUpdate(editor, utils.extend(compoundData, { + data: cssRule.toString(), + caret: offset + })); + } + }); + } + } + } + + /** + * Returns image dimensions for source + * @param {IEmmetEditor} editor + * @param {String} src Image source (path or data:url) + */ + function getImageSizeForSource(editor, src, callback) { + var fileContent; + if (src) { + // check if it is data:url + if (/^data:/.test(src)) { + fileContent = base64.decode( src.replace(/^data\:.+?;.+?,/, '') ); + return callback(actionUtils.getImageSize(fileContent)); + } + + var absPath = file.locateFile(editor.getFilePath(), src); + if (absPath === null) { + throw "Can't find " + src + ' file'; + } + + file.read(absPath, function(err, content) { + if (err) { + throw 'Unable to read ' + absPath + ': ' + err; + } + + content = String(content); + callback(actionUtils.getImageSize(content)); + }); + } + } + + return { + updateImageSizeAction: function(editor) { + // this action will definitely won’t work in SASS dialect, + // but may work in SCSS or LESS + if (actionUtils.isSupportedCSS(editor.getSyntax())) { + updateImageSizeCSS(editor); + } else { + updateImageSizeHTML(editor); + } + + return true; + } + }; +}); +},{"../editTree/css":"editTree/css.js","../editTree/xml":"editTree/xml.js","../plugin/file":"plugin/file.js","../utils/action":"utils/action.js","../utils/base64":"utils/base64.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/updateTag.js":[function(require,module,exports){ +/** + * Update Tag action: allows users to update existing HTML tags and add/remove + * attributes or even tag name + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var xmlEditTree = require('../editTree/xml'); + var editorUtils = require('../utils/editor'); + var actionUtils = require('../utils/action'); + var utils = require('../utils/common'); + var parser = require('../parser/abbreviation'); + + function updateAttributes(tag, abbrNode, ix) { + var classNames = (abbrNode.attribute('class') || '').split(/\s+/g); + if (ix) { + classNames.push('+' + abbrNode.name()); + } + + var r = function(str) { + return utils.replaceCounter(str, abbrNode.counter); + }; + + // update class + classNames.forEach(function(className) { + if (!className) { + return; + } + + className = r(className); + var ch = className.charAt(0); + if (ch == '+') { + tag.addClass(className.substr(1)); + } else if (ch == '-') { + tag.removeClass(className.substr(1)); + } else { + tag.value('class', className); + } + }); + + // update attributes + abbrNode.attributeList().forEach(function(attr) { + if (attr.name.toLowerCase() == 'class') { + return; + } + + var ch = attr.name.charAt(0); + if (ch == '+') { + var attrName = attr.name.substr(1); + var tagAttr = tag.get(attrName); + if (tagAttr) { + tagAttr.value(tagAttr.value() + r(attr.value)); + } else { + tag.value(attrName, r(attr.value)); + } + } else if (ch == '-') { + tag.remove(attr.name.substr(1)); + } else { + tag.value(attr.name, r(attr.value)); + } + }); + } + + return { + /** + * Matches HTML tag under caret and updates its definition + * according to given abbreviation + * @param {IEmmetEditor} Editor instance + * @param {String} abbr Abbreviation to update with + */ + updateTagAction: function(editor, abbr) { + abbr = abbr || editor.prompt("Enter abbreviation"); + + if (!abbr) { + return false; + } + + var content = editor.getContent(); + var ctx = actionUtils.captureContext(editor); + var tag = this.getUpdatedTag(abbr, ctx, content); + + if (!tag) { + // nothing to update + return false; + } + + // check if tag name was updated + if (tag.name() != ctx.name && ctx.match.close) { + editor.replaceContent('', ctx.match.close.range.start, ctx.match.close.range.end, true); + } + + editor.replaceContent(tag.source, ctx.match.open.range.start, ctx.match.open.range.end, true); + return true; + }, + + /** + * Returns XMLEditContainer node with updated tag structure + * of existing tag context. + * This data can be used to modify existing tag + * @param {String} abbr Abbreviation + * @param {Object} ctx Tag to be updated (captured with `htmlMatcher`) + * @param {String} content Original editor content + * @return {XMLEditContainer} + */ + getUpdatedTag: function(abbr, ctx, content, options) { + if (!ctx) { + // nothing to update + return null; + } + + var tree = parser.parse(abbr, options || {}); + + // for this action some characters in abbreviation has special + // meaning. For example, `.-c2` means “remove `c2` class from + // element” and `.+c3` means “append class `c3` to exising one. + // + // But `.+c3` abbreviation will actually produce two elements: + //
and . Thus, we have to walk on each element + // of parsed tree and use their definitions to update current element + var tag = xmlEditTree.parse(ctx.match.open.range.substring(content), { + offset: ctx.match.outerRange.start + }); + + tree.children.forEach(function(node, i) { + updateAttributes(tag, node, i); + }); + + // if tag name was resolved by implicit tag name resolver, + // then user omitted it in abbreviation and wants to keep + // original tag name + var el = tree.children[0]; + if (!el.data('nameResolved')) { + tag.name(el.name()); + } + + return tag; + } + }; +}); +},{"../editTree/xml":"editTree/xml.js","../parser/abbreviation":"parser/abbreviation.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"action/wrapWithAbbreviation.js":[function(require,module,exports){ +/** + * Action that wraps content with abbreviation. For convenience, action is + * defined as reusable module + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var range = require('../assets/range'); + var htmlMatcher = require('../assets/htmlMatcher'); + var utils = require('../utils/common'); + var editorUtils = require('../utils/editor'); + var actionUtils = require('../utils/action'); + var parser = require('../parser/abbreviation'); + + return { + /** + * Wraps content with abbreviation + * @param {IEmmetEditor} Editor instance + * @param {String} abbr Abbreviation to wrap with + * @param {String} syntax Syntax type (html, css, etc.) + * @param {String} profile Output profile name (html, xml, xhtml) + */ + wrapWithAbbreviationAction: function(editor, abbr, syntax, profile) { + var info = editorUtils.outputInfo(editor, syntax, profile); + abbr = abbr || editor.prompt("Enter abbreviation"); + + if (!abbr) { + return null; + } + + abbr = String(abbr); + + var r = range(editor.getSelectionRange()); + + if (!r.length()) { + // no selection, find tag pair + var match = htmlMatcher.tag(info.content, r.start); + if (!match) { // nothing to wrap + return false; + } + + r = utils.narrowToNonSpace(info.content, match.range); + } + + var newContent = utils.escapeText(r.substring(info.content)); + var result = parser.expand(abbr, { + pastedContent: editorUtils.unindent(editor, newContent), + syntax: info.syntax, + profile: info.profile, + contextNode: actionUtils.captureContext(editor) + }); + + if (result) { + editor.replaceContent(result, r.start, r.end); + return true; + } + + return false; + } + }; +}); +},{"../assets/htmlMatcher":"assets/htmlMatcher.js","../assets/range":"assets/range.js","../parser/abbreviation":"parser/abbreviation.js","../utils/action":"utils/action.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js"}],"assets/caniuse.js":[function(require,module,exports){ +/** + * Parsed resources (snippets, abbreviations, variables, etc.) for Emmet. + * Contains convenient method to get access for snippets with respect of + * inheritance. Also provides ability to store data in different vocabularies + * ('system' and 'user') for fast and safe resource update + * @author Sergey Chikuyonok (serge.che@gmail.com) + * @link http://chikuyonok.ru + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('./preferences'); + var utils = require('../utils/common'); + + prefs.define('caniuse.enabled', true, 'Enable support of Can I Use database. When enabled,\ + CSS abbreviation resolver will look at Can I Use database first before detecting\ + CSS properties that should be resolved'); + + prefs.define('caniuse.vendors', 'all', 'A comma-separated list vendor identifiers\ + (as described in Can I Use database) that should be supported\ + when resolving vendor-prefixed properties. Set value to all\ + to support all available properties'); + + prefs.define('caniuse.era', 'e-2', 'Browser era, as defined in Can I Use database.\ + Examples: e0 (current version), e1 (near future)\ + e-2 (2 versions back) and so on.'); + + var cssSections = { + 'border-image': ['border-image'], + 'css-boxshadow': ['box-shadow'], + 'css3-boxsizing': ['box-sizing'], + 'multicolumn': ['column-width', 'column-count', 'columns', 'column-gap', 'column-rule-color', 'column-rule-style', 'column-rule-width', 'column-rule', 'column-span', 'column-fill'], + 'border-radius': ['border-radius', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-right-radius', 'border-bottom-left-radius'], + 'transforms2d': ['transform'], + 'css-hyphens': ['hyphens'], + 'css-transitions': ['transition', 'transition-property', 'transition-duration', 'transition-timing-function', 'transition-delay'], + 'font-feature': ['font-feature-settings'], + 'css-animation': ['animation', 'animation-name', 'animation-duration', 'animation-timing-function', 'animation-iteration-count', 'animation-direction', 'animation-play-state', 'animation-delay', 'animation-fill-mode', '@keyframes'], + 'css-gradients': ['linear-gradient'], + 'css-masks': ['mask-image', 'mask-source-type', 'mask-repeat', 'mask-position', 'mask-clip', 'mask-origin', 'mask-size', 'mask', 'mask-type', 'mask-box-image-source', 'mask-box-image-slice', 'mask-box-image-width', 'mask-box-image-outset', 'mask-box-image-repeat', 'mask-box-image', 'clip-path', 'clip-rule'], + 'css-featurequeries': ['@supports'], + 'flexbox': ['flex', 'inline-flex', 'flex-direction', 'flex-wrap', 'flex-flow', 'order', 'flex'], + 'calc': ['calc'], + 'object-fit': ['object-fit', 'object-position'], + 'css-grid': ['grid', 'inline-grid', 'grid-template-rows', 'grid-template-columns', 'grid-template-areas', 'grid-template', 'grid-auto-rows', 'grid-auto-columns', ' grid-auto-flow', 'grid-auto-position', 'grid', ' grid-row-start', 'grid-column-start', 'grid-row-end', 'grid-column-end', 'grid-column', 'grid-row', 'grid-area', 'justify-self', 'justify-items', 'align-self', 'align-items'], + 'css-repeating-gradients': ['repeating-linear-gradient'], + 'css-filters': ['filter'], + 'user-select-none': ['user-select'], + 'intrinsic-width': ['min-content', 'max-content', 'fit-content', 'fill-available'], + 'css3-tabsize': ['tab-size'] + }; + + /** @type {Object} The Can I Use database for CSS */ + var cssDB = null; + /** @type {Object} A list of available vendors (browsers) and their prefixes */ + var vendorsDB = null; + var erasDB = null; + + function intersection(arr1, arr2) { + var result = []; + var smaller = arr1, larger = arr2; + if (smaller.length > larger.length) { + smaller = arr2; + larger = arr1; + } + larger.forEach(function(item) { + if (~smaller.indexOf(item)) { + result.push(item); + } + }); + return result; + } + + /** + * Parses raw Can I Use database for better lookups + * @param {String} data Raw database + * @param {Boolean} optimized Pass `true` if given `data` is already optimized + * @return {Object} + */ + function parseDB(data, optimized) { + if (typeof data == 'string') { + data = JSON.parse(data); + } + + if (!optimized) { + data = optimize(data); + } + + vendorsDB = data.vendors; + cssDB = data.css; + erasDB = data.era; + } + + /** + * Extract required data only from CIU database + * @param {Object} data Raw Can I Use database + * @return {Object} Optimized database + */ + function optimize(data) { + if (typeof data == 'string') { + data = JSON.parse(data); + } + + return { + vendors: parseVendors(data), + css: parseCSS(data), + era: parseEra(data) + }; + } + + /** + * Parses vendor data + * @param {Object} data + * @return {Object} + */ + function parseVendors(data) { + var out = {}; + Object.keys(data.agents).forEach(function(name) { + var agent = data.agents[name]; + out[name] = { + prefix: agent.prefix, + versions: agent.versions + }; + }); + return out; + } + + /** + * Parses CSS data from Can I Use raw database + * @param {Object} data + * @return {Object} + */ + function parseCSS(data) { + var out = {}; + var cssCategories = data.cats.CSS; + Object.keys(data.data).forEach(function(name) { + var section = data.data[name]; + if (name in cssSections) { + cssSections[name].forEach(function(kw) { + out[kw] = section.stats; + }); + } + }); + + return out; + } + + /** + * Parses era data from Can I Use raw database + * @param {Object} data + * @return {Array} + */ + function parseEra(data) { + // some runtimes (like Mozilla Rhino) does not preserves + // key order so we have to sort values manually + return Object.keys(data.eras).sort(function(a, b) { + return parseInt(a.substr(1)) - parseInt(b.substr(1)); + }); + } + + /** + * Returs list of supported vendors, depending on user preferences + * @return {Array} + */ + function getVendorsList() { + var allVendors = Object.keys(vendorsDB); + var vendors = prefs.getArray('caniuse.vendors'); + if (!vendors || vendors[0] == 'all') { + return allVendors; + } + + return intersection(allVendors, vendors); + } + + /** + * Returns size of version slice as defined by era identifier + * @return {Number} + */ + function getVersionSlice() { + var era = prefs.get('caniuse.era'); + var ix = erasDB.indexOf(era); + if (!~ix) { + ix = erasDB.indexOf('e-2'); + } + + return ix; + } + + // try to load caniuse database + // hide it from Require.JS parser + var db = null; + (function(r) { + if (typeof define === 'undefined' || !define.amd) { + try { + var fs = r('fs'); + var path = r('path'); + db = fs.readFileSync(path.join(__dirname, '../caniuse.json'), {encoding: 'utf8'}); + } catch(e) {} + } + })(require); + + if (db) { + parseDB(db); + } + + return { + load: parseDB, + optimize: optimize, + + /** + * Resolves prefixes for given property + * @param {String} property A property to resolve. It can start with `@` symbol + * (CSS section, like `@keyframes`) or `:` (CSS value, like `flex`) + * @return {Array} Array of resolved prefixes or null + * if prefixes can't be resolved. Empty array means property has no vendor + * prefixes + */ + resolvePrefixes: function(property) { + if (!prefs.get('caniuse.enabled') || !cssDB || !(property in cssDB)) { + return null; + } + + var prefixes = []; + var propStats = cssDB[property]; + var versions = getVersionSlice(); + + getVendorsList().forEach(function(vendor) { + var vendorVesions = vendorsDB[vendor].versions.slice(versions); + for (var i = 0, v; i < vendorVesions.length; i++) { + v = vendorVesions[i]; + if (!v) { + continue; + } + + if (~propStats[vendor][v].indexOf('x')) { + prefixes.push(vendorsDB[vendor].prefix); + break; + } + } + }); + + return utils.unique(prefixes).sort(function(a, b) { + return b.length - a.length; + }); + } + }; +}); +},{"../utils/common":"utils/common.js","./preferences":"assets/preferences.js"}],"assets/elements.js":[function(require,module,exports){ +/** + * Module that contains factories for element types used by Emmet + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var factories = {}; + var reAttrs = /([@\!]?)([\w\-:]+)\s*=\s*(['"])(.*?)\3/g; + + // register resource references + function commonFactory(value) { + return {data: value}; + } + + module = module || {}; + module.exports = { + /** + * Create new element factory + * @param {String} name Element identifier + * @param {Function} factory Function that produces element of specified + * type. The object generated by this factory is automatically + * augmented with type property pointing to element + * name + * @memberOf elements + */ + add: function(name, factory) { + var that = this; + factories[name] = function() { + var elem = factory.apply(that, arguments); + if (elem) + elem.type = name; + + return elem; + }; + }, + + /** + * Returns factory for specified name + * @param {String} name + * @returns {Function} + */ + get: function(name) { + return factories[name]; + }, + + /** + * Creates new element with specified type + * @param {String} name + * @returns {Object} + */ + create: function(name) { + var args = [].slice.call(arguments, 1); + var factory = this.get(name); + return factory ? factory.apply(this, args) : null; + }, + + /** + * Check if passed element is of specified type + * @param {Object} elem + * @param {String} type + * @returns {Boolean} + */ + is: function(elem, type) { + return this.type(elem) === type; + }, + + /** + * Returns type of element + * @param {Object} elem + * @return {String} + */ + type: function(elem) { + return elem && elem.type; + } + }; + + /** + * Element factory + * @param {String} elementName Name of output element + * @param {String} attrs Attributes definition. You may also pass + * Array where each contains object with name + * and value properties, or Object + * @param {Boolean} isEmpty Is expanded element should be empty + */ + module.exports.add('element', function(elementName, attrs, isEmpty) { + var ret = { + name: elementName, + is_empty: !!isEmpty + }; + + if (attrs) { + ret.attributes = []; + if (Array.isArray(attrs)) { + ret.attributes = attrs; + } else if (typeof attrs === 'string') { + var m; + while ((m = reAttrs.exec(attrs))) { + ret.attributes.push({ + name: m[2], + value: m[4], + isDefault: m[1] == '@', + isImplied: m[1] == '!' + }); + } + } else { + ret.attributes = Object.keys(attrs).map(function(name) { + return { + name: name, + value: attrs[name] + }; + }); + } + } + + return ret; + }); + + module.exports.add('snippet', commonFactory); + module.exports.add('reference', commonFactory); + module.exports.add('empty', function() { + return {}; + }); + + return module.exports; +}); +},{}],"assets/handlerList.js":[function(require,module,exports){ +/** + * Utility module that provides ordered storage of function handlers. + * Many Emmet modules' functionality can be extended/overridden by custom + * function. This modules provides unified storage of handler functions, their + * management and execution + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + + /** + * @type HandlerList + * @constructor + */ + function HandlerList() { + this._list = []; + } + + HandlerList.prototype = { + /** + * Adds function handler + * @param {Function} fn Handler + * @param {Object} options Handler options. Possible values are:

+ * order : (Number) – order in handler list. Handlers + * with higher order value will be executed earlier. + */ + add: function(fn, options) { + // TODO hack for stable sort, remove after fixing `list()` + var order = this._list.length; + if (options && 'order' in options) { + order = options.order * 10000; + } + this._list.push(utils.extend({}, options, {order: order, fn: fn})); + }, + + /** + * Removes handler from list + * @param {Function} fn + */ + remove: function(fn) { + var item = utils.find(this._list, function(item) { + return item.fn === fn; + }); + if (item) { + this._list.splice(this._list.indexOf(item), 1); + } + }, + + /** + * Returns ordered list of handlers. By default, handlers + * with the same order option returned in reverse order, + * i.e. the latter function was added into the handlers list, the higher + * it will be in the returned array + * @returns {Array} + */ + list: function() { + // TODO make stable sort + return this._list.sort(function(a, b) { + return b.order - a.order; + }); + }, + + /** + * Returns ordered list of handler functions + * @returns {Array} + */ + listFn: function() { + return this.list().map(function(item) { + return item.fn; + }); + }, + + /** + * Executes handler functions in their designated order. If function + * returns skipVal, meaning that function was unable to + * handle passed args, the next function will be executed + * and so on. + * @param {Object} skipValue If function returns this value, execute + * next handler. + * @param {Array} args Arguments to pass to handler function + * @returns {Boolean} Whether any of registered handlers performed + * successfully + */ + exec: function(skipValue, args) { + args = args || []; + var result = null; + utils.find(this.list(), function(h) { + result = h.fn.apply(h, args); + if (result !== skipValue) { + return true; + } + }); + + return result; + } + }; + + return { + /** + * Factory method that produces HandlerList instance + * @returns {HandlerList} + * @memberOf handlerList + */ + create: function() { + return new HandlerList(); + } + }; +}); +},{"../utils/common":"utils/common.js"}],"assets/htmlMatcher.js":[function(require,module,exports){ +/** + * HTML matcher: takes string and searches for HTML tag pairs for given position + * + * Unlike “classic” matchers, it parses content from the specified + * position, not from the start, so it may work even outside HTML documents + * (for example, inside strings of programming languages like JavaScript, Python + * etc.) + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var range = require('./range'); + + // Regular Expressions for parsing tags and attributes + var reOpenTag = /^<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; + var reCloseTag = /^<\/([\w\:\-]+)[^>]*>/; + + function openTag(i, match) { + return { + name: match[1], + selfClose: !!match[3], + /** @type Range */ + range: range(i, match[0]), + type: 'open' + }; + } + + function closeTag(i, match) { + return { + name: match[1], + /** @type Range */ + range: range(i, match[0]), + type: 'close' + }; + } + + function comment(i, match) { + return { + /** @type Range */ + range: range(i, typeof match == 'number' ? match - i : match[0]), + type: 'comment' + }; + } + + /** + * Creates new tag matcher session + * @param {String} text + */ + function createMatcher(text) { + var memo = {}, m; + return { + /** + * Test if given position matches opening tag + * @param {Number} i + * @returns {Object} Matched tag object + */ + open: function(i) { + var m = this.matches(i); + return m && m.type == 'open' ? m : null; + }, + + /** + * Test if given position matches closing tag + * @param {Number} i + * @returns {Object} Matched tag object + */ + close: function(i) { + var m = this.matches(i); + return m && m.type == 'close' ? m : null; + }, + + /** + * Matches either opening or closing tag for given position + * @param i + * @returns + */ + matches: function(i) { + var key = 'p' + i; + + if (!(key in memo)) { + memo[key] = false; + if (text.charAt(i) == '<') { + var substr = text.slice(i); + if ((m = substr.match(reOpenTag))) { + memo[key] = openTag(i, m); + } else if ((m = substr.match(reCloseTag))) { + memo[key] = closeTag(i, m); + } + } + } + + return memo[key]; + }, + + /** + * Returns original text + * @returns {String} + */ + text: function() { + return text; + }, + + clean: function() { + memo = text = m = null; + } + }; + } + + function matches(text, pos, pattern) { + return text.substring(pos, pos + pattern.length) == pattern; + } + + /** + * Search for closing pair of opening tag + * @param {Object} open Open tag instance + * @param {Object} matcher Matcher instance + */ + function findClosingPair(open, matcher) { + var stack = [], tag = null; + var text = matcher.text(); + + for (var pos = open.range.end, len = text.length; pos < len; pos++) { + if (matches(text, pos, '')) { + pos = j + 3; + break; + } + } + } + + if ((tag = matcher.matches(pos))) { + if (tag.type == 'open' && !tag.selfClose) { + stack.push(tag.name); + } else if (tag.type == 'close') { + if (!stack.length) { // found valid pair? + return tag.name == open.name ? tag : null; + } + + // check if current closing tag matches previously opened one + if (stack[stack.length - 1] == tag.name) { + stack.pop(); + } else { + var found = false; + while (stack.length && !found) { + var last = stack.pop(); + if (last == tag.name) { + found = true; + } + } + + if (!stack.length && !found) { + return tag.name == open.name ? tag : null; + } + } + } + + pos = tag.range.end - 1; + } + } + } + + return { + /** + * Main function: search for tag pair in text for given + * position + * @memberOf htmlMatcher + * @param {String} text + * @param {Number} pos + * @returns {Object} + */ + find: function(text, pos) { + var matcher = createMatcher(text); + var open = null, close = null; + var j, jl; + + for (var i = pos; i >= 0; i--) { + if ((open = matcher.open(i))) { + // found opening tag + if (open.selfClose) { + if (open.range.cmp(pos, 'lt', 'gt')) { + // inside self-closing tag, found match + break; + } + + // outside self-closing tag, continue + continue; + } + + close = findClosingPair(open, matcher); + if (close) { + // found closing tag. + var r = range.create2(open.range.start, close.range.end); + if (r.contains(pos)) { + break; + } + } else if (open.range.contains(pos)) { + // we inside empty HTML tag like
+ break; + } + + open = null; + } else if (matches(text, i, '-->')) { + // skip back to comment start + for (j = i - 1; j >= 0; j--) { + if (matches(text, j, '-->')) { + // found another comment end, do nothing + break; + } else if (matches(text, j, '')) { + j += 3; + break; + } + } + + open = comment(i, j); + break; + } + } + + matcher.clean(); + + if (open) { + var outerRange = null; + var innerRange = null; + + if (close) { + outerRange = range.create2(open.range.start, close.range.end); + innerRange = range.create2(open.range.end, close.range.start); + } else { + outerRange = innerRange = range.create2(open.range.start, open.range.end); + } + + if (open.type == 'comment') { + // adjust positions of inner range for comment + var _c = outerRange.substring(text); + innerRange.start += _c.length - _c.replace(/^<\!--\s*/, '').length; + innerRange.end -= _c.length - _c.replace(/\s*-->$/, '').length; + } + + return { + open: open, + close: close, + type: open.type == 'comment' ? 'comment' : 'tag', + innerRange: innerRange, + innerContent: function() { + return this.innerRange.substring(text); + }, + outerRange: outerRange, + outerContent: function() { + return this.outerRange.substring(text); + }, + range: !innerRange.length() || !innerRange.cmp(pos, 'lte', 'gte') ? outerRange : innerRange, + content: function() { + return this.range.substring(text); + }, + source: text + }; + } + }, + + /** + * The same as find() method, but restricts matched result + * to tag type + * @param {String} text + * @param {Number} pos + * @returns {Object} + */ + tag: function(text, pos) { + var result = this.find(text, pos); + if (result && result.type == 'tag') { + return result; + } + } + }; +}); +},{"./range":"assets/range.js"}],"assets/logger.js":[function(require,module,exports){ +/** + * Simple logger for Emmet + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + return { + log: function() { + if (typeof console != 'undefined' && console.log) { + console.log.apply(console, arguments); + } + } + } +}) +},{}],"assets/preferences.js":[function(require,module,exports){ +/** + * Common module's preferences storage. This module + * provides general storage for all module preferences, their description and + * default values.

+ * + * This module can also be used to list all available properties to create + * UI for updating properties + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + + var preferences = {}; + var defaults = {}; + var _dbgDefaults = null; + var _dbgPreferences = null; + + function toBoolean(val) { + if (typeof val === 'string') { + val = val.toLowerCase(); + return val == 'yes' || val == 'true' || val == '1'; + } + + return !!val; + } + + function isValueObj(obj) { + return typeof obj === 'object' + && !Array.isArray(obj) + && 'value' in obj + && Object.keys(obj).length < 3; + } + + return { + /** + * Creates new preference item with default value + * @param {String} name Preference name. You can also pass object + * with many options + * @param {Object} value Preference default value + * @param {String} description Item textual description + * @memberOf preferences + */ + define: function(name, value, description) { + var prefs = name; + if (typeof name === 'string') { + prefs = {}; + prefs[name] = { + value: value, + description: description + }; + } + + Object.keys(prefs).forEach(function(k) { + var v = prefs[k]; + defaults[k] = isValueObj(v) ? v : {value: v}; + }); + }, + + /** + * Updates preference item value. Preference value should be defined + * first with define method. + * @param {String} name Preference name. You can also pass object + * with many options + * @param {Object} value Preference default value + * @memberOf preferences + */ + set: function(name, value) { + var prefs = name; + if (typeof name === 'string') { + prefs = {}; + prefs[name] = value; + } + + Object.keys(prefs).forEach(function(k) { + var v = prefs[k]; + if (!(k in defaults)) { + throw new Error('Property "' + k + '" is not defined. You should define it first with `define` method of current module'); + } + + // do not set value if it equals to default value + if (v !== defaults[k].value) { + // make sure we have value of correct type + switch (typeof defaults[k].value) { + case 'boolean': + v = toBoolean(v); + break; + case 'number': + v = parseInt(v + '', 10) || 0; + break; + default: // convert to string + if (v !== null) { + v += ''; + } + } + + preferences[k] = v; + } else if (k in preferences) { + delete preferences[k]; + } + }); + }, + + /** + * Returns preference value + * @param {String} name + * @returns {String} Returns undefined if preference is + * not defined + */ + get: function(name) { + if (name in preferences) { + return preferences[name]; + } + + if (name in defaults) { + return defaults[name].value; + } + + return void 0; + }, + + /** + * Returns comma-separated preference value as array of values + * @param {String} name + * @returns {Array} Returns undefined if preference is + * not defined, null if string cannot be converted to array + */ + getArray: function(name) { + var val = this.get(name); + if (typeof val === 'undefined' || val === null || val === '') { + return null; + } + + val = val.split(',').map(utils.trim); + if (!val.length) { + return null; + } + + return val; + }, + + /** + * Returns comma and colon-separated preference value as dictionary + * @param {String} name + * @returns {Object} + */ + getDict: function(name) { + var result = {}; + this.getArray(name).forEach(function(val) { + var parts = val.split(':'); + result[parts[0]] = parts[1]; + }); + + return result; + }, + + /** + * Returns description of preference item + * @param {String} name Preference name + * @returns {Object} + */ + description: function(name) { + return name in defaults ? defaults[name].description : void 0; + }, + + /** + * Completely removes specified preference(s) + * @param {String} name Preference name (or array of names) + */ + remove: function(name) { + if (!Array.isArray(name)) { + name = [name]; + } + + name.forEach(function(key) { + if (key in preferences) { + delete preferences[key]; + } + + if (key in defaults) { + delete defaults[key]; + } + }); + }, + + /** + * Returns sorted list of all available properties + * @returns {Array} + */ + list: function() { + return Object.keys(defaults).sort().map(function(key) { + return { + name: key, + value: this.get(key), + type: typeof defaults[key].value, + description: defaults[key].description + }; + }, this); + }, + + /** + * Loads user-defined preferences from JSON + * @param {Object} json + * @returns + */ + load: function(json) { + Object.keys(json).forEach(function(key) { + this.set(key, json[key]); + }, this); + }, + + /** + * Returns hash of user-modified preferences + * @returns {Object} + */ + exportModified: function() { + return utils.extend({}, preferences); + }, + + /** + * Reset to defaults + * @returns + */ + reset: function() { + preferences = {}; + }, + + /** + * For unit testing: use empty storage + */ + _startTest: function() { + _dbgDefaults = defaults; + _dbgPreferences = preferences; + defaults = {}; + preferences = {}; + }, + + /** + * For unit testing: restore original storage + */ + _stopTest: function() { + defaults = _dbgDefaults; + preferences = _dbgPreferences; + } + }; +}); +},{"../utils/common":"utils/common.js"}],"assets/profile.js":[function(require,module,exports){ +/** + * Output profile module. + * Profile defines how XHTML output data should look like + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var resources = require('./resources'); + var prefs = require('./preferences'); + + prefs.define('profile.allowCompactBoolean', true, + 'This option can be used to globally disable compact form of boolean ' + + 'attribues (attributes where name and value are equal). With compact' + + 'form enabled, HTML tags can be outputted as <div contenteditable> ' + + 'instead of <div contenteditable="contenteditable">'); + + prefs.define('profile.booleanAttributes', '^contenteditable|seamless$', + 'A regular expression for attributes that should be boolean by default.' + + 'If attribute name matches this expression, you don’t have to write dot ' + + 'after attribute name in Emmet abbreviation to mark it as boolean.'); + + var profiles = {}; + + var defaultProfile = { + tag_case: 'asis', + attr_case: 'asis', + attr_quotes: 'double', + + // Each tag on new line + tag_nl: 'decide', + + // With tag_nl === true, defines if leaf node (e.g. node with no children) + // should have formatted line breaks + tag_nl_leaf: false, + + place_cursor: true, + + // Indent tags + indent: true, + + // How many inline elements should be to force line break + // (set to 0 to disable) + inline_break: 3, + + // Produce compact notation of boolean attribues: + // attributes where name and value are equal. + // With this option enabled, HTML filter will + // produce
instead of
+ compact_bool: false, + + // Use self-closing style for writing empty elements, e.g.
or
+ self_closing_tag: 'xhtml', + + // Profile-level output filters, re-defines syntax filters + filters: '', + + // Additional filters applied to abbreviation. + // Unlike "filters", this preference doesn't override default filters + // but add the instead every time given profile is chosen + extraFilters: '' + }; + + /** + * @constructor + * @type OutputProfile + * @param {Object} options + */ + function OutputProfile(options) { + utils.extend(this, defaultProfile, options); + } + + OutputProfile.prototype = { + /** + * Transforms tag name case depending on current profile settings + * @param {String} name String to transform + * @returns {String} + */ + tagName: function(name) { + return stringCase(name, this.tag_case); + }, + + /** + * Transforms attribute name case depending on current profile settings + * @param {String} name String to transform + * @returns {String} + */ + attributeName: function(name) { + return stringCase(name, this.attr_case); + }, + + /** + * Returns quote character for current profile + * @returns {String} + */ + attributeQuote: function() { + return this.attr_quotes == 'single' ? "'" : '"'; + }, + + /** + * Returns self-closing tag symbol for current profile + * @returns {String} + */ + selfClosing: function() { + if (this.self_closing_tag == 'xhtml') + return ' /'; + + if (this.self_closing_tag === true) + return '/'; + + return ''; + }, + + /** + * Returns cursor token based on current profile settings + * @returns {String} + */ + cursor: function() { + return this.place_cursor ? utils.getCaretPlaceholder() : ''; + }, + + /** + * Check if attribute with given name is boolean, + * e.g. written as `contenteditable` instead of + * `contenteditable="contenteditable"` + * @param {String} name Attribute name + * @return {Boolean} + */ + isBoolean: function(name, value) { + if (name == value) { + return true; + } + + var boolAttrs = prefs.get('profile.booleanAttributes'); + if (!value && boolAttrs) { + boolAttrs = new RegExp(boolAttrs, 'i'); + return boolAttrs.test(name); + } + + return false; + }, + + /** + * Check if compact boolean attribute record is + * allowed for current profile + * @return {Boolean} + */ + allowCompactBoolean: function() { + return this.compact_bool && prefs.get('profile.allowCompactBoolean'); + } + }; + + /** + * Helper function that converts string case depending on + * caseValue + * @param {String} str String to transform + * @param {String} caseValue Case value: can be lower, + * upper and leave + * @returns {String} + */ + function stringCase(str, caseValue) { + switch (String(caseValue || '').toLowerCase()) { + case 'lower': + return str.toLowerCase(); + case 'upper': + return str.toUpperCase(); + } + + return str; + } + + /** + * Creates new output profile + * @param {String} name Profile name + * @param {Object} options Profile options + */ + function createProfile(name, options) { + return profiles[name.toLowerCase()] = new OutputProfile(options); + } + + function createDefaultProfiles() { + createProfile('xhtml'); + createProfile('html', {self_closing_tag: false, compact_bool: true}); + createProfile('xml', {self_closing_tag: true, tag_nl: true}); + createProfile('plain', {tag_nl: false, indent: false, place_cursor: false}); + createProfile('line', {tag_nl: false, indent: false, extraFilters: 's'}); + createProfile('css', {tag_nl: true}); + createProfile('css_line', {tag_nl: false}); + } + + createDefaultProfiles(); + + return { + /** + * Creates new output profile and adds it into internal dictionary + * @param {String} name Profile name + * @param {Object} options Profile options + * @memberOf emmet.profile + * @returns {Object} New profile + */ + create: function(name, options) { + if (arguments.length == 2) + return createProfile(name, options); + else + // create profile object only + return new OutputProfile(utils.defaults(name || {}, defaultProfile)); + }, + + /** + * Returns profile by its name. If profile wasn't found, returns + * 'plain' profile + * @param {String} name Profile name. Might be profile itself + * @param {String} syntax. Optional. Current editor syntax. If defined, + * profile is searched in resources first, then in predefined profiles + * @returns {Object} + */ + get: function(name, syntax) { + if (!name && syntax) { + // search in user resources first + var profile = resources.findItem(syntax, 'profile'); + if (profile) { + name = profile; + } + } + + if (!name) { + return profiles.plain; + } + + if (name instanceof OutputProfile) { + return name; + } + + if (typeof name === 'string' && name.toLowerCase() in profiles) { + return profiles[name.toLowerCase()]; + } + + return this.create(name); + }, + + /** + * Deletes profile with specified name + * @param {String} name Profile name + */ + remove: function(name) { + name = (name || '').toLowerCase(); + if (name in profiles) + delete profiles[name]; + }, + + /** + * Resets all user-defined profiles + */ + reset: function() { + profiles = {}; + createDefaultProfiles(); + }, + + /** + * Helper function that converts string case depending on + * caseValue + * @param {String} str String to transform + * @param {String} caseValue Case value: can be lower, + * upper and leave + * @returns {String} + */ + stringCase: stringCase + }; +}); +},{"../utils/common":"utils/common.js","./preferences":"assets/preferences.js","./resources":"assets/resources.js"}],"assets/range.js":[function(require,module,exports){ +/** + * Helper module to work with ranges + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + function cmp(a, b, op) { + switch (op) { + case 'eq': + case '==': + return a === b; + case 'lt': + case '<': + return a < b; + case 'lte': + case '<=': + return a <= b; + case 'gt': + case '>': + return a > b; + case 'gte': + case '>=': + return a >= b; + } + } + + + /** + * @type Range + * @constructor + * @param {Object} start + * @param {Number} len + */ + function Range(start, len) { + if (typeof start === 'object' && 'start' in start) { + // create range from object stub + this.start = Math.min(start.start, start.end); + this.end = Math.max(start.start, start.end); + } else if (Array.isArray(start)) { + this.start = start[0]; + this.end = start[1]; + } else { + len = typeof len === 'string' ? len.length : +len; + this.start = start; + this.end = start + len; + } + } + + Range.prototype = { + length: function() { + return Math.abs(this.end - this.start); + }, + + /** + * Returns true if passed range is equals to current one + * @param {Range} range + * @returns {Boolean} + */ + equal: function(range) { + return this.cmp(range, 'eq', 'eq'); +// return this.start === range.start && this.end === range.end; + }, + + /** + * Shifts indexes position with passed delta + * @param {Number} delta + * @returns {Range} range itself + */ + shift: function(delta) { + this.start += delta; + this.end += delta; + return this; + }, + + /** + * Check if two ranges are overlapped + * @param {Range} range + * @returns {Boolean} + */ + overlap: function(range) { + return range.start <= this.end && range.end >= this.start; + }, + + /** + * Finds intersection of two ranges + * @param {Range} range + * @returns {Range} null if ranges does not overlap + */ + intersection: function(range) { + if (this.overlap(range)) { + var start = Math.max(range.start, this.start); + var end = Math.min(range.end, this.end); + return new Range(start, end - start); + } + + return null; + }, + + /** + * Returns the union of the thow ranges. + * @param {Range} range + * @returns {Range} null if ranges are not overlapped + */ + union: function(range) { + if (this.overlap(range)) { + var start = Math.min(range.start, this.start); + var end = Math.max(range.end, this.end); + return new Range(start, end - start); + } + + return null; + }, + + /** + * Returns a Boolean value that indicates whether a specified position + * is in a given range. + * @param {Number} loc + */ + inside: function(loc) { + return this.cmp(loc, 'lte', 'gt'); +// return this.start <= loc && this.end > loc; + }, + + /** + * Returns a Boolean value that indicates whether a specified position + * is in a given range, but not equals bounds. + * @param {Number} loc + */ + contains: function(loc) { + return this.cmp(loc, 'lt', 'gt'); + }, + + /** + * Check if current range completely includes specified one + * @param {Range} r + * @returns {Boolean} + */ + include: function(r) { + return this.cmp(r, 'lte', 'gte'); +// return this.start <= r.start && this.end >= r.end; + }, + + /** + * Low-level comparision method + * @param {Number} loc + * @param {String} left Left comparison operator + * @param {String} right Right comaprison operator + */ + cmp: function(loc, left, right) { + var a, b; + if (loc instanceof Range) { + a = loc.start; + b = loc.end; + } else { + a = b = loc; + } + + return cmp(this.start, a, left || '<=') && cmp(this.end, b, right || '>'); + }, + + /** + * Returns substring of specified str for current range + * @param {String} str + * @returns {String} + */ + substring: function(str) { + return this.length() > 0 + ? str.substring(this.start, this.end) + : ''; + }, + + /** + * Creates copy of current range + * @returns {Range} + */ + clone: function() { + return new Range(this.start, this.length()); + }, + + /** + * @returns {Array} + */ + toArray: function() { + return [this.start, this.end]; + }, + + toString: function() { + return this.valueOf(); + }, + + valueOf: function() { + return '{' + this.start + ', ' + this.length() + '}'; + } + }; + + /** + * Creates new range object instance + * @param {Object} start Range start or array with 'start' and 'end' + * as two first indexes or object with 'start' and 'end' properties + * @param {Number} len Range length or string to produce range from + * @returns {Range} + */ + module.exports = function(start, len) { + if (typeof start == 'undefined' || start === null) + return null; + + if (start instanceof Range) + return start; + + if (typeof start == 'object' && 'start' in start && 'end' in start) { + len = start.end - start.start; + start = start.start; + } + + return new Range(start, len); + }; + + module.exports.create = module.exports; + + module.exports.isRange = function(val) { + return val instanceof Range; + }; + + /** + * Range object factory, the same as this.create() + * but last argument represents end of range, not length + * @returns {Range} + */ + module.exports.create2 = function(start, end) { + if (typeof start === 'number' && typeof end === 'number') { + end -= start; + } + + return this.create(start, end); + }; + + /** + * Helper function that sorts ranges in order as they + * appear in text + * @param {Array} ranges + * @return {Array} + */ + module.exports.sort = function(ranges, reverse) { + ranges = ranges.sort(function(a, b) { + if (a.start === b.start) { + return b.end - a.end; + } + + return a.start - b.start; + }); + + reverse && ranges.reverse(); + return ranges; + }; + + return module.exports; +}); +},{}],"assets/resources.js":[function(require,module,exports){ +/** + * Parsed resources (snippets, abbreviations, variables, etc.) for Emmet. + * Contains convenient method to get access for snippets with respect of + * inheritance. Also provides ability to store data in different vocabularies + * ('system' and 'user') for fast and safe resource update + * @author Sergey Chikuyonok (serge.che@gmail.com) + * @link http://chikuyonok.ru + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var handlerList = require('./handlerList'); + var utils = require('../utils/common'); + var elements = require('./elements'); + var logger = require('../assets/logger'); + var stringScore = require('../vendor/stringScore'); + var cssResolver = require('../resolver/css'); + + var VOC_SYSTEM = 'system'; + var VOC_USER = 'user'; + + var cache = {}; + + /** Regular expression for XML tag matching */ + var reTag = /^<(\w+\:?[\w\-]*)((?:\s+[@\!]?[\w\:\-]+\s*=\s*(['"]).*?\3)*)\s*(\/?)>/; + + var systemSettings = {}; + var userSettings = {}; + + /** @type HandlerList List of registered abbreviation resolvers */ + var resolvers = handlerList.create(); + + function each(obj, fn) { + if (!obj) { + return; + } + + Object.keys(obj).forEach(function(key) { + fn(obj[key], key); + }); + } + + /** + * Normalizes caret plceholder in passed text: replaces | character with + * default caret placeholder + * @param {String} text + * @returns {String} + */ + function normalizeCaretPlaceholder(text) { + return utils.replaceUnescapedSymbol(text, '|', utils.getCaretPlaceholder()); + } + + function parseItem(name, value, type) { + value = normalizeCaretPlaceholder(value); + + if (type == 'snippets') { + return elements.create('snippet', value); + } + + if (type == 'abbreviations') { + return parseAbbreviation(name, value); + } + } + + /** + * Parses single abbreviation + * @param {String} key Abbreviation name + * @param {String} value Abbreviation value + * @return {Object} + */ + function parseAbbreviation(key, value) { + key = utils.trim(key); + var m; + if ((m = reTag.exec(value))) { + return elements.create('element', m[1], m[2], m[4] == '/'); + } else { + // assume it's reference to another abbreviation + return elements.create('reference', value); + } + } + + /** + * Normalizes snippet key name for better fuzzy search + * @param {String} str + * @returns {String} + */ + function normalizeName(str) { + return str.replace(/:$/, '').replace(/:/g, '-'); + } + + function expandSnippetsDefinition(snippets) { + var out = {}; + each(snippets, function(val, key) { + var items = key.split('|'); + // do not use iterators for better performance + for (var i = items.length - 1; i >= 0; i--) { + out[items[i]] = val; + } + }); + + return out; + } + + utils.extend(exports, { + /** + * Sets new unparsed data for specified settings vocabulary + * @param {Object} data + * @param {String} type Vocabulary type ('system' or 'user') + * @memberOf resources + */ + setVocabulary: function(data, type) { + cache = {}; + + // sections like "snippets" and "abbreviations" could have + // definitions like `"f|fs": "fieldset"` which is the same as distinct + // "f" and "fs" keys both equals to "fieldset". + // We should parse these definitions first + var voc = {}; + each(data, function(section, syntax) { + var _section = {}; + each(section, function(subsection, name) { + if (name == 'abbreviations' || name == 'snippets') { + subsection = expandSnippetsDefinition(subsection); + } + _section[name] = subsection; + }); + + voc[syntax] = _section; + }); + + + if (type == VOC_SYSTEM) { + systemSettings = voc; + } else { + userSettings = voc; + } + }, + + /** + * Returns resource vocabulary by its name + * @param {String} name Vocabulary name ('system' or 'user') + * @return {Object} + */ + getVocabulary: function(name) { + return name == VOC_SYSTEM ? systemSettings : userSettings; + }, + + /** + * Returns resource (abbreviation, snippet, etc.) matched for passed + * abbreviation + * @param {AbbreviationNode} node + * @param {String} syntax + * @returns {Object} + */ + getMatchedResource: function(node, syntax) { + return resolvers.exec(null, utils.toArray(arguments)) + || this.findSnippet(syntax, node.name()); + }, + + /** + * Returns variable value + * @return {String} + */ + getVariable: function(name) { + return (this.getSection('variables') || {})[name]; + }, + + /** + * Store runtime variable in user storage + * @param {String} name Variable name + * @param {String} value Variable value + */ + setVariable: function(name, value){ + var voc = this.getVocabulary('user') || {}; + if (!('variables' in voc)) + voc.variables = {}; + + voc.variables[name] = value; + this.setVocabulary(voc, 'user'); + }, + + /** + * Check if there are resources for specified syntax + * @param {String} syntax + * @return {Boolean} + */ + hasSyntax: function(syntax) { + return syntax in this.getVocabulary(VOC_USER) + || syntax in this.getVocabulary(VOC_SYSTEM); + }, + + /** + * Registers new abbreviation resolver. + * @param {Function} fn Abbreviation resolver which will receive + * abbreviation as first argument and should return parsed abbreviation + * object if abbreviation has handled successfully, null + * otherwise + * @param {Object} options Options list as described in + * {@link HandlerList#add()} method + */ + addResolver: function(fn, options) { + resolvers.add(fn, options); + }, + + removeResolver: function(fn) { + resolvers.remove(fn); + }, + + /** + * Returns actual section data, merged from both + * system and user data + * @param {String} name Section name (syntax) + * @param {String} ...args Subsections + * @returns + */ + getSection: function(name) { + if (!name) + return null; + + if (!(name in cache)) { + cache[name] = utils.deepMerge({}, systemSettings[name], userSettings[name]); + } + + var data = cache[name], subsections = utils.toArray(arguments, 1), key; + while (data && (key = subsections.shift())) { + if (key in data) { + data = data[key]; + } else { + return null; + } + } + + return data; + }, + + /** + * Recursively searches for a item inside top level sections (syntaxes) + * with respect of `extends` attribute + * @param {String} topSection Top section name (syntax) + * @param {String} subsection Inner section name + * @returns {Object} + */ + findItem: function(topSection, subsection) { + var data = this.getSection(topSection); + while (data) { + if (subsection in data) + return data[subsection]; + + data = this.getSection(data['extends']); + } + }, + + /** + * Recursively searches for a snippet definition inside syntax section. + * Definition is searched inside `snippets` and `abbreviations` + * subsections + * @param {String} syntax Top-level section name (syntax) + * @param {String} name Snippet name + * @returns {Object} + */ + findSnippet: function(syntax, name, memo) { + if (!syntax || !name) + return null; + + memo = memo || []; + + var names = [name]; + // create automatic aliases to properties with colons, + // e.g. pos-a == pos:a + if (~name.indexOf('-')) { + names.push(name.replace(/\-/g, ':')); + } + + var data = this.getSection(syntax), matchedItem = null; + ['snippets', 'abbreviations'].some(function(sectionName) { + var data = this.getSection(syntax, sectionName); + if (data) { + return names.some(function(n) { + if (data[n]) { + return matchedItem = parseItem(n, data[n], sectionName); + } + }); + } + }, this); + + memo.push(syntax); + if (!matchedItem && data['extends'] && !~memo.indexOf(data['extends'])) { + // try to find item in parent syntax section + return this.findSnippet(data['extends'], name, memo); + } + + return matchedItem; + }, + + /** + * Performs fuzzy search of snippet definition + * @param {String} syntax Top-level section name (syntax) + * @param {String} name Snippet name + * @returns + */ + fuzzyFindSnippet: function(syntax, name, minScore) { + var result = this.fuzzyFindMatches(syntax, name, minScore)[0]; + if (result) { + return result.value.parsedValue; + } + }, + + fuzzyFindMatches: function(syntax, name, minScore) { + minScore = minScore || 0.3; + name = normalizeName(name); + var snippets = this.getAllSnippets(syntax); + + return Object.keys(snippets) + .map(function(key) { + var value = snippets[key]; + return { + key: key, + score: stringScore.score(value.nk, name, 0.1), + value: value + }; + }) + .filter(function(item) { + return item.score >= minScore; + }) + .sort(function(a, b) { + return a.score - b.score; + }) + .reverse(); + }, + + /** + * Returns plain dictionary of all available abbreviations and snippets + * for specified syntax with respect of inheritance + * @param {String} syntax + * @returns {Object} + */ + getAllSnippets: function(syntax) { + var cacheKey = 'all-' + syntax; + if (!cache[cacheKey]) { + var stack = [], sectionKey = syntax; + var memo = []; + + do { + var section = this.getSection(sectionKey); + if (!section) + break; + + ['snippets', 'abbreviations'].forEach(function(sectionName) { + var stackItem = {}; + each(section[sectionName] || null, function(v, k) { + stackItem[k] = { + nk: normalizeName(k), + value: v, + parsedValue: parseItem(k, v, sectionName), + type: sectionName + }; + }); + + stack.push(stackItem); + }); + + memo.push(sectionKey); + sectionKey = section['extends']; + } while (sectionKey && !~memo.indexOf(sectionKey)); + + + cache[cacheKey] = utils.extend.apply(utils, stack.reverse()); + } + + return cache[cacheKey]; + }, + + /** + * Returns newline character + * @returns {String} + */ + getNewline: function() { + var nl = this.getVariable('newline'); + return typeof nl === 'string' ? nl : '\n'; + }, + + /** + * Sets new newline character that will be used in output + * @param {String} str + */ + setNewline: function(str) { + this.setVariable('newline', str); + this.setVariable('nl', str); + } + }); + + // XXX add default resolvers + exports.addResolver(cssResolver.resolve.bind(cssResolver)); + + // try to load snippets + // hide it from Require.JS parser + (function(r) { + if (typeof define === 'undefined' || !define.amd) { + try { + var fs = r('fs'); + var path = r('path'); + + var defaultSnippets = fs.readFileSync(path.join(__dirname, '../snippets.json'), {encoding: 'utf8'}); + exports.setVocabulary(JSON.parse(defaultSnippets), VOC_SYSTEM); + } catch (e) {} + } + })(require); + + + return exports; +}); +},{"../assets/logger":"assets/logger.js","../resolver/css":"resolver/css.js","../utils/common":"utils/common.js","../vendor/stringScore":"vendor/stringScore.js","./elements":"assets/elements.js","./handlerList":"assets/handlerList.js"}],"assets/stringStream.js":[function(require,module,exports){ +/** + * A trimmed version of CodeMirror's StringStream module for string parsing + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + /** + * @type StringStream + * @constructor + * @param {String} string Assuming that bound string should be + * immutable + */ + function StringStream(string) { + this.pos = this.start = 0; + this.string = string; + this._length = string.length; + } + + StringStream.prototype = { + /** + * Returns true only if the stream is at the end of the line. + * @returns {Boolean} + */ + eol: function() { + return this.pos >= this._length; + }, + + /** + * Returns true only if the stream is at the start of the line + * @returns {Boolean} + */ + sol: function() { + return this.pos === 0; + }, + + /** + * Returns the next character in the stream without advancing it. + * Will return undefined at the end of the line. + * @returns {String} + */ + peek: function() { + return this.string.charAt(this.pos); + }, + + /** + * Returns the next character in the stream and advances it. + * Also returns undefined when no more characters are available. + * @returns {String} + */ + next: function() { + if (this.pos < this._length) + return this.string.charAt(this.pos++); + }, + + /** + * match can be a character, a regular expression, or a function that + * takes a character and returns a boolean. If the next character in the + * stream 'matches' the given argument, it is consumed and returned. + * Otherwise, undefined is returned. + * @param {Object} match + * @returns {String} + */ + eat: function(match) { + var ch = this.string.charAt(this.pos), ok; + if (typeof match == "string") + ok = ch == match; + else + ok = ch && (match.test ? match.test(ch) : match(ch)); + + if (ok) { + ++this.pos; + return ch; + } + }, + + /** + * Repeatedly calls eat with the given argument, until it + * fails. Returns true if any characters were eaten. + * @param {Object} match + * @returns {Boolean} + */ + eatWhile: function(match) { + var start = this.pos; + while (this.eat(match)) {} + return this.pos > start; + }, + + /** + * Shortcut for eatWhile when matching white-space. + * @returns {Boolean} + */ + eatSpace: function() { + var start = this.pos; + while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) + ++this.pos; + return this.pos > start; + }, + + /** + * Moves the position to the end of the line. + */ + skipToEnd: function() { + this.pos = this._length; + }, + + /** + * Skips to the next occurrence of the given character, if found on the + * current line (doesn't advance the stream if the character does not + * occur on the line). Returns true if the character was found. + * @param {String} ch + * @returns {Boolean} + */ + skipTo: function(ch) { + var found = this.string.indexOf(ch, this.pos); + if (found > -1) { + this.pos = found; + return true; + } + }, + + /** + * Skips to close character which is pair to open + * character, considering possible pair nesting. This function is used + * to consume pair of characters, like opening and closing braces + * @param {String} open + * @param {String} close + * @returns {Boolean} Returns true if pair was successfully + * consumed + */ + skipToPair: function(open, close, skipString) { + var braceCount = 0, ch; + var pos = this.pos, len = this._length; + while (pos < len) { + ch = this.string.charAt(pos++); + if (ch == open) { + braceCount++; + } else if (ch == close) { + braceCount--; + if (braceCount < 1) { + this.pos = pos; + return true; + } + } else if (skipString && (ch == '"' || ch == "'")) { + this.skipString(ch); + } + } + + return false; + }, + + /** + * A helper function which, in case of either single or + * double quote was found in current position, skips entire + * string (quoted value) + * @return {Boolean} Wether quoted string was skipped + */ + skipQuoted: function(noBackup) { + var ch = this.string.charAt(noBackup ? this.pos : this.pos - 1); + if (ch === '"' || ch === "'") { + if (noBackup) { + this.pos++; + } + return this.skipString(ch); + } + }, + + /** + * A custom function to skip string literal, e.g. a "double-quoted" + * or 'single-quoted' value + * @param {String} quote An opening quote + * @return {Boolean} + */ + skipString: function(quote) { + var pos = this.pos, len = this._length, ch; + while (pos < len) { + ch = this.string.charAt(pos++); + if (ch == '\\') { + continue; + } else if (ch == quote) { + this.pos = pos; + return true; + } + } + + return false; + }, + + /** + * Backs up the stream n characters. Backing it up further than the + * start of the current token will cause things to break, so be careful. + * @param {Number} n + */ + backUp : function(n) { + this.pos -= n; + }, + + /** + * Act like a multi-character eat—if consume is true or + * not given—or a look-ahead that doesn't update the stream position—if + * it is false. pattern can be either a string or a + * regular expression starting with ^. When it is a string, + * caseInsensitive can be set to true to make the match + * case-insensitive. When successfully matching a regular expression, + * the returned value will be the array returned by match, + * in case you need to extract matched groups. + * + * @param {RegExp} pattern + * @param {Boolean} consume + * @param {Boolean} caseInsensitive + * @returns + */ + match: function(pattern, consume, caseInsensitive) { + if (typeof pattern == "string") { + var cased = caseInsensitive + ? function(str) {return str.toLowerCase();} + : function(str) {return str;}; + + if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) { + if (consume !== false) + this.pos += pattern.length; + return true; + } + } else { + var match = this.string.slice(this.pos).match(pattern); + if (match && consume !== false) + this.pos += match[0].length; + return match; + } + }, + + /** + * Get the string between the start of the current token and the + * current stream position. + * @returns {String} + */ + current: function(backUp) { + return this.string.slice(this.start, this.pos - (backUp ? 1 : 0)); + } + }; + + module.exports = function(string) { + return new StringStream(string); + }; + + /** @deprecated */ + module.exports.create = module.exports; + return module.exports; +}); +},{}],"assets/tabStops.js":[function(require,module,exports){ +/** + * Utility module for handling tabstops tokens generated by Emmet's + * "Expand Abbreviation" action. The main extract method will take + * raw text (for example: ${0} some ${1:text}), find all tabstops + * occurrences, replace them with tokens suitable for your editor of choice and + * return object with processed text and list of found tabstops and their ranges. + * For sake of portability (Objective-C/Java) the tabstops list is a plain + * sorted array with plain objects. + * + * Placeholders with the same are meant to be linked in your editor. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var stringStream = require('./stringStream'); + var resources = require('./resources'); + + /** + * Global placeholder value, automatically incremented by + * variablesResolver() function + */ + var startPlaceholderNum = 100; + var tabstopIndex = 0; + + var defaultOptions = { + replaceCarets: false, + escape: function(ch) { + return '\\' + ch; + }, + tabstop: function(data) { + return data.token; + }, + variable: function(data) { + return data.token; + } + }; + + return { + /** + * Main function that looks for a tabstops in provided text + * and returns a processed version of text with expanded + * placeholders and list of tabstops found. + * @param {String} text Text to process + * @param {Object} options List of processor options:
+ * + * replaceCarets : Boolean — replace all default + * caret placeholders (like {%::emmet-caret::%}) with ${0:caret}
+ * + * escape : Function — function that handle escaped + * characters (mostly '$'). By default, it returns the character itself + * to be displayed as is in output, but sometimes you will use + * extract method as intermediate solution for further + * processing and want to keep character escaped. Thus, you should override + * escape method to return escaped symbol (e.g. '\\$')
+ * + * tabstop : Function – a tabstop handler. Receives + * a single argument – an object describing token: its position, number + * group, placeholder and token itself. Should return a replacement + * string that will appear in final output + * + * variable : Function – variable handler. Receives + * a single argument – an object describing token: its position, name + * and original token itself. Should return a replacement + * string that will appear in final output + * + * @returns {Object} Object with processed text property + * and array of tabstops found + * @memberOf tabStops + */ + extract: function(text, options) { + // prepare defaults + var placeholders = {carets: ''}; + var marks = []; + + options = utils.extend({}, defaultOptions, options, { + tabstop: function(data) { + var token = data.token; + var ret = ''; + if (data.placeholder == 'cursor') { + marks.push({ + start: data.start, + end: data.start + token.length, + group: 'carets', + value: '' + }); + } else { + // unify placeholder value for single group + if ('placeholder' in data) + placeholders[data.group] = data.placeholder; + + if (data.group in placeholders) + ret = placeholders[data.group]; + + marks.push({ + start: data.start, + end: data.start + token.length, + group: data.group, + value: ret + }); + } + + return token; + } + }); + + if (options.replaceCarets) { + text = text.replace(new RegExp( utils.escapeForRegexp( utils.getCaretPlaceholder() ), 'g'), '${0:cursor}'); + } + + // locate tabstops and unify group's placeholders + text = this.processText(text, options); + + // now, replace all tabstops with placeholders + var buf = '', lastIx = 0; + var tabStops = marks.map(function(mark) { + buf += text.substring(lastIx, mark.start); + + var pos = buf.length; + var ph = placeholders[mark.group] || ''; + + buf += ph; + lastIx = mark.end; + + return { + group: mark.group, + start: pos, + end: pos + ph.length + }; + }); + + buf += text.substring(lastIx); + + return { + text: buf, + tabstops: tabStops.sort(function(a, b) { + return a.start - b.start; + }) + }; + }, + + /** + * Text processing routine. Locates escaped characters and tabstops and + * replaces them with values returned by handlers defined in + * options + * @param {String} text + * @param {Object} options See extract method options + * description + * @returns {String} + */ + processText: function(text, options) { + options = utils.extend({}, defaultOptions, options); + + var buf = ''; + /** @type StringStream */ + var stream = stringStream.create(text); + var ch, m, a; + + while ((ch = stream.next())) { + if (ch == '\\' && !stream.eol()) { + // handle escaped character + buf += options.escape(stream.next()); + continue; + } + + a = ch; + + if (ch == '$') { + // looks like a tabstop + stream.start = stream.pos - 1; + + if ((m = stream.match(/^[0-9]+/))) { + // it's $N + a = options.tabstop({ + start: buf.length, + group: stream.current().substr(1), + token: stream.current() + }); + } else if ((m = stream.match(/^\{([a-z_\-][\w\-]*)\}/))) { + // ${variable} + a = options.variable({ + start: buf.length, + name: m[1], + token: stream.current() + }); + } else if ((m = stream.match(/^\{([0-9]+)(:.+?)?\}/, false))) { + // ${N:value} or ${N} placeholder + // parse placeholder, including nested ones + stream.skipToPair('{', '}'); + + var obj = { + start: buf.length, + group: m[1], + token: stream.current() + }; + + var placeholder = obj.token.substring(obj.group.length + 2, obj.token.length - 1); + + if (placeholder) { + obj.placeholder = placeholder.substr(1); + } + + a = options.tabstop(obj); + } + } + + buf += a; + } + + return buf; + }, + + /** + * Upgrades tabstops in output node in order to prevent naming conflicts + * @param {AbbreviationNode} node + * @param {Number} offset Tab index offset + * @returns {Number} Maximum tabstop index in element + */ + upgrade: function(node, offset) { + var maxNum = 0; + var options = { + tabstop: function(data) { + var group = parseInt(data.group, 10); + if (group > maxNum) maxNum = group; + + if (data.placeholder) + return '${' + (group + offset) + ':' + data.placeholder + '}'; + else + return '${' + (group + offset) + '}'; + } + }; + + ['start', 'end', 'content'].forEach(function(p) { + node[p] = this.processText(node[p], options); + }, this); + + return maxNum; + }, + + /** + * Helper function that produces a callback function for + * replaceVariables() method from {@link utils} + * module. This callback will replace variable definitions (like + * ${var_name}) with their value defined in resource module, + * or outputs tabstop with variable name otherwise. + * @param {AbbreviationNode} node Context node + * @returns {Function} + */ + variablesResolver: function(node) { + var placeholderMemo = {}; + return function(str, varName) { + // do not mark `child` variable as placeholder – it‘s a reserved + // variable name + if (varName == 'child') { + return str; + } + + if (varName == 'cursor') { + return utils.getCaretPlaceholder(); + } + + var attr = node.attribute(varName); + if (typeof attr !== 'undefined' && attr !== str) { + return attr; + } + + var varValue = resources.getVariable(varName); + if (varValue) { + return varValue; + } + + // output as placeholder + if (!placeholderMemo[varName]) { + placeholderMemo[varName] = startPlaceholderNum++; + } + + return '${' + placeholderMemo[varName] + ':' + varName + '}'; + }; + }, + + /** + * Replace variables like ${var} in string + * @param {String} str + * @param {Object} vars Variable set (defaults to variables defined in + * snippets.json) or variable resolver (Function) + * @return {String} + */ + replaceVariables: function(str, vars) { + vars = vars || {}; + var resolver = typeof vars === 'function' ? vars : function(str, p1) { + return p1 in vars ? vars[p1] : null; + }; + + return this.processText(str, { + variable: function(data) { + var newValue = resolver(data.token, data.name, data); + if (newValue === null) { + // try to find variable in resources + newValue = resources.getVariable(data.name); + } + + if (newValue === null || typeof newValue === 'undefined') + // nothing found, return token itself + newValue = data.token; + return newValue; + } + }); + }, + + /** + * Resets global tabstop index. When parsed tree is converted to output + * string (AbbreviationNode.toString()), all tabstops + * defined in snippets and elements are upgraded in order to prevent + * naming conflicts of nested. For example, ${1} of a node + * should not be linked with the same placehilder of the child node. + * By default, AbbreviationNode.toString() automatically + * upgrades tabstops of the same index for each node and writes maximum + * tabstop index into the tabstopIndex variable. To keep + * this variable at reasonable value, it is recommended to call + * resetTabstopIndex() method each time you expand variable + * @returns + */ + resetTabstopIndex: function() { + tabstopIndex = 0; + startPlaceholderNum = 100; + }, + + /** + * Output processor for abbreviation parser that will upgrade tabstops + * of parsed node in order to prevent tabstop index conflicts + */ + abbrOutputProcessor: function(text, node, type) { + var maxNum = 0; + var that = this; + + var tsOptions = { + tabstop: function(data) { + var group = parseInt(data.group, 10); + if (group === 0) + return '${0}'; + + if (group > maxNum) maxNum = group; + if (data.placeholder) { + // respect nested placeholders + var ix = group + tabstopIndex; + var placeholder = that.processText(data.placeholder, tsOptions); + return '${' + ix + ':' + placeholder + '}'; + } else { + return '${' + (group + tabstopIndex) + '}'; + } + } + }; + + // upgrade tabstops + text = this.processText(text, tsOptions); + + // resolve variables + text = this.replaceVariables(text, this.variablesResolver(node)); + + tabstopIndex += maxNum + 1; + return text; + } + }; +}); +},{"../utils/common":"utils/common.js","./resources":"assets/resources.js","./stringStream":"assets/stringStream.js"}],"assets/tokenIterator.js":[function(require,module,exports){ +/** + * Helper class for convenient token iteration + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + /** + * @type TokenIterator + * @param {Array} tokens + * @type TokenIterator + * @constructor + */ + function TokenIterator(tokens) { + /** @type Array */ + this.tokens = tokens; + this._position = 0; + this.reset(); + } + + TokenIterator.prototype = { + next: function() { + if (this.hasNext()) { + var token = this.tokens[++this._i]; + this._position = token.start; + return token; + } else { + this._i = this._il; + } + + return null; + }, + + current: function() { + return this.tokens[this._i]; + }, + + peek: function() { + return this.tokens[this._i + i]; + }, + + position: function() { + return this._position; + }, + + hasNext: function() { + return this._i < this._il - 1; + }, + + reset: function() { + this._i = 0; + this._il = this.tokens.length; + }, + + item: function() { + return this.tokens[this._i]; + }, + + itemNext: function() { + return this.tokens[this._i + 1]; + }, + + itemPrev: function() { + return this.tokens[this._i - 1]; + }, + + nextUntil: function(type, callback) { + var token; + var test = typeof type == 'string' + ? function(t){return t.type == type;} + : type; + + while ((token = this.next())) { + if (callback) + callback.call(this, token); + if (test.call(this, token)) + break; + } + } + }; + + return { + create: function(tokens) { + return new TokenIterator(tokens); + } + }; +}); +},{}],"caniuse.json":[function(require,module,exports){ +module.exports={"vendors":{"ie":{"prefix":"ms","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"5.5","6","7","8","9","10","11",null,null]},"firefox":{"prefix":"moz","versions":[null,"2","3","3.5","3.6","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27"]},"chrome":{"prefix":"webkit","versions":["4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24","25","26","27","28","29","30","31","32"]},"safari":{"prefix":"webkit","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"3.1","3.2","4","5","5.1","6","6.1","7",null,null]},"opera":{"prefix":"o","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,"9.5-9.6","10.0-10.1","10.5","10.6","11","11.1","11.5","11.6","12","12.1","15","16","17","18",null]},"ios_saf":{"prefix":"webkit","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"3.2","4.0-4.1","4.2-4.3","5.0-5.1","6.0-6.1","7.0",null,null]},"op_mini":{"prefix":"o","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"5.0-7.0",null,null]},"android":{"prefix":"webkit","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"2.1","2.2","2.3","3","4","4.1","4.2-4.3","4.4",null]},"op_mob":{"prefix":"o","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"10",null,null,"11.5","12","12.1","0",null,null]},"bb":{"prefix":"webkit","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"7","10",null,null]},"and_chr":{"prefix":"webkit","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"0",null,null]},"and_ff":{"prefix":"moz","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"0",null,null]},"ie_mob":{"prefix":"ms","versions":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,"10",null,null]}},"css":{"border-image":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x","5":"a x","6":"y","7":"y","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"y"},"opera":{"9":"n","11":"a x","12":"a x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"a","10.6":"a","11.1":"a x","11.5":"a x","11.6":"a x","12.1":"a x"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"y"},"bb":{"7":"a x","10":"y"},"op_mob":{"0":"y","10":"n","11":"a x","12":"a x","11.1":"a x","11.5":"a x","12.1":"a x"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"n"}},"box-shadow":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x","5":"y x","6":"y","7":"y","3.1":"a x","3.2":"a x","5.1":"y","6.1":"y"},"opera":{"9":"n","11":"y","12":"y","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y","10.6":"y","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y","4.2-4.3":"y","4.4":"y"},"bb":{"7":"y x","10":"y"},"op_mob":{"0":"y","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"box-sizing":{"ie":{"6":"p","7":"p","8":"a","9":"a","10":"a","11":"a","5.5":"p"},"firefox":{"2":"y x","3":"y x","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"y x","3.6":"y x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a","11":"a","12":"a","13":"a","14":"a","15":"a","16":"a","17":"a","18":"a","19":"a","20":"a","21":"a","22":"a","23":"a","24":"a","25":"a","26":"a","27":"a","28":"a","29":"a","30":"a","31":"a","32":"a"},"safari":{"4":"a x","5":"a x","6":"a","7":"a","3.1":"a x","3.2":"a x","5.1":"a","6.1":"a"},"opera":{"9":"n","11":"a","12":"a","15":"a","16":"a","17":"a","18":"a","9.5-9.6":"a","10.0-10.1":"a","10.5":"a","10.6":"a","11.1":"a","11.5":"a","11.6":"a","12.1":"a"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a","6.0-6.1":"a","7.0":"a"},"op_mini":{"5.0-7.0":"a"},"android":{"3":"a x","4":"a","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a","4.2-4.3":"a","4.4":"a"},"bb":{"7":"a x","10":"a"},"op_mob":{"0":"a","10":"a","11":"a","12":"a","11.1":"a","11.5":"a","12.1":"a"},"and_chr":{"0":"a"},"and_ff":{"0":"y x"},"ie_mob":{"10":"a"}},"column-width":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-count":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"columns":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-gap":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-rule-color":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-rule-style":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-rule-width":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-rule":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-span":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"column-fill":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"a x","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","3.5":"a x","3.6":"a x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"a x","3.2":"a x","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"y","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"y"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"a x"},"and_ff":{"0":"a x"},"ie_mob":{"10":"y"}},"border-radius":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"y x","4":"y","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y","6":"y","7":"y","3.1":"y x","3.2":"y x","5.1":"y","6.1":"y"},"opera":{"9":"n","11":"y","12":"y","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y","10.6":"y","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y","4.2-4.3":"y","5.0-5.1":"y","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y","4":"y","2.1":"y x","2.2":"y","2.3":"y","4.1":"y","4.2-4.3":"y","4.4":"y"},"bb":{"7":"y","10":"y"},"op_mob":{"0":"y","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"border-top-left-radius":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"y x","4":"y","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y","6":"y","7":"y","3.1":"y x","3.2":"y x","5.1":"y","6.1":"y"},"opera":{"9":"n","11":"y","12":"y","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y","10.6":"y","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y","4.2-4.3":"y","5.0-5.1":"y","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y","4":"y","2.1":"y x","2.2":"y","2.3":"y","4.1":"y","4.2-4.3":"y","4.4":"y"},"bb":{"7":"y","10":"y"},"op_mob":{"0":"y","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"border-top-right-radius":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"y x","4":"y","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y","6":"y","7":"y","3.1":"y x","3.2":"y x","5.1":"y","6.1":"y"},"opera":{"9":"n","11":"y","12":"y","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y","10.6":"y","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y","4.2-4.3":"y","5.0-5.1":"y","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y","4":"y","2.1":"y x","2.2":"y","2.3":"y","4.1":"y","4.2-4.3":"y","4.4":"y"},"bb":{"7":"y","10":"y"},"op_mob":{"0":"y","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"border-bottom-right-radius":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"y x","4":"y","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y","6":"y","7":"y","3.1":"y x","3.2":"y x","5.1":"y","6.1":"y"},"opera":{"9":"n","11":"y","12":"y","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y","10.6":"y","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y","4.2-4.3":"y","5.0-5.1":"y","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y","4":"y","2.1":"y x","2.2":"y","2.3":"y","4.1":"y","4.2-4.3":"y","4.4":"y"},"bb":{"7":"y","10":"y"},"op_mob":{"0":"y","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"border-bottom-left-radius":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"a x","3":"y x","4":"y","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y","6":"y","7":"y","8":"y","9":"y","10":"y","11":"y","12":"y","13":"y","14":"y","15":"y","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y","6":"y","7":"y","3.1":"y x","3.2":"y x","5.1":"y","6.1":"y"},"opera":{"9":"n","11":"y","12":"y","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y","10.6":"y","11.1":"y","11.5":"y","11.6":"y","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y","4.2-4.3":"y","5.0-5.1":"y","6.0-6.1":"y","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y","4":"y","2.1":"y x","2.2":"y","2.3":"y","4.1":"y","4.2-4.3":"y","4.4":"y"},"bb":{"7":"y","10":"y"},"op_mob":{"0":"y","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"transform":{"ie":{"6":"p","7":"p","8":"p","9":"y x","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"y x","3.6":"y x"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"y x","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"y x","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"y","12":"y","11.1":"y","11.5":"y","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"hyphens":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"n","27":"n","28":"n","29":"n","30":"n","31":"n","32":"n"},"safari":{"4":"n","5":"n","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"n"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"n","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"n"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}},"transition":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"y x","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y x","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y","10":"y x","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"transition-property":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"y x","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y x","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y","10":"y x","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"transition-duration":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"y x","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y x","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y","10":"y x","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"transition-timing-function":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"y x","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y x","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y","10":"y x","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"transition-delay":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"y x","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"y x","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y","10":"y x","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"font-feature-settings":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"a","5":"a","6":"a","7":"y x","3.1":"n","3.2":"n","5.1":"a","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a","4.0-4.1":"a","4.2-4.3":"a","5.0-5.1":"a","6.0-6.1":"a","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y x"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}},"animation":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-name":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-duration":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-timing-function":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-iteration-count":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-direction":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-play-state":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-delay":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"animation-fill-mode":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"@keyframes":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"y x","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y x"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"linear-gradient":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"y x"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x","5":"a x","6":"y x","7":"y","3.1":"n","3.2":"n","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"n","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"a x","11.5":"a x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"y x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"a x","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"y x","11.1":"a x","11.5":"a x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"mask-image":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-source-type":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-repeat":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-position":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-clip":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-origin":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-size":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-type":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-box-image-source":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-box-image-slice":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-box-image-width":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-box-image-outset":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-box-image-repeat":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"mask-box-image":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"clip-path":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"clip-rule":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"a x","5":"a x","6":"a x","7":"a x","8":"a x","9":"a x","10":"a x","11":"a x","12":"a x","13":"a x","14":"a x","15":"a x","16":"a x","17":"a x","18":"a x","19":"a x","20":"a x","21":"a x","22":"a x","23":"a x","24":"a x","25":"a x","26":"a x","27":"a x","28":"a x","29":"a x","30":"a x","31":"a x","32":"a x"},"safari":{"4":"a x","5":"a x","6":"a x","7":"a x","3.1":"n","3.2":"n","5.1":"a x","6.1":"a x"},"opera":{"9":"n","11":"n","12":"n","15":"a x","16":"a x","17":"a x","18":"a x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"a x","4.0-4.1":"a x","4.2-4.3":"a x","5.0-5.1":"a x","6.0-6.1":"a x","7.0":"a x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x","4":"a x","2.1":"a x","2.2":"a x","2.3":"a x","4.1":"a x","4.2-4.3":"a x","4.4":"a x"},"bb":{"7":"a x","10":"a x"},"op_mob":{"0":"a x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"a x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"@supports":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"n","27":"n","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"n","5":"n","6":"n","7":"n","3.1":"n","3.2":"n","5.1":"n","6.1":"n"},"opera":{"9":"n","11":"n","12":"n","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"n"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"n"}},"flex":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"a x #2","11":"y","5.5":"n"},"firefox":{"2":"a x #1","3":"a x #1","4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"a x #1","22":"a #3","23":"a #3","24":"a #3","25":"a #3","26":"a #3","27":"a #3","3.5":"a x #1","3.6":"a x #1"},"chrome":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"y x","3.1":"a x #1","3.2":"a x #1","5.1":"a x #1","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"a x #1","4.0-4.1":"a x #1","4.2-4.3":"a x #1","5.0-5.1":"a x #1","6.0-6.1":"a x #1","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x #1","4":"a x #1","2.1":"a x #1","2.2":"a x #1","2.3":"a x #1","4.1":"a x #1","4.2-4.3":"a x #1","4.4":"y"},"bb":{"7":"a x #1","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"a x #1"},"ie_mob":{"10":"a x #2"}},"inline-flex":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"a x #2","11":"y","5.5":"n"},"firefox":{"2":"a x #1","3":"a x #1","4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"a x #1","22":"a #3","23":"a #3","24":"a #3","25":"a #3","26":"a #3","27":"a #3","3.5":"a x #1","3.6":"a x #1"},"chrome":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"y x","3.1":"a x #1","3.2":"a x #1","5.1":"a x #1","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"a x #1","4.0-4.1":"a x #1","4.2-4.3":"a x #1","5.0-5.1":"a x #1","6.0-6.1":"a x #1","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x #1","4":"a x #1","2.1":"a x #1","2.2":"a x #1","2.3":"a x #1","4.1":"a x #1","4.2-4.3":"a x #1","4.4":"y"},"bb":{"7":"a x #1","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"a x #1"},"ie_mob":{"10":"a x #2"}},"flex-direction":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"a x #2","11":"y","5.5":"n"},"firefox":{"2":"a x #1","3":"a x #1","4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"a x #1","22":"a #3","23":"a #3","24":"a #3","25":"a #3","26":"a #3","27":"a #3","3.5":"a x #1","3.6":"a x #1"},"chrome":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"y x","3.1":"a x #1","3.2":"a x #1","5.1":"a x #1","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"a x #1","4.0-4.1":"a x #1","4.2-4.3":"a x #1","5.0-5.1":"a x #1","6.0-6.1":"a x #1","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x #1","4":"a x #1","2.1":"a x #1","2.2":"a x #1","2.3":"a x #1","4.1":"a x #1","4.2-4.3":"a x #1","4.4":"y"},"bb":{"7":"a x #1","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"a x #1"},"ie_mob":{"10":"a x #2"}},"flex-wrap":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"a x #2","11":"y","5.5":"n"},"firefox":{"2":"a x #1","3":"a x #1","4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"a x #1","22":"a #3","23":"a #3","24":"a #3","25":"a #3","26":"a #3","27":"a #3","3.5":"a x #1","3.6":"a x #1"},"chrome":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"y x","3.1":"a x #1","3.2":"a x #1","5.1":"a x #1","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"a x #1","4.0-4.1":"a x #1","4.2-4.3":"a x #1","5.0-5.1":"a x #1","6.0-6.1":"a x #1","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x #1","4":"a x #1","2.1":"a x #1","2.2":"a x #1","2.3":"a x #1","4.1":"a x #1","4.2-4.3":"a x #1","4.4":"y"},"bb":{"7":"a x #1","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"a x #1"},"ie_mob":{"10":"a x #2"}},"flex-flow":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"a x #2","11":"y","5.5":"n"},"firefox":{"2":"a x #1","3":"a x #1","4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"a x #1","22":"a #3","23":"a #3","24":"a #3","25":"a #3","26":"a #3","27":"a #3","3.5":"a x #1","3.6":"a x #1"},"chrome":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"y x","3.1":"a x #1","3.2":"a x #1","5.1":"a x #1","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"a x #1","4.0-4.1":"a x #1","4.2-4.3":"a x #1","5.0-5.1":"a x #1","6.0-6.1":"a x #1","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x #1","4":"a x #1","2.1":"a x #1","2.2":"a x #1","2.3":"a x #1","4.1":"a x #1","4.2-4.3":"a x #1","4.4":"y"},"bb":{"7":"a x #1","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"a x #1"},"ie_mob":{"10":"a x #2"}},"order":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"a x #2","11":"y","5.5":"n"},"firefox":{"2":"a x #1","3":"a x #1","4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"a x #1","22":"a #3","23":"a #3","24":"a #3","25":"a #3","26":"a #3","27":"a #3","3.5":"a x #1","3.6":"a x #1"},"chrome":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"a x #1","8":"a x #1","9":"a x #1","10":"a x #1","11":"a x #1","12":"a x #1","13":"a x #1","14":"a x #1","15":"a x #1","16":"a x #1","17":"a x #1","18":"a x #1","19":"a x #1","20":"a x #1","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"a x #1","5":"a x #1","6":"a x #1","7":"y x","3.1":"a x #1","3.2":"a x #1","5.1":"a x #1","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"y"},"ios_saf":{"3.2":"a x #1","4.0-4.1":"a x #1","4.2-4.3":"a x #1","5.0-5.1":"a x #1","6.0-6.1":"a x #1","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"a x #1","4":"a x #1","2.1":"a x #1","2.2":"a x #1","2.3":"a x #1","4.1":"a x #1","4.2-4.3":"a x #1","4.4":"y"},"bb":{"7":"a x #1","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"a x #1"},"ie_mob":{"10":"a x #2"}},"calc":{"ie":{"6":"n","7":"n","8":"n","9":"y","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"n","5":"n","6":"y x","7":"y","3.1":"n","3.2":"n","5.1":"n","6.1":"y"},"opera":{"9":"n","11":"n","12":"n","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y"},"and_ff":{"0":"y"},"ie_mob":{"10":"y"}},"object-fit":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"n","27":"n","28":"n","29":"n","30":"n","31":"n","32":"y"},"safari":{"4":"n","5":"n","6":"n","7":"u","3.1":"n","3.2":"n","5.1":"n","6.1":"u"},"opera":{"9":"n","11":"y x","12":"y x","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y x"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"n"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"n"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"n","10":"n","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y x"},"and_chr":{"0":"n"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"object-position":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"n","27":"n","28":"n","29":"n","30":"n","31":"n","32":"y"},"safari":{"4":"n","5":"n","6":"n","7":"u","3.1":"n","3.2":"n","5.1":"n","6.1":"u"},"opera":{"9":"n","11":"y x","12":"y x","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y x"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"n"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"n"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"n","10":"n","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y x"},"and_chr":{"0":"n"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"grid":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"inline-grid":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-template-rows":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-template-columns":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-template-areas":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-template":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-auto-rows":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-auto-columns":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}}," grid-auto-flow":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-auto-position":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}}," grid-row-start":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-column-start":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-row-end":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-column-end":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-column":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-row":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"grid-area":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"justify-self":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"justify-items":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"align-self":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"align-items":{"ie":{"6":"n","7":"n","8":"n","9":"p","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"p","20":"p","21":"p","22":"p","23":"p","24":"p","25":"p","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"p","26":"p","27":"p","28":"p","29":"p","30":"p","31":"u","32":"u"},"safari":{"4":"n","5":"n","6":"p","7":"p","3.1":"n","3.2":"n","5.1":"n","6.1":"p"},"opera":{"9":"n","11":"n","12":"n","15":"n","16":"n","17":"n","18":"n","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"p","7.0":"p"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"p","4.4":"p"},"bb":{"7":"n","10":"n"},"op_mob":{"0":"p","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"p"},"and_ff":{"0":"n"},"ie_mob":{"10":"y x"}},"repeating-linear-gradient":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y","11":"y","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y","17":"y","18":"y","19":"y","20":"y","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","3.5":"n","3.6":"y x"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"n","5":"n","6":"y x","7":"y","3.1":"n","3.2":"n","5.1":"y x","6.1":"y"},"opera":{"9":"n","11":"n","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"a x","11.5":"a x","11.6":"y x","12.1":"y"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"y x","2.1":"n","2.2":"n","2.3":"n","4.1":"y x","4.2-4.3":"y x","4.4":"y"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y","10":"n","11":"n","12":"y x","11.1":"a x","11.5":"a x","12.1":"y"},"and_chr":{"0":"y"},"and_ff":{"0":"y x"},"ie_mob":{"10":"y"}},"filter":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"n","23":"n","24":"n","25":"n","26":"u","27":"u","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"n","5":"n","6":"y x","7":"y x","3.1":"n","3.2":"n","5.1":"n","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y x"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"n"},"ie_mob":{"10":"n"}},"user-select":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"y x","11":"y x","5.5":"n"},"firefox":{"2":"y x","3":"y x","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"y x","3.6":"y x"},"chrome":{"4":"u","5":"u","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"y x","5":"y x","6":"y x","7":"y x","3.1":"y x","3.2":"y x","5.1":"y x","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"y x","4.0-4.1":"y x","4.2-4.3":"y x","5.0-5.1":"y x","6.0-6.1":"y x","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"y x","4":"y x","2.1":"y x","2.2":"y x","2.3":"y x","4.1":"y x","4.2-4.3":"y x","4.4":"y x"},"bb":{"7":"y x","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"y x"},"ie_mob":{"10":"y x"}},"min-content":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"n","5":"n","6":"n","7":"y x","3.1":"n","3.2":"n","5.1":"n","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y x"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}},"max-content":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"n","5":"n","6":"n","7":"y x","3.1":"n","3.2":"n","5.1":"n","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y x"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}},"fit-content":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"n","5":"n","6":"n","7":"y x","3.1":"n","3.2":"n","5.1":"n","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y x"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}},"fill-available":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"n","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","28":"y x","29":"y x","30":"y x","31":"y x","32":"y x"},"safari":{"4":"n","5":"n","6":"n","7":"y x","3.1":"n","3.2":"n","5.1":"n","6.1":"y x"},"opera":{"9":"n","11":"n","12":"n","15":"y x","16":"y x","17":"y x","18":"y x","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"n","11.1":"n","11.5":"n","11.6":"n","12.1":"n"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"y x"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y x"},"bb":{"7":"n","10":"y x"},"op_mob":{"0":"y x","10":"n","11":"n","12":"n","11.1":"n","11.5":"n","12.1":"n"},"and_chr":{"0":"y x"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}},"tab-size":{"ie":{"6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","5.5":"n"},"firefox":{"2":"n","3":"n","4":"y x","5":"y x","6":"y x","7":"y x","8":"y x","9":"y x","10":"y x","11":"y x","12":"y x","13":"y x","14":"y x","15":"y x","16":"y x","17":"y x","18":"y x","19":"y x","20":"y x","21":"y x","22":"y x","23":"y x","24":"y x","25":"y x","26":"y x","27":"y x","3.5":"n","3.6":"n"},"chrome":{"4":"n","5":"n","6":"n","7":"n","8":"n","9":"n","10":"n","11":"n","12":"n","13":"n","14":"n","15":"n","16":"n","17":"n","18":"n","19":"n","20":"n","21":"y","22":"y","23":"y","24":"y","25":"y","26":"y","27":"y","28":"y","29":"y","30":"y","31":"y","32":"y"},"safari":{"4":"n","5":"n","6":"n","7":"y","3.1":"n","3.2":"n","5.1":"n","6.1":"y"},"opera":{"9":"n","11":"y x","12":"y x","15":"y","16":"y","17":"y","18":"y","9.5-9.6":"n","10.0-10.1":"n","10.5":"n","10.6":"y x","11.1":"y x","11.5":"y x","11.6":"y x","12.1":"y x"},"ios_saf":{"3.2":"n","4.0-4.1":"n","4.2-4.3":"n","5.0-5.1":"n","6.0-6.1":"n","7.0":"y"},"op_mini":{"5.0-7.0":"n"},"android":{"3":"n","4":"n","2.1":"n","2.2":"n","2.3":"n","4.1":"n","4.2-4.3":"n","4.4":"y"},"bb":{"7":"y","10":"y"},"op_mob":{"0":"y","10":"n","11":"y x","12":"y x","11.1":"y x","11.5":"y x","12.1":"y x"},"and_chr":{"0":"y"},"and_ff":{"0":"y x"},"ie_mob":{"10":"n"}}},"era":["e-26","e-25","e-24","e-23","e-22","e-21","e-20","e-19","e-18","e-17","e-16","e-15","e-14","e-13","e-12","e-11","e-10","e-9","e-8","e-7","e-6","e-5","e-4","e-3","e-2","e-1","e0","e1","e2"]} +},{}],"editTree/base.js":[function(require,module,exports){ +/** + * Abstract implementation of edit tree interface. + * Edit tree is a named container of editable “name-value” child elements, + * parsed from source. This container provides convenient methods + * for editing/adding/removing child elements. All these update actions are + * instantly reflected in the source code with respect of formatting. + *

+ * For example, developer can create an edit tree from CSS rule and add or + * remove properties from it–all changes will be immediately reflected in the + * original source. + *

+ * All classes defined in this module should be extended the same way as in + * Backbone framework: using extend method to create new class and + * initialize method to define custom class constructor. + * + * @example + *

+ * var MyClass = require('editTree/base').EditElement.extend({
+ *     initialize: function() {
+ *     // constructor code here
+ *   }
+ * });
+ *
+ * var elem = new MyClass();
+ * 
+ */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var range = require('../assets/range'); + var utils = require('../utils/common'); + var klass = require('../vendor/klass'); + + /** + * Named container of edited source + * @type EditContainer + * @param {String} source + * @param {Object} options + */ + function EditContainer(source, options) { + this.options = utils.extend({offset: 0}, options); + /** + * Source code of edited structure. All changes in the structure are + * immediately reflected into this property + */ + this.source = source; + + /** + * List of all editable children + * @private + */ + this._children = []; + + /** + * Hash of all positions of container + * @private + */ + this._positions = { + name: 0 + }; + + this.initialize.apply(this, arguments); + } + + /** + * The self-propagating extend function for classes. + * @type Function + */ + EditContainer.extend = klass.extend; + + EditContainer.prototype = { + type: 'container', + /** + * Child class constructor + */ + initialize: function() {}, + + /** + * Make position absolute + * @private + * @param {Number} num + * @param {Boolean} isAbsolute + * @returns {Boolean} + */ + _pos: function(num, isAbsolute) { + return num + (isAbsolute ? this.options.offset : 0); + }, + + /** + * Replace substring of tag's source + * @param {String} value + * @param {Number} start + * @param {Number} end + * @private + */ + _updateSource: function(value, start, end) { + // create modification range + var r = range.create(start, typeof end === 'undefined' ? 0 : end - start); + var delta = value.length - r.length(); + + var update = function(obj) { + Object.keys(obj).forEach(function(k) { + if (obj[k] >= r.end) { + obj[k] += delta; + } + }); + }; + + // update affected positions of current container + update(this._positions); + + // update affected positions of children + var recursiveUpdate = function(items) { + items.forEach(function(item) { + update(item._positions); + if (item.type == 'container') { + recursiveUpdate(item.list()); + } + }); + }; + + recursiveUpdate(this.list()); + this.source = utils.replaceSubstring(this.source, value, r); + }, + + + /** + * Adds new attribute + * @param {String} name Property name + * @param {String} value Property value + * @param {Number} pos Position at which to insert new property. By + * default the property is inserted at the end of rule + * @returns {EditElement} Newly created element + */ + add: function(name, value, pos) { + // this is abstract implementation + var item = new EditElement(name, value); + this._children.push(item); + return item; + }, + + /** + * Returns attribute object + * @param {String} name Attribute name or its index + * @returns {EditElement} + */ + get: function(name) { + if (typeof name === 'number') { + return this.list()[name]; + } + + if (typeof name === 'string') { + return utils.find(this.list(), function(prop) { + return prop.name() === name; + }); + } + + return name; + }, + + /** + * Returns all children by name or indexes + * @param {Object} name Element name(s) or indexes (String, + * Array, Number) + * @returns {Array} + */ + getAll: function(name) { + if (!Array.isArray(name)) + name = [name]; + + // split names and indexes + var names = [], indexes = []; + name.forEach(function(item) { + if (typeof item === 'string') { + names.push(item); + } else if (typeof item === 'number') { + indexes.push(item); + } + }); + + return this.list().filter(function(attribute, i) { + return ~indexes.indexOf(i) || ~names.indexOf(attribute.name()); + }); + }, + + /** + * Returns list of all editable child elements + * @returns {Array} + */ + list: function() { + return this._children; + }, + + /** + * Remove child element + * @param {String} name Property name or its index + */ + remove: function(name) { + var element = this.get(name); + if (element) { + this._updateSource('', element.fullRange()); + var ix = this._children.indexOf(element); + if (~ix) { + this._children.splice(ix, 1); + } + } + }, + + /** + * Returns index of editble child in list + * @param {Object} item + * @returns {Number} + */ + indexOf: function(item) { + return this.list().indexOf(this.get(item)); + }, + + /** + * Returns or updates element value. If such element doesn't exists, + * it will be created automatically and added at the end of child list. + * @param {String} name Element name or its index + * @param {String} value New element value + * @returns {String} + */ + value: function(name, value, pos) { + var element = this.get(name); + if (element) + return element.value(value); + + if (typeof value !== 'undefined') { + // no such element — create it + return this.add(name, value, pos); + } + }, + + /** + * Returns all values of child elements found by getAll() + * method + * @param {Object} name Element name(s) or indexes (String, + * Array, Number) + * @returns {Array} + */ + values: function(name) { + return this.getAll(name).map(function(element) { + return element.value(); + }); + }, + + /** + * Sets or gets container name + * @param {String} val New name. If not passed, current + * name is returned + * @return {String} + */ + name: function(val) { + if (typeof val !== 'undefined' && this._name !== (val = String(val))) { + this._updateSource(val, this._positions.name, this._positions.name + this._name.length); + this._name = val; + } + + return this._name; + }, + + /** + * Returns name range object + * @param {Boolean} isAbsolute Return absolute range (with respect of + * rule offset) + * @returns {Range} + */ + nameRange: function(isAbsolute) { + return range.create(this._positions.name + (isAbsolute ? this.options.offset : 0), this.name()); + }, + + /** + * Returns range of current source + * @param {Boolean} isAbsolute + */ + range: function(isAbsolute) { + return range.create(isAbsolute ? this.options.offset : 0, this.valueOf()); + }, + + /** + * Returns element that belongs to specified position + * @param {Number} pos + * @param {Boolean} isAbsolute + * @returns {EditElement} + */ + itemFromPosition: function(pos, isAbsolute) { + return utils.find(this.list(), function(elem) { + return elem.range(isAbsolute).inside(pos); + }); + }, + + /** + * Returns source code of current container + * @returns {String} + */ + toString: function() { + return this.valueOf(); + }, + + valueOf: function() { + return this.source; + } + }; + + /** + * @param {EditContainer} parent + * @param {Object} nameToken + * @param {Object} valueToken + */ + function EditElement(parent, nameToken, valueToken) { + /** @type EditContainer */ + this.parent = parent; + + this._name = nameToken.value; + this._value = valueToken ? valueToken.value : ''; + + this._positions = { + name: nameToken.start, + value: valueToken ? valueToken.start : -1 + }; + + this.initialize.apply(this, arguments); + } + + /** + * The self-propagating extend function for classes. + * @type Function + */ + EditElement.extend = klass.extend; + + EditElement.prototype = { + type: 'element', + + /** + * Child class constructor + */ + initialize: function() {}, + + /** + * Make position absolute + * @private + * @param {Number} num + * @param {Boolean} isAbsolute + * @returns {Boolean} + */ + _pos: function(num, isAbsolute) { + return num + (isAbsolute ? this.parent.options.offset : 0); + }, + + /** + * Sets of gets element value + * @param {String} val New element value. If not passed, current + * value is returned + * @returns {String} + */ + value: function(val) { + if (typeof val !== 'undefined' && this._value !== (val = String(val))) { + this.parent._updateSource(val, this.valueRange()); + this._value = val; + } + + return this._value; + }, + + /** + * Sets of gets element name + * @param {String} val New element name. If not passed, current + * name is returned + * @returns {String} + */ + name: function(val) { + if (typeof val !== 'undefined' && this._name !== (val = String(val))) { + this.parent._updateSource(val, this.nameRange()); + this._name = val; + } + + return this._name; + }, + + /** + * Returns position of element name token + * @param {Boolean} isAbsolute Return absolute position + * @returns {Number} + */ + namePosition: function(isAbsolute) { + return this._pos(this._positions.name, isAbsolute); + }, + + /** + * Returns position of element value token + * @param {Boolean} isAbsolute Return absolute position + * @returns {Number} + */ + valuePosition: function(isAbsolute) { + return this._pos(this._positions.value, isAbsolute); + }, + + /** + * Returns element name + * @param {Boolean} isAbsolute Return absolute range + * @returns {Range} + */ + range: function(isAbsolute) { + return range.create(this.namePosition(isAbsolute), this.valueOf()); + }, + + /** + * Returns full element range, including possible indentation + * @param {Boolean} isAbsolute Return absolute range + * @returns {Range} + */ + fullRange: function(isAbsolute) { + return this.range(isAbsolute); + }, + + /** + * Returns element name range + * @param {Boolean} isAbsolute Return absolute range + * @returns {Range} + */ + nameRange: function(isAbsolute) { + return range.create(this.namePosition(isAbsolute), this.name()); + }, + + /** + * Returns element value range + * @param {Boolean} isAbsolute Return absolute range + * @returns {Range} + */ + valueRange: function(isAbsolute) { + return range.create(this.valuePosition(isAbsolute), this.value()); + }, + + /** + * Returns current element string representation + * @returns {String} + */ + toString: function() { + return this.valueOf(); + }, + + valueOf: function() { + return this.name() + this.value(); + } + }; + + return { + EditContainer: EditContainer, + EditElement: EditElement, + + /** + * Creates token that can be fed to EditElement + * @param {Number} start + * @param {String} value + * @param {String} type + * @returns + */ + createToken: function(start, value, type) { + var obj = { + start: start || 0, + value: value || '', + type: type + }; + + obj.end = obj.start + obj.value.length; + return obj; + } + }; +}); +},{"../assets/range":"assets/range.js","../utils/common":"utils/common.js","../vendor/klass":"vendor/klass.js"}],"editTree/css.js":[function(require,module,exports){ +/** + * CSS EditTree is a module that can parse a CSS rule into a tree with + * convenient methods for adding, modifying and removing CSS properties. These + * changes can be written back to string with respect of code formatting. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var editTree = require('./base'); + var cssParser = require('../parser/css'); + var cssSections = require('../utils/cssSections'); + var range = require('../assets/range'); + var stringStream = require('../assets/stringStream'); + var tokenIterator = require('../assets/tokenIterator'); + + var defaultOptions = { + styleBefore: '\n\t', + styleSeparator: ': ', + offset: 0 + }; + + var reSpaceStart = /^\s+/; + var reSpaceEnd = /\s+$/; + var WHITESPACE_REMOVE_FROM_START = 1; + var WHITESPACE_REMOVE_FROM_END = 2; + + /** + * Modifies given range to remove whitespace from beginning + * and/or from the end + * @param {Range} rng Range to modify + * @param {String} text Text that range belongs to + * @param {Number} mask Mask indicating from which end + * whitespace should be removed + * @return {Range} + */ + function trimWhitespaceInRange(rng, text, mask) { + mask = mask || (WHITESPACE_REMOVE_FROM_START | WHITESPACE_REMOVE_FROM_END); + text = rng.substring(text); + var m; + if ((mask & WHITESPACE_REMOVE_FROM_START) && (m = text.match(reSpaceStart))) { + rng.start += m[0].length; + } + + if ((mask & WHITESPACE_REMOVE_FROM_END) && (m = text.match(reSpaceEnd))) { + rng.end -= m[0].length; + } + + // in case given range is just a whatespace + if (rng.end < rng.start) { + rng.end = rng.start; + } + + return rng; + } + + /** + * Consumes CSS property and value from current token + * iterator state. Offsets iterator pointer into token + * that can be used for next value consmption + * @param {TokenIterator} it + * @param {String} text + * @return {Object} Object with `name` and `value` properties + * ar ranges. Value range can be zero-length. + */ + function consumeSingleProperty(it, text) { + var name, value, end; + var token = it.current(); + + if (!token) { + return null; + } + + // skip whitespace + var ws = {'white': 1, 'line': 1, 'comment': 1}; + while ((token = it.current())) { + if (!(token.type in ws)) { + break; + } + it.next(); + } + + if (!it.hasNext()) { + return null; + } + + // consume property name + token = it.current(); + name = range(token.start, token.value); + var isAtProperty = token.value.charAt(0) == '@'; + while (token = it.next()) { + name.end = token.end; + if (token.type == ':' || token.type == 'white') { + name.end = token.start; + it.next(); + if (token.type == ':' || isAtProperty) { + // XXX I really ashame of this hardcode, but I need + // to stop parsing if this is an SCSS mixin call, + // for example: @include border-radius(10px) + break; + } + } else if (token.type == ';' || token.type == 'line') { + // there’s no value, looks like a mixin + // or a special use case: + // user is writing a new property or abbreviation + name.end = token.start; + value = range(token.start, 0); + it.next(); + break; + } + } + + token = it.current(); + if (!value && token) { + if (token.type == 'line') { + lastNewline = token; + } + // consume value + value = range(token.start, token.value); + var lastNewline; + while ((token = it.next())) { + value.end = token.end; + if (token.type == 'line') { + lastNewline = token; + } else if (token.type == '}' || token.type == ';') { + value.end = token.start; + if (token.type == ';') { + end = range(token.start, token.value); + } + it.next(); + break; + } else if (token.type == ':' && lastNewline) { + // A special case: + // user is writing a value before existing + // property, but didn’t inserted closing semi-colon. + // In this case, limit value range to previous + // newline + value.end = lastNewline.start; + it._i = it.tokens.indexOf(lastNewline); + break; + } + } + } + + if (!value) { + value = range(name.end, 0); + } + + return { + name: trimWhitespaceInRange(name, text), + value: trimWhitespaceInRange(value, text, WHITESPACE_REMOVE_FROM_START | (end ? WHITESPACE_REMOVE_FROM_END : 0)), + end: end || range(value.end, 0) + }; + } + + /** + * Finds parts of complex CSS value + * @param {String} str + * @returns {Array} Returns list of Range's + */ + function findParts(str) { + /** @type StringStream */ + var stream = stringStream.create(str); + var ch; + var result = []; + var sep = /[\s\u00a0,;]/; + + var add = function() { + stream.next(); + result.push(range(stream.start, stream.current())); + stream.start = stream.pos; + }; + + // skip whitespace + stream.eatSpace(); + stream.start = stream.pos; + + while ((ch = stream.next())) { + if (ch == '"' || ch == "'") { + stream.next(); + if (!stream.skipTo(ch)) break; + add(); + } else if (ch == '(') { + // function found, may have nested function + stream.backUp(1); + if (!stream.skipToPair('(', ')')) break; + stream.backUp(1); + add(); + } else { + if (sep.test(ch)) { + result.push(range(stream.start, stream.current().length - 1)); + stream.eatWhile(sep); + stream.start = stream.pos; + } + } + } + + add(); + + return utils.unique(result.filter(function(item) { + return !!item.length(); + })); + } + + /** + * Parses CSS properties from given CSS source + * and adds them to CSSEditContainer node + * @param {CSSEditContainer} node + * @param {String} source CSS source + * @param {Number} offset Offset of properties subset from original source + */ + function consumeProperties(node, source, offset) { + var list = extractPropertiesFromSource(source, offset); + + list.forEach(function(property) { + node._children.push(new CSSEditElement(node, + editTree.createToken(property.name.start, property.nameText), + editTree.createToken(property.value.start, property.valueText), + editTree.createToken(property.end.start, property.endText) + )); + }); + } + + /** + * Parses given CSS source and returns list of ranges of located CSS properties. + * Normally, CSS source must contain properties only, it must be, + * for example, a content of CSS selector or text between nested + * CSS sections + * @param {String} source CSS source + * @param {Number} offset Offset of properties subset from original source. + * Used to provide proper ranges of locates items + */ + function extractPropertiesFromSource(source, offset) { + offset = offset || 0; + source = source.replace(reSpaceEnd, ''); + var out = []; + + if (!source) { + return out; + } + + var tokens = cssParser.parse(source); + var it = tokenIterator.create(tokens); + var property; + + while ((property = consumeSingleProperty(it, source))) { + out.push({ + nameText: property.name.substring(source), + name: property.name.shift(offset), + + valueText: property.value.substring(source), + value: property.value.shift(offset), + + endText: property.end.substring(source), + end: property.end.shift(offset) + }); + } + + return out; + } + + /** + * @class + * @extends EditContainer + */ + var CSSEditContainer = editTree.EditContainer.extend({ + initialize: function(source, options) { + utils.extend(this.options, defaultOptions, options); + + if (Array.isArray(source)) { + source = cssParser.toSource(source); + } + + var allRules = cssSections.findAllRules(source); + var currentRule = allRules.shift(); + + // keep top-level rules only since they will + // be parsed by nested CSSEditContainer call + var topLevelRules = []; + allRules.forEach(function(r) { + var isTopLevel = !utils.find(topLevelRules, function(tr) { + return tr.contains(r); + }); + + if (isTopLevel) { + topLevelRules.push(r); + } + }); + + + var selectorRange = range.create2(currentRule.start, currentRule._selectorEnd); + this._name = selectorRange.substring(source); + this._positions.name = selectorRange.start; + this._positions.contentStart = currentRule._contentStart + 1; + + var sectionOffset = currentRule._contentStart + 1; + var sectionEnd = currentRule.end - 1; + + // parse properties between nested rules + // and add nested rules as children + var that = this; + topLevelRules.forEach(function(r) { + consumeProperties(that, source.substring(sectionOffset, r.start), sectionOffset); + var opt = utils.extend({}, that.options, {offset: r.start + that.options.offset}); + // XXX I think I don’t need nested containers here + // They should be handled separately + // that._children.push(new CSSEditContainer(r.substring(source), opt)); + sectionOffset = r.end; + }); + + // consume the rest of data + consumeProperties(this, source.substring(sectionOffset, currentRule.end - 1), sectionOffset); + this._saveStyle(); + }, + + /** + * Remembers all styles of properties + * @private + */ + _saveStyle: function() { + var start = this._positions.contentStart; + var source = this.source; + + this.list().forEach(function(p) { + if (p.type === 'container') { + return; + } + + p.styleBefore = source.substring(start, p.namePosition()); + // a small hack here: + // Sometimes users add empty lines before properties to logically + // separate groups of properties. In this case, a blind copy of + // characters between rules may lead to undesired behavior, + // especially when current rule is duplicated or used as a donor + // to create new rule. + // To solve this issue, we‘ll take only last newline indentation + var lines = utils.splitByLines(p.styleBefore); + if (lines.length > 1) { + p.styleBefore = '\n' + lines[lines.length - 1]; + } + + p.styleSeparator = source.substring(p.nameRange().end, p.valuePosition()); + + // graceful and naive comments removal + var parts = p.styleBefore.split('*/'); + p.styleBefore = parts[parts.length - 1]; + p.styleSeparator = p.styleSeparator.replace(/\/\*.*?\*\//g, ''); + + start = p.range().end; + }); + }, + + /** + * Returns position of element name token + * @param {Boolean} isAbsolute Return absolute position + * @returns {Number} + */ + namePosition: function(isAbsolute) { + return this._pos(this._positions.name, isAbsolute); + }, + + /** + * Returns position of element value token + * @param {Boolean} isAbsolute Return absolute position + * @returns {Number} + */ + valuePosition: function(isAbsolute) { + return this._pos(this._positions.contentStart, isAbsolute); + }, + + /** + * Returns element value range + * @param {Boolean} isAbsolute Return absolute range + * @returns {Range} + */ + valueRange: function(isAbsolute) { + return range.create2(this.valuePosition(isAbsolute), this._pos(this.valueOf().length, isAbsolute) - 1); + }, + + /** + * Adds new CSS property + * @param {String} name Property name + * @param {String} value Property value + * @param {Number} pos Position at which to insert new property. By + * default the property is inserted at the end of rule + * @returns {CSSEditProperty} + */ + add: function(name, value, pos) { + var list = this.list(); + var start = this._positions.contentStart; + var styles = utils.pick(this.options, 'styleBefore', 'styleSeparator'); + + if (typeof pos === 'undefined') { + pos = list.length; + } + + /** @type CSSEditProperty */ + var donor = list[pos]; + if (donor) { + start = donor.fullRange().start; + } else if ((donor = list[pos - 1])) { + // make sure that donor has terminating semicolon + donor.end(';'); + start = donor.range().end; + } + + if (donor) { + styles = utils.pick(donor, 'styleBefore', 'styleSeparator'); + } + + var nameToken = editTree.createToken(start + styles.styleBefore.length, name); + var valueToken = editTree.createToken(nameToken.end + styles.styleSeparator.length, value); + + var property = new CSSEditElement(this, nameToken, valueToken, + editTree.createToken(valueToken.end, ';')); + + utils.extend(property, styles); + + // write new property into the source + this._updateSource(property.styleBefore + property.toString(), start); + + // insert new property + this._children.splice(pos, 0, property); + return property; + } + }); + + /** + * @class + * @type CSSEditElement + * @constructor + */ + var CSSEditElement = editTree.EditElement.extend({ + initialize: function(rule, name, value, end) { + this.styleBefore = rule.options.styleBefore; + this.styleSeparator = rule.options.styleSeparator; + + this._end = end.value; + this._positions.end = end.start; + }, + + /** + * Returns ranges of complex value parts + * @returns {Array} Returns null if value is not complex + */ + valueParts: function(isAbsolute) { + var parts = findParts(this.value()); + if (isAbsolute) { + var offset = this.valuePosition(true); + parts.forEach(function(p) { + p.shift(offset); + }); + } + + return parts; + }, + + /** + * Sets of gets element value. + * When setting value, this implementation will ensure that your have + * proper name-value separator + * @param {String} val New element value. If not passed, current + * value is returned + * @returns {String} + */ + value: function(val) { + var isUpdating = typeof val !== 'undefined'; + var allItems = this.parent.list(); + if (isUpdating && this.isIncomplete()) { + var self = this; + var donor = utils.find(allItems, function(item) { + return item !== self && !item.isIncomplete(); + }); + + this.styleSeparator = donor + ? donor.styleSeparator + : this.parent.options.styleSeparator; + this.parent._updateSource(this.styleSeparator, range(this.valueRange().start, 0)); + } + + var value = this.constructor.__super__.value.apply(this, arguments); + if (isUpdating) { + // make sure current property has terminating semi-colon + // if it’s not the last one + var ix = allItems.indexOf(this); + if (ix !== allItems.length - 1 && !this.end()) { + this.end(';'); + } + } + return value; + }, + + /** + * Test if current element is incomplete, e.g. has no explicit + * name-value separator + * @return {Boolean} [description] + */ + isIncomplete: function() { + return this.nameRange().end === this.valueRange().start; + }, + + /** + * Sets of gets property end value (basically, it's a semicolon) + * @param {String} val New end value. If not passed, current + * value is returned + */ + end: function(val) { + if (typeof val !== 'undefined' && this._end !== val) { + this.parent._updateSource(val, this._positions.end, this._positions.end + this._end.length); + this._end = val; + } + + return this._end; + }, + + /** + * Returns full rule range, with indentation + * @param {Boolean} isAbsolute Return absolute range (with respect of + * rule offset) + * @returns {Range} + */ + fullRange: function(isAbsolute) { + var r = this.range(isAbsolute); + r.start -= this.styleBefore.length; + return r; + }, + + /** + * Returns item string representation + * @returns {String} + */ + valueOf: function() { + return this.name() + this.styleSeparator + this.value() + this.end(); + } + }); + + return { + /** + * Parses CSS rule into editable tree + * @param {String} source + * @param {Object} options + * @memberOf emmet.cssEditTree + * @returns {EditContainer} + */ + parse: function(source, options) { + return new CSSEditContainer(source, options); + }, + + /** + * Extract and parse CSS rule from specified position in content + * @param {String} content CSS source code + * @param {Number} pos Character position where to start source code extraction + * @returns {EditContainer} + */ + parseFromPosition: function(content, pos, isBackward) { + var bounds = cssSections.locateRule(content, pos, isBackward); + if (!bounds || !bounds.inside(pos)) { + // no matching CSS rule or caret outside rule bounds + return null; + } + + return this.parse(bounds.substring(content), { + offset: bounds.start + }); + }, + + /** + * Locates CSS property in given CSS code fragment under specified character position + * @param {String} css CSS code or parsed CSSEditContainer + * @param {Number} pos Character position where to search CSS property + * @return {CSSEditElement} + */ + propertyFromPosition: function(css, pos) { + var cssProp = null; + /** @type EditContainer */ + var cssRule = typeof css === 'string' ? this.parseFromPosition(css, pos, true) : css; + if (cssRule) { + cssProp = cssRule.itemFromPosition(pos, true); + if (!cssProp) { + // in case user just started writing CSS property + // and didn't include semicolon–try another approach + cssProp = utils.find(cssRule.list(), function(elem) { + return elem.range(true).end == pos; + }); + } + } + + return cssProp; + }, + + /** + * Removes vendor prefix from CSS property + * @param {String} name CSS property + * @return {String} + */ + baseName: function(name) { + return name.replace(/^\s*\-\w+\-/, ''); + }, + + /** + * Finds parts of complex CSS value + * @param {String} str + * @returns {Array} + */ + findParts: findParts, + + extractPropertiesFromSource: extractPropertiesFromSource + }; +}); +},{"../assets/range":"assets/range.js","../assets/stringStream":"assets/stringStream.js","../assets/tokenIterator":"assets/tokenIterator.js","../parser/css":"parser/css.js","../utils/common":"utils/common.js","../utils/cssSections":"utils/cssSections.js","./base":"editTree/base.js"}],"editTree/xml.js":[function(require,module,exports){ +/** + * XML EditTree is a module that can parse an XML/HTML element into a tree with + * convenient methods for adding, modifying and removing attributes. These + * changes can be written back to string with respect of code formatting. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var editTree = require('./base'); + var xmlParser = require('../parser/xml'); + var range = require('../assets/range'); + var utils = require('../utils/common'); + + var defaultOptions = { + styleBefore: ' ', + styleSeparator: '=', + styleQuote: '"', + offset: 0 + }; + + var startTag = /^<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/m; + + var XMLEditContainer = editTree.EditContainer.extend({ + initialize: function(source, options) { + utils.defaults(this.options, defaultOptions); + this._positions.name = 1; + + var attrToken = null; + var tokens = xmlParser.parse(source); + + tokens.forEach(function(token) { + token.value = range.create(token).substring(source); + switch (token.type) { + case 'tag': + if (/^<[^\/]+/.test(token.value)) { + this._name = token.value.substring(1); + } + break; + + case 'attribute': + // add empty attribute + if (attrToken) { + this._children.push(new XMLEditElement(this, attrToken)); + } + + attrToken = token; + break; + + case 'string': + this._children.push(new XMLEditElement(this, attrToken, token)); + attrToken = null; + break; + } + }, this); + + if (attrToken) { + this._children.push(new XMLEditElement(this, attrToken)); + } + + this._saveStyle(); + }, + + /** + * Remembers all styles of properties + * @private + */ + _saveStyle: function() { + var start = this.nameRange().end; + var source = this.source; + + this.list().forEach(function(p) { + p.styleBefore = source.substring(start, p.namePosition()); + + if (p.valuePosition() !== -1) { + p.styleSeparator = source.substring(p.namePosition() + p.name().length, p.valuePosition() - p.styleQuote.length); + } + + start = p.range().end; + }); + }, + + /** + * Adds new attribute + * @param {String} name Property name + * @param {String} value Property value + * @param {Number} pos Position at which to insert new property. By + * default the property is inserted at the end of rule + */ + add: function(name, value, pos) { + var list = this.list(); + var start = this.nameRange().end; + var styles = utils.pick(this.options, 'styleBefore', 'styleSeparator', 'styleQuote'); + + if (typeof pos === 'undefined') { + pos = list.length; + } + + + /** @type XMLEditAttribute */ + var donor = list[pos]; + if (donor) { + start = donor.fullRange().start; + } else if ((donor = list[pos - 1])) { + start = donor.range().end; + } + + if (donor) { + styles = utils.pick(donor, 'styleBefore', 'styleSeparator', 'styleQuote'); + } + + value = styles.styleQuote + value + styles.styleQuote; + + var attribute = new XMLEditElement(this, + editTree.createToken(start + styles.styleBefore.length, name), + editTree.createToken(start + styles.styleBefore.length + name.length + + styles.styleSeparator.length, value) + ); + + utils.extend(attribute, styles); + + // write new attribute into the source + this._updateSource(attribute.styleBefore + attribute.toString(), start); + + // insert new attribute + this._children.splice(pos, 0, attribute); + return attribute; + }, + + /** + * A special case of attribute editing: adds class value to existing + * `class` attribute + * @param {String} value + */ + addClass: function(value) { + var attr = this.get('class'); + value = utils.trim(value); + if (!attr) { + return this.add('class', value); + } + + var classVal = attr.value(); + var classList = ' ' + classVal.replace(/\n/g, ' ') + ' '; + if (!~classList.indexOf(' ' + value + ' ')) { + attr.value(classVal + ' ' + value); + } + }, + + /** + * A special case of attribute editing: removes class value from existing + * `class` attribute + * @param {String} value + */ + removeClass: function(value) { + var attr = this.get('class'); + value = utils.trim(value); + if (!attr) { + return; + } + + var reClass = new RegExp('(^|\\s+)' + utils.escapeForRegexp(value)); + var classVal = attr.value().replace(reClass, ''); + if (!utils.trim(classVal)) { + this.remove('class'); + } else { + attr.value(classVal); + } + } + }); + + var XMLEditElement = editTree.EditElement.extend({ + initialize: function(parent, nameToken, valueToken) { + this.styleBefore = parent.options.styleBefore; + this.styleSeparator = parent.options.styleSeparator; + + var value = '', quote = parent.options.styleQuote; + if (valueToken) { + value = valueToken.value; + quote = value.charAt(0); + if (quote == '"' || quote == "'") { + value = value.substring(1); + } else { + quote = ''; + } + + if (quote && value.charAt(value.length - 1) == quote) { + value = value.substring(0, value.length - 1); + } + } + + this.styleQuote = quote; + + this._value = value; + this._positions.value = valueToken ? valueToken.start + quote.length : -1; + }, + + /** + * Returns full rule range, with indentation + * @param {Boolean} isAbsolute Return absolute range (with respect of + * rule offset) + * @returns {Range} + */ + fullRange: function(isAbsolute) { + var r = this.range(isAbsolute); + r.start -= this.styleBefore.length; + return r; + }, + + valueOf: function() { + return this.name() + this.styleSeparator + + this.styleQuote + this.value() + this.styleQuote; + } + }); + + return { + /** + * Parses HTML element into editable tree + * @param {String} source + * @param {Object} options + * @memberOf emmet.htmlEditTree + * @returns {EditContainer} + */ + parse: function(source, options) { + return new XMLEditContainer(source, options); + }, + + /** + * Extract and parse HTML from specified position in content + * @param {String} content CSS source code + * @param {Number} pos Character position where to start source code extraction + * @returns {XMLEditElement} + */ + parseFromPosition: function(content, pos, isBackward) { + var bounds = this.extractTag(content, pos, isBackward); + if (!bounds || !bounds.inside(pos)) + // no matching HTML tag or caret outside tag bounds + return null; + + return this.parse(bounds.substring(content), { + offset: bounds.start + }); + }, + + /** + * Extracts nearest HTML tag range from content, starting at + * pos position + * @param {String} content + * @param {Number} pos + * @param {Boolean} isBackward + * @returns {Range} + */ + extractTag: function(content, pos, isBackward) { + var len = content.length, i; + + // max extraction length. I don't think there may be tags larger + // than 2000 characters length + var maxLen = Math.min(2000, len); + + /** @type Range */ + var r = null; + + var match = function(pos) { + var m; + if (content.charAt(pos) == '<' && (m = content.substr(pos, maxLen).match(startTag))) + return range.create(pos, m[0]); + }; + + // lookup backward, in case we are inside tag already + for (i = pos; i >= 0; i--) { + if ((r = match(i))) break; + } + + if (r && (r.inside(pos) || isBackward)) + return r; + + if (!r && isBackward) + return null; + + // search forward + for (i = pos; i < len; i++) { + if ((r = match(i))) + return r; + } + } + }; +}); +},{"../assets/range":"assets/range.js","../parser/xml":"parser/xml.js","../utils/common":"utils/common.js","./base":"editTree/base.js"}],"filter/bem.js":[function(require,module,exports){ +/** + * Filter for aiding of writing elements with complex class names as described + * in Yandex's BEM (Block, Element, Modifier) methodology. This filter will + * automatically inherit block and element names from parent elements and insert + * them into child element classes + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var htmlFilter = require('./html'); + var prefs = require('../assets/preferences'); + var abbreviationUtils = require('../utils/abbreviation'); + var utils = require('../utils/common'); + + prefs.define('bem.elementSeparator', '__', 'Class name’s element separator.'); + prefs.define('bem.modifierSeparator', '_', 'Class name’s modifier separator.'); + prefs.define('bem.shortElementPrefix', '-', + 'Symbol for describing short “block-element” notation. Class names ' + + 'prefixed with this symbol will be treated as element name for parent‘s ' + + 'block name. Each symbol instance traverses one level up in parsed ' + + 'tree for block name lookup. Empty value will disable short notation.'); + + var shouldRunHtmlFilter = false; + + function getSeparators() { + return { + element: prefs.get('bem.elementSeparator'), + modifier: prefs.get('bem.modifierSeparator') + }; + } + + /** + * @param {AbbreviationNode} item + */ + function bemParse(item) { + if (abbreviationUtils.isSnippet(item)) + return item; + + // save BEM stuff in cache for faster lookups + item.__bem = { + block: '', + element: '', + modifier: '' + }; + + var classNames = normalizeClassName(item.attribute('class')).split(' '); + + // guess best match for block name + var reBlockName = /^[a-z]\-/i; + item.__bem.block = utils.find(classNames, function(name) { + return reBlockName.test(name); + }); + + // guessing doesn't worked, pick first class name as block name + if (!item.__bem.block) { + reBlockName = /^[a-z]/i; + item.__bem.block = utils.find(classNames, function(name) { + return reBlockName.test(name); + }) || ''; + } + + classNames = classNames.map(function(name) { + return processClassName(name, item); + }); + + classNames = utils.unique(utils.flatten(classNames)).join(' '); + if (classNames) { + item.attribute('class', classNames); + } + + return item; + } + + /** + * @param {String} className + * @returns {String} + */ + function normalizeClassName(className) { + className = (' ' + (className || '') + ' ').replace(/\s+/g, ' '); + + var shortSymbol = prefs.get('bem.shortElementPrefix'); + if (shortSymbol) { + var re = new RegExp('\\s(' + utils.escapeForRegexp(shortSymbol) + '+)', 'g'); + className = className.replace(re, function(str, p1) { + return ' ' + utils.repeatString(getSeparators().element, p1.length); + }); + } + + return utils.trim(className); + } + + /** + * Processes class name + * @param {String} name Class name item to process + * @param {AbbreviationNode} item Host node for provided class name + * @returns Processed class name. May return Array of + * class names + */ + function processClassName(name, item) { + name = transformClassName(name, item, 'element'); + name = transformClassName(name, item, 'modifier'); + + // expand class name + // possible values: + // * block__element + // * block__element_modifier + // * block__element_modifier1_modifier2 + // * block_modifier + var block = '', element = '', modifier = ''; + var separators = getSeparators(); + if (~name.indexOf(separators.element)) { + var elements = name.split(separators.element); + block = elements.shift(); + + var modifiers = elements.pop().split(separators.modifier); + elements.push(modifiers.shift()); + element = elements.join(separators.element); + modifier = modifiers.join(separators.modifier); + } else if (~name.indexOf(separators.modifier)) { + var blockModifiers = name.split(separators.modifier); + + block = blockModifiers.shift(); + modifier = blockModifiers.join(separators.modifier); + } + + if (block || element || modifier) { + if (!block) { + block = item.__bem.block; + } + + // inherit parent bem element, if exists +// if (item.parent && item.parent.__bem && item.parent.__bem.element) +// element = item.parent.__bem.element + separators.element + element; + + // produce multiple classes + var prefix = block; + var result = []; + + if (element) { + prefix += separators.element + element; + result.push(prefix); + } else { + result.push(prefix); + } + + if (modifier) { + result.push(prefix + separators.modifier + modifier); + } + + item.__bem.block = block; + item.__bem.element = element; + item.__bem.modifier = modifier; + + return result; + } + + // ...otherwise, return processed or original class name + return name; + } + + /** + * Low-level function to transform user-typed class name into full BEM class + * @param {String} name Class name item to process + * @param {AbbreviationNode} item Host node for provided class name + * @param {String} entityType Type of entity to be tried to transform + * ('element' or 'modifier') + * @returns {String} Processed class name or original one if it can't be + * transformed + */ + function transformClassName(name, item, entityType) { + var separators = getSeparators(); + var reSep = new RegExp('^(' + separators[entityType] + ')+', 'g'); + if (reSep.test(name)) { + var depth = 0; // parent lookup depth + var cleanName = name.replace(reSep, function(str) { + depth = str.length / separators[entityType].length; + return ''; + }); + + // find donor element + var donor = item; + while (donor.parent && depth--) { + donor = donor.parent; + } + + if (!donor || !donor.__bem) + donor = item; + + if (donor && donor.__bem) { + var prefix = donor.__bem.block; + + // decide if we should inherit element name +// if (entityType == 'element') { +// var curElem = cleanName.split(separators.modifier, 1)[0]; +// if (donor.__bem.element && donor.__bem.element != curElem) +// prefix += separators.element + donor.__bem.element; +// } + + if (entityType == 'modifier' && donor.__bem.element) + prefix += separators.element + donor.__bem.element; + + return prefix + separators[entityType] + cleanName; + } + } + + return name; + } + + /** + * Recursive function for processing tags, which extends class names + * according to BEM specs: http://bem.github.com/bem-method/pages/beginning/beginning.ru.html + *

+ * It does several things:
+ *
    + *
  • Expands complex class name (according to BEM symbol semantics): + * .block__elem_modifier → .block.block__elem.block__elem_modifier + *
  • + *
  • Inherits block name on child elements: + * .b-block > .__el > .__el → .b-block > .b-block__el > .b-block__el__el + *
  • + *
  • Treats first dash symbol as '__'
  • + *
  • Double underscore (or typographic '–') is also treated as an element + * level lookup, e.g. ____el will search for element definition in parent’s + * parent element: + * .b-block > .__el1 > .____el2 → .b-block > .b-block__el1 > .b-block__el2 + *
  • + *
+ * + * @param {AbbreviationNode} tree + * @param {Object} profile + */ + function process(tree, profile) { + if (tree.name) { + bemParse(tree, profile); + } + + tree.children.forEach(function(item) { + process(item, profile); + if (!abbreviationUtils.isSnippet(item) && item.start) { + shouldRunHtmlFilter = true; + } + }); + + return tree; + } + + return function(tree, profile) { + shouldRunHtmlFilter = false; + tree = process(tree, profile); + // in case 'bem' filter is applied after 'html' filter: run it again + // to update output + if (shouldRunHtmlFilter) { + tree = htmlFilter(tree, profile); + } + + return tree; + }; +}); +},{"../assets/preferences":"assets/preferences.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","./html":"filter/html.js"}],"filter/comment.js":[function(require,module,exports){ +/** + * Comment important tags (with 'id' and 'class' attributes) + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + var utils = require('../utils/common'); + var template = require('../utils/template'); + var abbrUtils = require('../utils/abbreviation'); + var filterCore = require('./main'); + + prefs.define('filter.commentAfter', + '\n', + 'A definition of comment that should be placed after matched ' + + 'element when comment filter is applied. This definition ' + + 'is an ERB-style template passed to _.template() ' + + 'function (see Underscore.js docs for details). In template context, ' + + 'the following properties and functions are availabe:\n' + + '
    ' + + + '
  • attr(name, before, after) – a function that outputs' + + 'specified attribute value concatenated with before ' + + 'and after strings. If attribute doesn\'t exists, the ' + + 'empty string will be returned.
  • ' + + + '
  • node – current node (instance of AbbreviationNode)
  • ' + + + '
  • name – name of current tag
  • ' + + + '
  • padding – current string padding, can be used ' + + 'for formatting
  • ' + + +'
'); + + prefs.define('filter.commentBefore', + '', + 'A definition of comment that should be placed before matched ' + + 'element when comment filter is applied. ' + + 'For more info, read description of filter.commentAfter ' + + 'property'); + + prefs.define('filter.commentTrigger', 'id, class', + 'A comma-separated list of attribute names that should exist in abbreviatoin ' + + 'where comment should be added. If you wish to add comment for ' + + 'every element, set this option to *'); + + /** + * Add comments to tag + * @param {AbbreviationNode} node + */ + function addComments(node, templateBefore, templateAfter) { + // check if comments should be added + var trigger = prefs.get('filter.commentTrigger'); + if (trigger != '*') { + var shouldAdd = utils.find(trigger.split(','), function(name) { + return !!node.attribute(utils.trim(name)); + }); + + if (!shouldAdd) { + return; + } + } + + var ctx = { + node: node, + name: node.name(), + padding: node.parent ? node.parent.padding : '', + attr: function(name, before, after) { + var attr = node.attribute(name); + if (attr) { + return (before || '') + attr + (after || ''); + } + + return ''; + } + }; + + var nodeBefore = templateBefore ? templateBefore(ctx) : ''; + var nodeAfter = templateAfter ? templateAfter(ctx) : ''; + + node.start = node.start.replace(//, '>' + nodeAfter); + } + + function process(tree, before, after) { + tree.children.forEach(function(item) { + if (abbrUtils.isBlock(item)) { + addComments(item, before, after); + } + + process(item, before, after); + }); + + return tree; + } + + return function(tree) { + var templateBefore = template(prefs.get('filter.commentBefore')); + var templateAfter = template(prefs.get('filter.commentAfter')); + + return process(tree, templateBefore, templateAfter); + }; +}); + +},{"../assets/preferences":"assets/preferences.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","../utils/template":"utils/template.js","./main":"filter/main.js"}],"filter/css.js":[function(require,module,exports){ +/** + * Filter for outputting CSS and alike + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + /** + * Test if passed item is very first child in parsed tree + * @param {AbbreviationNode} item + */ + function isVeryFirstChild(item) { + return item.parent && !item.parent.parent && !item.index(); + } + + return function process(tree, profile, level) { + level = level || 0; + + tree.children.forEach(function(item) { + if (!isVeryFirstChild(item) && profile.tag_nl !== false) { + item.start = '\n' + item.start; + } + process(item, profile, level + 1); + }); + + return tree; + }; +}); +},{}],"filter/escape.js":[function(require,module,exports){ +/** + * Filter for escaping unsafe XML characters: <, >, & + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var charMap = { + '<': '<', + '>': '>', + '&': '&' + }; + + function escapeChars(str) { + return str.replace(/([<>&])/g, function(str, p1){ + return charMap[p1]; + }); + } + + return function process(tree) { + tree.children.forEach(function(item) { + item.start = escapeChars(item.start); + item.end = escapeChars(item.end); + item.content = escapeChars(item.content); + process(item); + }); + + return tree; + }; +}); +},{}],"filter/format.js":[function(require,module,exports){ +/** + * Generic formatting filter: creates proper indentation for each tree node, + * placing "%s" placeholder where the actual output should be. You can use + * this filter to preformat tree and then replace %s placeholder to whatever you + * need. This filter should't be called directly from editor as a part + * of abbreviation. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var abbrUtils = require('../utils/abbreviation'); + var prefs = require('../assets/preferences'); + var resources = require('../assets/resources'); + + prefs.define('format.noIndentTags', 'html', + 'A comma-separated list of tag names that should not get inner indentation.'); + + prefs.define('format.forceIndentationForTags', 'body', + 'A comma-separated list of tag names that should always get inner indentation.'); + + var placeholder = '%s'; + + /** + * Get indentation for given node + * @param {AbbreviationNode} node + * @returns {String} + */ + function getIndentation(node) { + var items = prefs.getArray('format.noIndentTags') || []; + if (~items.indexOf(node.name())) { + return ''; + } + + return '\t'; + } + + /** + * Test if passed node has block-level sibling element + * @param {AbbreviationNode} item + * @return {Boolean} + */ + function hasBlockSibling(item) { + return item.parent && abbrUtils.hasBlockChildren(item.parent); + } + + /** + * Test if passed item is very first child in parsed tree + * @param {AbbreviationNode} item + */ + function isVeryFirstChild(item) { + return item.parent && !item.parent.parent && !item.index(); + } + + /** + * Check if a newline should be added before element + * @param {AbbreviationNode} node + * @param {OutputProfile} profile + * @return {Boolean} + */ + function shouldAddLineBreak(node, profile) { + if (profile.tag_nl === true || abbrUtils.isBlock(node)) + return true; + + if (!node.parent || !profile.inline_break) + return false; + + // check if there are required amount of adjacent inline element + return shouldFormatInline(node.parent, profile); +} + + /** + * Need to add newline because item has too many inline children + * @param {AbbreviationNode} node + * @param {OutputProfile} profile + */ + function shouldBreakChild(node, profile) { + // we need to test only one child element, because + // hasBlockChildren() method will do the rest + return node.children.length && shouldAddLineBreak(node.children[0], profile); + } + + function shouldFormatInline(node, profile) { + var nodeCount = 0; + return !!utils.find(node.children, function(child) { + if (child.isTextNode() || !abbrUtils.isInline(child)) + nodeCount = 0; + else if (abbrUtils.isInline(child)) + nodeCount++; + + if (nodeCount >= profile.inline_break) + return true; + }); + } + + function isRoot(item) { + return !item.parent; + } + + /** + * Processes element with matched resource of type snippet + * @param {AbbreviationNode} item + * @param {OutputProfile} profile + */ + function processSnippet(item, profile) { + item.start = item.end = ''; + if (!isVeryFirstChild(item) && profile.tag_nl !== false && shouldAddLineBreak(item, profile)) { + // check if we’re not inside inline element + if (isRoot(item.parent) || !abbrUtils.isInline(item.parent)) { + item.start = '\n' + item.start; + } + } + + return item; + } + + /** + * Check if we should add line breaks inside inline element + * @param {AbbreviationNode} node + * @param {OutputProfile} profile + * @return {Boolean} + */ + function shouldBreakInsideInline(node, profile) { + var hasBlockElems = node.children.some(function(child) { + if (abbrUtils.isSnippet(child)) + return false; + + return !abbrUtils.isInline(child); + }); + + if (!hasBlockElems) { + return shouldFormatInline(node, profile); + } + + return true; + } + + /** + * Processes element with tag type + * @param {AbbreviationNode} item + * @param {OutputProfile} profile + */ + function processTag(item, profile) { + item.start = item.end = placeholder; + var isUnary = abbrUtils.isUnary(item); + var nl = '\n'; + var indent = getIndentation(item); + + // formatting output + if (profile.tag_nl !== false) { + var forceNl = profile.tag_nl === true && (profile.tag_nl_leaf || item.children.length); + if (!forceNl) { + var forceIndentTags = prefs.getArray('format.forceIndentationForTags') || []; + forceNl = ~forceIndentTags.indexOf(item.name()); + } + + // formatting block-level elements + if (!item.isTextNode()) { + if (shouldAddLineBreak(item, profile)) { + // - do not indent the very first element + // - do not indent first child of a snippet + if (!isVeryFirstChild(item) && (!abbrUtils.isSnippet(item.parent) || item.index())) + item.start = nl + item.start; + + if (abbrUtils.hasBlockChildren(item) || shouldBreakChild(item, profile) || (forceNl && !isUnary)) + item.end = nl + item.end; + + if (abbrUtils.hasTagsInContent(item) || (forceNl && !item.children.length && !isUnary)) + item.start += nl + indent; + } else if (abbrUtils.isInline(item) && hasBlockSibling(item) && !isVeryFirstChild(item)) { + item.start = nl + item.start; + } else if (abbrUtils.isInline(item) && shouldBreakInsideInline(item, profile)) { + item.end = nl + item.end; + } + + item.padding = indent; + } + } + + return item; + } + + /** + * Processes simplified tree, making it suitable for output as HTML structure + * @param {AbbreviationNode} tree + * @param {OutputProfile} profile + * @param {Number} level Depth level + */ + return function process(tree, profile, level) { + level = level || 0; + + tree.children.forEach(function(item) { + if (abbrUtils.isSnippet(item)) { + processSnippet(item, profile, level); + } else { + processTag(item, profile, level); + } + + process(item, profile, level + 1); + }); + + return tree; + }; +}); +},{"../assets/preferences":"assets/preferences.js","../assets/resources":"assets/resources.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js"}],"filter/haml.js":[function(require,module,exports){ +/** + * Filter for producing HAML code from abbreviation. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var abbrUtils = require('../utils/abbreviation'); + var formatFilter = require('./format'); + + function transformClassName(className) { + return utils.trim(className).replace(/\s+/g, '.'); + } + + /** + * Condenses all "data-" attributes into a single entry. + * HAML allows data attributes to be ouputted as a sub-hash + * of `:data` key + * @param {Array} attrs + * @return {Array} + */ + function condenseDataAttrs(attrs) { + var out = [], data = null; + var reData = /^data-/i; + attrs.forEach(function(attr) { + if (reData.test(attr.name)) { + if (!data) { + data = []; + out.push({ + name: 'data', + value: data + }); + } + + data.push(utils.extend({}, attr, {name: attr.name.replace(reData, '')})); + } else { + out.push(attr); + } + }); + + return out; + } + + function stringifyAttrs(attrs, profile) { + var attrQuote = profile.attributeQuote(); + return '{' + attrs.map(function(attr) { + var value = attrQuote + attr.value + attrQuote; + if (Array.isArray(attr.value)) { + value = stringifyAttrs(attr.value, profile); + } else if (attr.isBoolean) { + value = 'true'; + } + + return ':' + attr.name + ' => ' + value + }).join(', ') + '}'; + } + + /** + * Creates HAML attributes string from tag according to profile settings + * @param {AbbreviationNode} tag + * @param {Object} profile + */ + function makeAttributesString(tag, profile) { + var attrs = ''; + var otherAttrs = []; + var attrQuote = profile.attributeQuote(); + var cursor = profile.cursor(); + + tag.attributeList().forEach(function(a) { + var attrName = profile.attributeName(a.name); + switch (attrName.toLowerCase()) { + // use short notation for ID and CLASS attributes + case 'id': + attrs += '#' + (a.value || cursor); + break; + case 'class': + attrs += '.' + transformClassName(a.value || cursor); + break; + // process other attributes + default: + otherAttrs.push({ + name: attrName, + value: a.value || cursor, + isBoolean: profile.isBoolean(a.name, a.value) + }); + } + }); + + if (otherAttrs.length) { + attrs += stringifyAttrs(condenseDataAttrs(otherAttrs), profile); + } + + return attrs; + } + + /** + * Processes element with tag type + * @param {AbbreviationNode} item + * @param {OutputProfile} profile + */ + function processTag(item, profile) { + if (!item.parent) + // looks like it's root element + return item; + + var attrs = makeAttributesString(item, profile); + var cursor = profile.cursor(); + var isUnary = abbrUtils.isUnary(item); + var selfClosing = profile.self_closing_tag && isUnary ? '/' : ''; + var start= ''; + + // define tag name + var tagName = '%' + profile.tagName(item.name()); + if (tagName.toLowerCase() == '%div' && attrs && attrs.indexOf('{') == -1) + // omit div tag + tagName = ''; + + item.end = ''; + start = tagName + attrs + selfClosing; + if (item.content && !/^\s/.test(item.content)) { + item.content = ' ' + item.content; + } + + var placeholder = '%s'; + // We can't just replace placeholder with new value because + // JavaScript will treat double $ character as a single one, assuming + // we're using RegExp literal. + item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder); + + if (!item.children.length && !isUnary) + item.start += cursor; + + return item; + } + + return function process(tree, profile, level) { + level = level || 0; + + if (!level) { + tree = formatFilter(tree, '_format', profile); + } + + tree.children.forEach(function(item) { + if (!abbrUtils.isSnippet(item)) { + processTag(item, profile, level); + } + + process(item, profile, level + 1); + }); + + return tree; + }; +}); +},{"../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","./format":"filter/format.js"}],"filter/html.js":[function(require,module,exports){ +/** + * Filter that produces HTML tree + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var abbrUtils = require('../utils/abbreviation'); + var utils = require('../utils/common'); + var tabStops = require('../assets/tabStops'); + var formatFilter = require('./format'); + + /** + * Creates HTML attributes string from tag according to profile settings + * @param {AbbreviationNode} node + * @param {OutputProfile} profile + */ + function makeAttributesString(node, profile) { + var attrQuote = profile.attributeQuote(); + var cursor = profile.cursor(); + + return node.attributeList().map(function(a) { + var isBoolean = profile.isBoolean(a.name, a.value); + var attrName = profile.attributeName(a.name); + var attrValue = isBoolean ? attrName : a.value; + if (isBoolean && profile.allowCompactBoolean()) { + return ' ' + attrName; + } + return ' ' + attrName + '=' + attrQuote + (attrValue || cursor) + attrQuote; + }).join(''); + } + + /** + * Processes element with tag type + * @param {AbbreviationNode} item + * @param {OutputProfile} profile + */ + function processTag(item, profile) { + if (!item.parent) { // looks like it's root element + return item; + } + + var attrs = makeAttributesString(item, profile); + var cursor = profile.cursor(); + var isUnary = abbrUtils.isUnary(item); + var start = ''; + var end = ''; + + // define opening and closing tags + if (!item.isTextNode()) { + var tagName = profile.tagName(item.name()); + if (isUnary) { + start = '<' + tagName + attrs + profile.selfClosing() + '>'; + item.end = ''; + } else { + start = '<' + tagName + attrs + '>'; + end = ''; + } + } + + var placeholder = '%s'; + // We can't just replace placeholder with new value because + // JavaScript will treat double $ character as a single one, assuming + // we're using RegExp literal. + item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder); + item.end = utils.replaceSubstring(item.end, end, item.end.indexOf(placeholder), placeholder); + + // should we put caret placeholder after opening tag? + if ( + !item.children.length + && !isUnary + && !~item.content.indexOf(cursor) + && !tabStops.extract(item.content).tabstops.length + ) { + item.start += cursor; + } + + return item; + } + + return function process(tree, profile, level) { + level = level || 0; + + if (!level) { + tree = formatFilter(tree, profile, level) + } + + tree.children.forEach(function(item) { + if (!abbrUtils.isSnippet(item)) { + processTag(item, profile, level); + } + + process(item, profile, level + 1); + }); + + return tree; + }; +}); +},{"../assets/tabStops":"assets/tabStops.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","./format":"filter/format.js"}],"filter/jade.js":[function(require,module,exports){ +/** + * Filter for producing Jade code from abbreviation. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var abbrUtils = require('../utils/abbreviation'); + var formatFilter = require('./format'); + var tabStops = require('../assets/tabStops'); + var profile = require('../assets/profile'); + + var reNl = /[\n\r]/; + var reIndentedText = /^\s*\|/; + var reSpace = /^\s/; + + function transformClassName(className) { + return utils.trim(className).replace(/\s+/g, '.'); + } + + function stringifyAttrs(attrs, profile) { + var attrQuote = profile.attributeQuote(); + return '(' + attrs.map(function(attr) { + if (attr.isBoolean) { + return attr.name; + } + + return attr.name + '=' + attrQuote + attr.value + attrQuote; + }).join(', ') + ')'; + } + + /** + * Creates HAML attributes string from tag according to profile settings + * @param {AbbreviationNode} tag + * @param {Object} profile + */ + function makeAttributesString(tag, profile) { + var attrs = ''; + var otherAttrs = []; + var attrQuote = profile.attributeQuote(); + var cursor = profile.cursor(); + + tag.attributeList().forEach(function(a) { + var attrName = profile.attributeName(a.name); + switch (attrName.toLowerCase()) { + // use short notation for ID and CLASS attributes + case 'id': + attrs += '#' + (a.value || cursor); + break; + case 'class': + attrs += '.' + transformClassName(a.value || cursor); + break; + // process other attributes + default: + otherAttrs.push({ + name: attrName, + value: a.value || cursor, + isBoolean: profile.isBoolean(a.name, a.value) + }); + } + }); + + if (otherAttrs.length) { + attrs += stringifyAttrs(otherAttrs, profile); + } + + return attrs; + } + + function processTagContent(item) { + if (!item.content) { + return; + } + + var content = tabStops.replaceVariables(item.content, function(str, name) { + if (name === 'nl' || name === 'newline') { + return '\n'; + } + return str; + }); + + if (reNl.test(content) && !reIndentedText.test(content)) { + // multiline content: pad it with indentation and pipe + var pad = '| '; + item.content = '\n' + pad + utils.padString(content, pad); + } else if (!reSpace.test(content)) { + item.content = ' ' + content; + } + } + + /** + * Processes element with tag type + * @param {AbbreviationNode} item + * @param {OutputProfile} profile + */ + function processTag(item, profile) { + if (!item.parent) + // looks like it's a root (empty) element + return item; + + var attrs = makeAttributesString(item, profile); + var cursor = profile.cursor(); + var isUnary = abbrUtils.isUnary(item); + + // define tag name + var tagName = profile.tagName(item.name()); + if (tagName.toLowerCase() == 'div' && attrs && attrs.charAt(0) != '(') + // omit div tag + tagName = ''; + + item.end = ''; + var start = tagName + attrs; + processTagContent(item); + + var placeholder = '%s'; + // We can't just replace placeholder with new value because + // JavaScript will treat double $ character as a single one, assuming + // we're using RegExp literal. + item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder); + + if (!item.children.length && !isUnary) + item.start += cursor; + + return item; + } + + return function process(tree, curProfile, level) { + level = level || 0; + + if (!level) { + // always format with `xml` profile since + // Jade requires all tags to be on separate lines + tree = formatFilter(tree, profile.get('xml')); + } + + tree.children.forEach(function(item) { + if (!abbrUtils.isSnippet(item)) { + processTag(item, curProfile, level); + } + + process(item, curProfile, level + 1); + }); + + return tree; + }; +}); +},{"../assets/profile":"assets/profile.js","../assets/tabStops":"assets/tabStops.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","./format":"filter/format.js"}],"filter/main.js":[function(require,module,exports){ +/** + * Module for handling filters + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var profile = require('../assets/profile'); + var resources = require('../assets/resources'); + + /** List of registered filters */ + var registeredFilters = { + html: require('./html'), + haml: require('./haml'), + jade: require('./jade'), + slim: require('./slim'), + xsl: require('./xsl'), + css: require('./css'), + bem: require('./bem'), + c: require('./comment'), + e: require('./escape'), + s: require('./singleLine'), + t: require('./trim') + }; + + /** Filters that will be applied for unknown syntax */ + var basicFilters = 'html'; + + function list(filters) { + if (!filters) + return []; + + if (typeof filters === 'string') { + return filters.split(/[\|,]/g); + } + + return filters; + } + + return { + /** + * Register new filter + * @param {String} name Filter name + * @param {Function} fn Filter function + */ + add: function(name, fn) { + registeredFilters[name] = fn; + }, + + /** + * Apply filters for final output tree + * @param {AbbreviationNode} tree Output tree + * @param {Array} filters List of filters to apply. Might be a + * String + * @param {Object} profile Output profile, defined in profile + * module. Filters defined it profile are not used, profile + * is passed to filter function + * @memberOf emmet.filters + * @returns {AbbreviationNode} + */ + apply: function(tree, filters, profileName) { + profileName = profile.get(profileName); + + list(filters).forEach(function(filter) { + var name = utils.trim(filter.toLowerCase()); + if (name && name in registeredFilters) { + tree = registeredFilters[name](tree, profileName); + } + }); + + return tree; + }, + + /** + * Composes list of filters that should be applied to a tree, based on + * passed data + * @param {String} syntax Syntax name ('html', 'css', etc.) + * @param {Object} profile Output profile + * @param {String} additionalFilters List or pipe-separated + * string of additional filters to apply + * @returns {Array} + */ + composeList: function(syntax, profileName, additionalFilters) { + profileName = profile.get(profileName); + var filters = list(profileName.filters || resources.findItem(syntax, 'filters') || basicFilters); + + if (profileName.extraFilters) { + filters = filters.concat(list(profileName.extraFilters)); + } + + if (additionalFilters) { + filters = filters.concat(list(additionalFilters)); + } + + if (!filters || !filters.length) { + // looks like unknown syntax, apply basic filters + filters = list(basicFilters); + } + + return filters; + }, + + /** + * Extracts filter list from abbreviation + * @param {String} abbr + * @returns {Array} Array with cleaned abbreviation and list of + * extracted filters + */ + extract: function(abbr) { + var filters = ''; + abbr = abbr.replace(/\|([\w\|\-]+)$/, function(str, p1){ + filters = p1; + return ''; + }); + + return [abbr, list(filters)]; + } + }; +}); +},{"../assets/profile":"assets/profile.js","../assets/resources":"assets/resources.js","../utils/common":"utils/common.js","./bem":"filter/bem.js","./comment":"filter/comment.js","./css":"filter/css.js","./escape":"filter/escape.js","./haml":"filter/haml.js","./html":"filter/html.js","./jade":"filter/jade.js","./singleLine":"filter/singleLine.js","./slim":"filter/slim.js","./trim":"filter/trim.js","./xsl":"filter/xsl.js"}],"filter/singleLine.js":[function(require,module,exports){ +/** + * Output abbreviation on a single line (i.e. no line breaks) + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var abbrUtils = require('../utils/abbreviation'); + var rePad = /^\s+/; + var reNl = /[\n\r]/g; + + return function process(tree) { + tree.children.forEach(function(item) { + if (!abbrUtils.isSnippet(item)) { + // remove padding from item + item.start = item.start.replace(rePad, ''); + item.end = item.end.replace(rePad, ''); + } + + // remove newlines + item.start = item.start.replace(reNl, ''); + item.end = item.end.replace(reNl, ''); + item.content = item.content.replace(reNl, ''); + + process(item); + }); + + return tree; + }; +}); + +},{"../utils/abbreviation":"utils/abbreviation.js"}],"filter/slim.js":[function(require,module,exports){ +/** + * Filter for producing Jade code from abbreviation. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + var abbrUtils = require('../utils/abbreviation'); + var formatFilter = require('./format'); + var tabStops = require('../assets/tabStops'); + var prefs = require('../assets/preferences'); + var profile = require('../assets/profile'); + + var reNl = /[\n\r]/; + var reIndentedText = /^\s*\|/; + var reSpace = /^\s/; + + prefs.define('slim.attributesWrapper', 'none', + 'Defines how attributes will be wrapped:' + + '
    ' + + '
  • none – no wrapping;
  • ' + + '
  • round — wrap attributes with round braces;
  • ' + + '
  • square — wrap attributes with round braces;
  • ' + + '
  • curly — wrap attributes with curly braces.
  • ' + + '
'); + + function transformClassName(className) { + return utils.trim(className).replace(/\s+/g, '.'); + } + + function getAttrWrapper() { + var start = ' ', end = ''; + switch (prefs.get('slim.attributesWrapper')) { + case 'round': + start = '('; + end = ')'; + break; + case 'square': + start = '['; + end = ']'; + break; + case 'curly': + start = '{'; + end = '}'; + break; + } + + return { + start: start, + end: end + }; + } + + function stringifyAttrs(attrs, profile) { + var attrQuote = profile.attributeQuote(); + var attrWrap = getAttrWrapper(); + return attrWrap.start + attrs.map(function(attr) { + var value = attrQuote + attr.value + attrQuote; + if (attr.isBoolean) { + if (!attrWrap.end) { + value = 'true'; + } else { + return attr.name; + } + } + + return attr.name + '=' + value; + }).join(' ') + attrWrap.end; + } + + /** + * Creates HAML attributes string from tag according to profile settings + * @param {AbbreviationNode} tag + * @param {Object} profile + */ + function makeAttributesString(tag, profile) { + var attrs = ''; + var otherAttrs = []; + var attrQuote = profile.attributeQuote(); + var cursor = profile.cursor(); + + tag.attributeList().forEach(function(a) { + var attrName = profile.attributeName(a.name); + switch (attrName.toLowerCase()) { + // use short notation for ID and CLASS attributes + case 'id': + attrs += '#' + (a.value || cursor); + break; + case 'class': + attrs += '.' + transformClassName(a.value || cursor); + break; + // process other attributes + default: + otherAttrs.push({ + name: attrName, + value: a.value || cursor, + isBoolean: profile.isBoolean(a.name, a.value) + }); + } + }); + + if (otherAttrs.length) { + attrs += stringifyAttrs(otherAttrs, profile); + } + + return attrs; + } + + function processTagContent(item) { + if (!item.content) { + return; + } + + var content = tabStops.replaceVariables(item.content, function(str, name) { + if (name === 'nl' || name === 'newline') { + return '\n'; + } + return str; + }); + + if (reNl.test(content) && !reIndentedText.test(content)) { + // multiline content: pad it with indentation and pipe + var pad = ' '; + item.content = '\n| ' + utils.padString(content, pad); + } else if (!reSpace.test(content)) { + item.content = ' ' + content; + } + } + + /** + * Processes element with tag type + * @param {AbbreviationNode} item + * @param {OutputProfile} profile + */ + function processTag(item, profile) { + if (!item.parent) + // looks like it's a root (empty) element + return item; + + var attrs = makeAttributesString(item, profile); + var cursor = profile.cursor(); + var isUnary = abbrUtils.isUnary(item); + var selfClosing = profile.self_closing_tag && isUnary ? '/' : ''; + + // define tag name + var tagName = profile.tagName(item.name()); + if (tagName.toLowerCase() == 'div' && attrs && '([{'.indexOf(attrs.charAt(0)) == -1) + // omit div tag + tagName = ''; + + item.end = ''; + var start = tagName + attrs + selfClosing; + processTagContent(item); + + var placeholder = '%s'; + // We can't just replace placeholder with new value because + // JavaScript will treat double $ character as a single one, assuming + // we're using RegExp literal. + item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder); + + if (!item.children.length && !isUnary) + item.start += cursor; + + return item; + } + + return function process(tree, curProfile, level) { + level = level || 0; + + if (!level) { + // always format with `xml` profile since + // Slim requires all tags to be on separate lines + tree = formatFilter(tree, profile.get('xml')); + } + + tree.children.forEach(function(item) { + if (!abbrUtils.isSnippet(item)) { + processTag(item, curProfile, level); + } + + process(item, curProfile, level + 1); + }); + + return tree; + }; +}); +},{"../assets/preferences":"assets/preferences.js","../assets/profile":"assets/profile.js","../assets/tabStops":"assets/tabStops.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","./format":"filter/format.js"}],"filter/trim.js":[function(require,module,exports){ +/** + * Trim filter: removes characters at the beginning of the text + * content that indicates lists: numbers, #, *, -, etc. + * + * Useful for wrapping lists with abbreviation. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + prefs.define('filter.trimRegexp', + '[\\s|\\u00a0]*[\\d|#|\\-|\*|\\u2022]+\\.?\\s*', + 'Regular expression used to remove list markers (numbers, dashes, ' + + 'bullets, etc.) in t (trim) filter. The trim filter ' + + 'is useful for wrapping with abbreviation lists, pased from other ' + + 'documents (for example, Word documents).'); + + function process(tree, re) { + tree.children.forEach(function(item) { + if (item.content) { + item.content = item.content.replace(re, ''); + } + + process(item, re); + }); + + return tree; + } + + return function(tree) { + var re = new RegExp(prefs.get('filter.trimRegexp')); + return process(tree, re); + }; +}); + +},{"../assets/preferences":"assets/preferences.js"}],"filter/xsl.js":[function(require,module,exports){ +/** + * Filter for trimming "select" attributes from some tags that contains + * child elements + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var abbrUtils = require('../utils/abbreviation'); + + var tags = { + 'xsl:variable': 1, + 'xsl:with-param': 1 + }; + + /** + * Removes "select" attribute from node + * @param {AbbreviationNode} node + */ + function trimAttribute(node) { + node.start = node.start.replace(/\s+select\s*=\s*(['"]).*?\1/, ''); + } + + return function process(tree) { + tree.children.forEach(function(item) { + if (!abbrUtils.isSnippet(item) + && (item.name() || '').toLowerCase() in tags + && item.children.length) + trimAttribute(item); + process(item); + }); + + return tree; + }; +}); +},{"../utils/abbreviation":"utils/abbreviation.js"}],"generator/lorem.js":[function(require,module,exports){ +/** + * "Lorem ipsum" text generator. Matches lipsum(num)? or + * lorem(num)? abbreviation. + * This code is based on Django's contribution: + * https://code.djangoproject.com/browser/django/trunk/django/contrib/webdesign/lorem_ipsum.py + *

+ * Examples to test:
+ * lipsum – generates 30 words text.
+ * lipsum*6 – generates 6 paragraphs (autowrapped with <p> element) of text.
+ * ol>lipsum10*5 — generates ordered list with 5 list items (autowrapped with <li> tag) + * with text of 10 words on each line.
+ * span*3>lipsum20 – generates 3 paragraphs of 20-words text, each wrapped with <span> element. + * Each paragraph phrase is unique. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + + var langs = { + en: { + common: ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipisicing', 'elit'], + words: ['exercitationem', 'perferendis', 'perspiciatis', 'laborum', 'eveniet', + 'sunt', 'iure', 'nam', 'nobis', 'eum', 'cum', 'officiis', 'excepturi', + 'odio', 'consectetur', 'quasi', 'aut', 'quisquam', 'vel', 'eligendi', + 'itaque', 'non', 'odit', 'tempore', 'quaerat', 'dignissimos', + 'facilis', 'neque', 'nihil', 'expedita', 'vitae', 'vero', 'ipsum', + 'nisi', 'animi', 'cumque', 'pariatur', 'velit', 'modi', 'natus', + 'iusto', 'eaque', 'sequi', 'illo', 'sed', 'ex', 'et', 'voluptatibus', + 'tempora', 'veritatis', 'ratione', 'assumenda', 'incidunt', 'nostrum', + 'placeat', 'aliquid', 'fuga', 'provident', 'praesentium', 'rem', + 'necessitatibus', 'suscipit', 'adipisci', 'quidem', 'possimus', + 'voluptas', 'debitis', 'sint', 'accusantium', 'unde', 'sapiente', + 'voluptate', 'qui', 'aspernatur', 'laudantium', 'soluta', 'amet', + 'quo', 'aliquam', 'saepe', 'culpa', 'libero', 'ipsa', 'dicta', + 'reiciendis', 'nesciunt', 'doloribus', 'autem', 'impedit', 'minima', + 'maiores', 'repudiandae', 'ipsam', 'obcaecati', 'ullam', 'enim', + 'totam', 'delectus', 'ducimus', 'quis', 'voluptates', 'dolores', + 'molestiae', 'harum', 'dolorem', 'quia', 'voluptatem', 'molestias', + 'magni', 'distinctio', 'omnis', 'illum', 'dolorum', 'voluptatum', 'ea', + 'quas', 'quam', 'corporis', 'quae', 'blanditiis', 'atque', 'deserunt', + 'laboriosam', 'earum', 'consequuntur', 'hic', 'cupiditate', + 'quibusdam', 'accusamus', 'ut', 'rerum', 'error', 'minus', 'eius', + 'ab', 'ad', 'nemo', 'fugit', 'officia', 'at', 'in', 'id', 'quos', + 'reprehenderit', 'numquam', 'iste', 'fugiat', 'sit', 'inventore', + 'beatae', 'repellendus', 'magnam', 'recusandae', 'quod', 'explicabo', + 'doloremque', 'aperiam', 'consequatur', 'asperiores', 'commodi', + 'optio', 'dolor', 'labore', 'temporibus', 'repellat', 'veniam', + 'architecto', 'est', 'esse', 'mollitia', 'nulla', 'a', 'similique', + 'eos', 'alias', 'dolore', 'tenetur', 'deleniti', 'porro', 'facere', + 'maxime', 'corrupti'] + }, + sp: { + common: ['mujer', 'uno', 'dolor', 'más', 'de', 'poder', 'mismo', 'si'], + words: ['ejercicio', 'preferencia', 'perspicacia', 'laboral', 'paño', + 'suntuoso', 'molde', 'namibia', 'planeador', 'mirar', 'demás', 'oficinista', 'excepción', + 'odio', 'consecuencia', 'casi', 'auto', 'chicharra', 'velo', 'elixir', + 'ataque', 'no', 'odio', 'temporal', 'cuórum', 'dignísimo', + 'facilismo', 'letra', 'nihilista', 'expedición', 'alma', 'alveolar', 'aparte', + 'león', 'animal', 'como', 'paria', 'belleza', 'modo', 'natividad', + 'justo', 'ataque', 'séquito', 'pillo', 'sed', 'ex', 'y', 'voluminoso', + 'temporalidad', 'verdades', 'racional', 'asunción', 'incidente', 'marejada', + 'placenta', 'amanecer', 'fuga', 'previsor', 'presentación', 'lejos', + 'necesariamente', 'sospechoso', 'adiposidad', 'quindío', 'pócima', + 'voluble', 'débito', 'sintió', 'accesorio', 'falda', 'sapiencia', + 'volutas', 'queso', 'permacultura', 'laudo', 'soluciones', 'entero', + 'pan', 'litro', 'tonelada', 'culpa', 'libertario', 'mosca', 'dictado', + 'reincidente', 'nascimiento', 'dolor', 'escolar', 'impedimento', 'mínima', + 'mayores', 'repugnante', 'dulce', 'obcecado', 'montaña', 'enigma', + 'total', 'deletéreo', 'décima', 'cábala', 'fotografía', 'dolores', + 'molesto', 'olvido', 'paciencia', 'resiliencia', 'voluntad', 'molestias', + 'magnífico', 'distinción', 'ovni', 'marejada', 'cerro', 'torre', 'y', + 'abogada', 'manantial', 'corporal', 'agua', 'crepúsculo', 'ataque', 'desierto', + 'laboriosamente', 'angustia', 'afortunado', 'alma', 'encefalograma', + 'materialidad', 'cosas', 'o', 'renuncia', 'error', 'menos', 'conejo', + 'abadía', 'analfabeto', 'remo', 'fugacidad', 'oficio', 'en', 'almácigo', 'vos', 'pan', + 'represión', 'números', 'triste', 'refugiado', 'trote', 'inventor', + 'corchea', 'repelente', 'magma', 'recusado', 'patrón', 'explícito', + 'paloma', 'síndrome', 'inmune', 'autoinmune', 'comodidad', + 'ley', 'vietnamita', 'demonio', 'tasmania', 'repeler', 'apéndice', + 'arquitecto', 'columna', 'yugo', 'computador', 'mula', 'a', 'propósito', + 'fantasía', 'alias', 'rayo', 'tenedor', 'deleznable', 'ventana', 'cara', + 'anemia', 'corrupto'] + }, + ru: { + common: ['далеко-далеко', 'за', 'словесными', 'горами', 'в стране', 'гласных', 'и согласных', 'живут', 'рыбные', 'тексты'], + words: ['вдали', 'от всех', 'они', 'буквенных', 'домах', 'на берегу', 'семантика', + 'большого', 'языкового', 'океана', 'маленький', 'ручеек', 'даль', + 'журчит', 'по всей', 'обеспечивает', 'ее','всеми', 'необходимыми', + 'правилами', 'эта', 'парадигматическая', 'страна', 'которой', 'жаренные', + 'предложения', 'залетают', 'прямо', 'рот', 'даже', 'всемогущая', + 'пунктуация', 'не', 'имеет', 'власти', 'над', 'рыбными', 'текстами', + 'ведущими', 'безорфографичный', 'образ', 'жизни', 'однажды', 'одна', + 'маленькая', 'строчка','рыбного', 'текста', 'имени', 'lorem', 'ipsum', + 'решила', 'выйти', 'большой', 'мир', 'грамматики', 'великий', 'оксмокс', + 'предупреждал', 'о', 'злых', 'запятых', 'диких', 'знаках', 'вопроса', + 'коварных', 'точках', 'запятой', 'но', 'текст', 'дал', 'сбить', + 'себя', 'толку', 'он', 'собрал', 'семь', 'своих', 'заглавных', 'букв', + 'подпоясал', 'инициал', 'за', 'пояс', 'пустился', 'дорогу', + 'взобравшись', 'первую', 'вершину', 'курсивных', 'гор', 'бросил', + 'последний', 'взгляд', 'назад', 'силуэт', 'своего', 'родного', 'города', + 'буквоград', 'заголовок', 'деревни', 'алфавит', 'подзаголовок', 'своего', + 'переулка', 'грустный', 'реторический', 'вопрос', 'скатился', 'его', + 'щеке', 'продолжил', 'свой', 'путь', 'дороге', 'встретил', 'рукопись', + 'она', 'предупредила', 'моей', 'все', 'переписывается', 'несколько', + 'раз', 'единственное', 'что', 'меня', 'осталось', 'это', 'приставка', + 'возвращайся', 'ты', 'лучше', 'свою', 'безопасную', 'страну', 'послушавшись', + 'рукописи', 'наш', 'продолжил', 'свой', 'путь', 'вскоре', 'ему', + 'повстречался', 'коварный', 'составитель', 'рекламных', 'текстов', + 'напоивший', 'языком', 'речью', 'заманивший', 'свое', 'агенство', + 'которое', 'использовало', 'снова', 'снова', 'своих', 'проектах', + 'если', 'переписали', 'то', 'живет', 'там', 'до', 'сих', 'пор'] + } + }; + + + prefs.define('lorem.defaultLang', 'en', + 'Default language of generated dummy text. Currently, en\ + and ru are supported, but users can add their own syntaxes\ + see docs.'); + prefs.define('lorem.omitCommonPart', false, + 'Omit commonly used part (e.g. “Lorem ipsum dolor sit amet“) from generated text.'); + + /** + * Returns random integer between from and to values + * @param {Number} from + * @param {Number} to + * @returns {Number} + */ + function randint(from, to) { + return Math.round(Math.random() * (to - from) + from); + } + + /** + * @param {Array} arr + * @param {Number} count + * @returns {Array} + */ + function sample(arr, count) { + var len = arr.length; + var iterations = Math.min(len, count); + var result = []; + while (result.length < iterations) { + var randIx = randint(0, len - 1); + if (!~result.indexOf(randIx)) { + result.push(randIx); + } + } + + return result.map(function(ix) { + return arr[ix]; + }); + } + + function choice(val) { + if (typeof val === 'string') + return val.charAt(randint(0, val.length - 1)); + + return val[randint(0, val.length - 1)]; + } + + function sentence(words, end) { + if (words.length) { + words[0] = words[0].charAt(0).toUpperCase() + words[0].substring(1); + } + + return words.join(' ') + (end || choice('?!...')); // more dots than question marks + } + + /** + * Insert commas at randomly selected words. This function modifies values + * inside words array + * @param {Array} words + */ + function insertCommas(words) { + var len = words.length; + + if (len < 2) { + return; + } + + var totalCommas = 0; + if (len > 3 && len <= 6) { + totalCommas = randint(0, 1); + } else if (len > 6 && len <= 12) { + totalCommas = randint(0, 2); + } else { + totalCommas = randint(1, 4); + } + + for (var i = 0, pos, word; i < totalCommas; i++) { + pos = randint(0, words.length - 2); + word = words[pos]; + if (word.charAt(word.length - 1) !== ',') { + words[pos] += ','; + } + } + } + + /** + * Generate a paragraph of "Lorem ipsum" text + * @param {Number} wordCount Words count in paragraph + * @param {Boolean} startWithCommon Should paragraph start with common + * "lorem ipsum" sentence. + * @returns {String} + */ + function paragraph(lang, wordCount, startWithCommon) { + var data = langs[lang]; + if (!data) { + return ''; + } + + var result = []; + var totalWords = 0; + var words; + + wordCount = parseInt(wordCount, 10); + + if (startWithCommon && data.common) { + words = data.common.slice(0, wordCount); + if (words.length > 5) { + words[4] += ','; + } + totalWords += words.length; + result.push(sentence(words, '.')); + } + + while (totalWords < wordCount) { + words = sample(data.words, Math.min(randint(2, 30), wordCount - totalWords)); + totalWords += words.length; + insertCommas(words); + result.push(sentence(words)); + } + + return result.join(' '); + } + + return { + /** + * Adds new language words for Lorem Ipsum generator + * @param {String} lang Two-letter lang definition + * @param {Object} data Words for language. Maight be either a space-separated + * list of words (String), Array of words or object with text and + * common properties + */ + addLang: function(lang, data) { + if (typeof data === 'string') { + data = { + words: data.split(' ').filter(function(item) { + return !!item; + }) + }; + } else if (Array.isArray(data)) { + data = {words: data}; + } + + langs[lang] = data; + }, + preprocessor: function(tree) { + var re = /^(?:lorem|lipsum)([a-z]{2})?(\d*)$/i, match; + var allowCommon = !prefs.get('lorem.omitCommonPart'); + + /** @param {AbbreviationNode} node */ + tree.findAll(function(node) { + if (node._name && (match = node._name.match(re))) { + var wordCound = match[2] || 30; + var lang = match[1] || prefs.get('lorem.defaultLang') || 'en'; + + // force node name resolving if node should be repeated + // or contains attributes. In this case, node should be outputed + // as tag, otherwise as text-only node + node._name = ''; + node.data('forceNameResolving', node.isRepeating() || node.attributeList().length); + node.data('pasteOverwrites', true); + node.data('paste', function(i) { + return paragraph(lang, wordCound, !i && allowCommon); + }); + } + }); + } + }; +}); + +},{"../assets/preferences":"assets/preferences.js"}],"parser/abbreviation.js":[function(require,module,exports){ +/** + * Emmet abbreviation parser. + * Takes string abbreviation and recursively parses it into a tree. The parsed + * tree can be transformed into a string representation with + * toString() method. Note that string representation is defined + * by custom processors (called filters), not by abbreviation parser + * itself. + * + * This module can be extended with custom pre-/post-processors to shape-up + * final tree or its representation. Actually, many features of abbreviation + * engine are defined in other modules as tree processors + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var tabStops = require('../assets/tabStops'); + var profile = require('../assets/profile'); + var filters = require('../filter/main'); + var utils = require('../utils/common'); + var abbreviationUtils = require('../utils/abbreviation'); + var stringStream = require('../assets/stringStream'); + + // pre- and post-processorcs + var lorem = require('../generator/lorem'); + var procPastedContent = require('./processor/pastedContent'); + var procTagName = require('./processor/tagName'); + var procResourceMatcher = require('./processor/resourceMatcher'); + var procAttributes = require('./processor/attributes'); + var procHref = require('./processor/href'); + + var reValidName = /^[\w\-\$\:@\!%]+\+?$/i; + var reWord = /[\w\-:\$@]/; + var DEFAULT_ATTR_NAME = '%default'; + + var pairs = { + '[': ']', + '(': ')', + '{': '}' + }; + + var spliceFn = Array.prototype.splice; + + var preprocessors = []; + var postprocessors = []; + var outputProcessors = []; + + /** + * @type AbbreviationNode + */ + function AbbreviationNode(parent) { + /** @type AbbreviationNode */ + this.parent = null; + this.children = []; + this._attributes = []; + + /** @type String Raw abbreviation for current node */ + this.abbreviation = ''; + this.counter = 1; + this._name = null; + this._text = ''; + this.repeatCount = 1; + this.hasImplicitRepeat = false; + + /** Custom data dictionary */ + this._data = {}; + + // output properties + this.start = ''; + this.end = ''; + this.content = ''; + this.padding = ''; + } + + AbbreviationNode.prototype = { + /** + * Adds passed node as child or creates new child + * @param {AbbreviationNode} child + * @param {Number} position Index in children array where child should + * be inserted + * @return {AbbreviationNode} + */ + addChild: function(child, position) { + child = child || new AbbreviationNode(); + child.parent = this; + + if (typeof position === 'undefined') { + this.children.push(child); + } else { + this.children.splice(position, 0, child); + } + + return child; + }, + + /** + * Creates a deep copy of current node + * @returns {AbbreviationNode} + */ + clone: function() { + var node = new AbbreviationNode(); + var attrs = ['abbreviation', 'counter', '_name', '_text', 'repeatCount', 'hasImplicitRepeat', 'start', 'end', 'content', 'padding']; + attrs.forEach(function(a) { + node[a] = this[a]; + }, this); + + // clone attributes + node._attributes = this._attributes.map(function(attr) { + return utils.extend({}, attr); + }); + + node._data = utils.extend({}, this._data); + + // clone children + node.children = this.children.map(function(child) { + child = child.clone(); + child.parent = node; + return child; + }); + + return node; + }, + + /** + * Removes current node from parent‘s child list + * @returns {AbbreviationNode} Current node itself + */ + remove: function() { + if (this.parent) { + var ix = this.parent.children.indexOf(this); + if (~ix) { + this.parent.children.splice(ix, 1); + } + } + + return this; + }, + + /** + * Replaces current node in parent‘s children list with passed nodes + * @param {AbbreviationNode} node Replacement node or array of nodes + */ + replace: function() { + var parent = this.parent; + var ix = parent.children.indexOf(this); + var items = utils.flatten(arguments); + spliceFn.apply(parent.children, [ix, 1].concat(items)); + + // update parent + items.forEach(function(item) { + item.parent = parent; + }); + }, + + /** + * Recursively sets property to value of current + * node and its children + * @param {String} name Property to update + * @param {Object} value New property value + */ + updateProperty: function(name, value) { + this[name] = value; + this.children.forEach(function(child) { + child.updateProperty(name, value); + }); + + return this; + }, + + /** + * Finds first child node that matches truth test for passed + * fn function + * @param {Function} fn + * @returns {AbbreviationNode} + */ + find: function(fn) { + return this.findAll(fn, {amount: 1})[0]; + }, + + /** + * Finds all child nodes that matches truth test for passed + * fn function + * @param {Function} fn + * @returns {Array} + */ + findAll: function(fn, state) { + state = utils.extend({amount: 0, found: 0}, state || {}); + + if (typeof fn !== 'function') { + var elemName = fn.toLowerCase(); + fn = function(item) {return item.name().toLowerCase() == elemName;}; + } + + var result = []; + this.children.forEach(function(child) { + if (fn(child)) { + result.push(child); + state.found++; + if (state.amount && state.found >= state.amount) { + return; + } + } + + result = result.concat(child.findAll(fn)); + }); + + return result.filter(function(item) { + return !!item; + }); + }, + + /** + * Sets/gets custom data + * @param {String} name + * @param {Object} value + * @returns {Object} + */ + data: function(name, value) { + if (arguments.length == 2) { + this._data[name] = value; + } + + return this._data[name]; + }, + + /** + * Returns name of current node + * @returns {String} + */ + name: function() { + return this._name; + }, + + /** + * Returns list of attributes for current node + * @returns {Array} + */ + attributeList: function() { + return optimizeAttributes(this._attributes.slice(0)); + }, + + /** + * Returns or sets attribute value + * @param {String} name Attribute name + * @param {String} value New attribute value. `Null` value + * will remove attribute + * @returns {String} + */ + attribute: function(name, value) { + if (arguments.length == 2) { + if (value === null) { + // remove attribute + var vals = this._attributes.filter(function(attr) { + return attr.name === name; + }); + + var that = this; + vals.forEach(function(attr) { + var ix = that._attributes.indexOf(attr); + if (~ix) { + that._attributes.splice(ix, 1); + } + }); + + return; + } + + // modify attribute + var attrNames = this._attributes.map(function(attr) { + return attr.name; + }); + var ix = attrNames.indexOf(name.toLowerCase()); + if (~ix) { + this._attributes[ix].value = value; + } else { + this._attributes.push({ + name: name, + value: value + }); + } + } + + return (utils.find(this.attributeList(), function(attr) { + return attr.name == name; + }) || {}).value; + }, + + /** + * Returns index of current node in parent‘s children list + * @returns {Number} + */ + index: function() { + return this.parent ? this.parent.children.indexOf(this) : -1; + }, + + /** + * Sets how many times current element should be repeated + * @private + */ + _setRepeat: function(count) { + if (count) { + this.repeatCount = parseInt(count, 10) || 1; + } else { + this.hasImplicitRepeat = true; + } + }, + + /** + * Sets abbreviation that belongs to current node + * @param {String} abbr + */ + setAbbreviation: function(abbr) { + abbr = abbr || ''; + + var that = this; + + // find multiplier + abbr = abbr.replace(/\*(\d+)?$/, function(str, repeatCount) { + that._setRepeat(repeatCount); + return ''; + }); + + this.abbreviation = abbr; + + var abbrText = extractText(abbr); + if (abbrText) { + abbr = abbrText.element; + this.content = this._text = abbrText.text; + } + + var abbrAttrs = parseAttributes(abbr); + if (abbrAttrs) { + abbr = abbrAttrs.element; + this._attributes = abbrAttrs.attributes; + } + + this._name = abbr; + + // validate name + if (this._name && !reValidName.test(this._name)) { + throw new Error('Invalid abbreviation'); + } + }, + + /** + * Returns string representation of current node + * @return {String} + */ + valueOf: function() { + var start = this.start; + var end = this.end; + var content = this.content; + + // apply output processors + var node = this; + outputProcessors.forEach(function(fn) { + start = fn(start, node, 'start'); + content = fn(content, node, 'content'); + end = fn(end, node, 'end'); + }); + + + var innerContent = this.children.map(function(child) { + return child.valueOf(); + }).join(''); + + content = abbreviationUtils.insertChildContent(content, innerContent, { + keepVariable: false + }); + + return start + utils.padString(content, this.padding) + end; + }, + + toString: function() { + return this.valueOf(); + }, + + /** + * Check if current node contains children with empty expr + * property + * @return {Boolean} + */ + hasEmptyChildren: function() { + return !!utils.find(this.children, function(child) { + return child.isEmpty(); + }); + }, + + /** + * Check if current node has implied name that should be resolved + * @returns {Boolean} + */ + hasImplicitName: function() { + return !this._name && !this.isTextNode(); + }, + + /** + * Indicates that current element is a grouping one, e.g. has no + * representation but serves as a container for other nodes + * @returns {Boolean} + */ + isGroup: function() { + return !this.abbreviation; + }, + + /** + * Indicates empty node (i.e. without abbreviation). It may be a + * grouping node and should not be outputted + * @return {Boolean} + */ + isEmpty: function() { + return !this.abbreviation && !this.children.length; + }, + + /** + * Indicates that current node should be repeated + * @returns {Boolean} + */ + isRepeating: function() { + return this.repeatCount > 1 || this.hasImplicitRepeat; + }, + + /** + * Check if current node is a text-only node + * @return {Boolean} + */ + isTextNode: function() { + return !this.name() && !this.attributeList().length; + }, + + /** + * Indicates whether this node may be used to build elements or snippets + * @returns {Boolean} + */ + isElement: function() { + return !this.isEmpty() && !this.isTextNode(); + }, + + /** + * Returns latest and deepest child of current tree + * @returns {AbbreviationNode} + */ + deepestChild: function() { + if (!this.children.length) + return null; + + var deepestChild = this; + while (deepestChild.children.length) { + deepestChild = deepestChild.children[deepestChild.children.length - 1]; + } + + return deepestChild; + } + }; + + /** + * Returns stripped string: a string without first and last character. + * Used for “unquoting” strings + * @param {String} str + * @returns {String} + */ + function stripped(str) { + return str.substring(1, str.length - 1); + } + + function consumeQuotedValue(stream, quote) { + var ch; + while ((ch = stream.next())) { + if (ch === quote) + return true; + + if (ch == '\\') + continue; + } + + return false; + } + + /** + * Parses abbreviation into a tree + * @param {String} abbr + * @returns {AbbreviationNode} + */ + function parseAbbreviation(abbr) { + abbr = utils.trim(abbr); + + var root = new AbbreviationNode(); + var context = root.addChild(), ch; + + /** @type StringStream */ + var stream = stringStream.create(abbr); + var loopProtector = 1000, multiplier; + var addChild = function(child) { + context.addChild(child); + }; + + var consumeAbbr = function() { + stream.start = stream.pos; + stream.eatWhile(function(c) { + if (c == '[' || c == '{') { + if (stream.skipToPair(c, pairs[c])) { + stream.backUp(1); + return true; + } + + throw new Error('Invalid abbreviation: mo matching "' + pairs[c] + '" found for character at ' + stream.pos); + } + + if (c == '+') { + // let's see if this is an expando marker + stream.next(); + var isMarker = stream.eol() || ~'+>^*'.indexOf(stream.peek()); + stream.backUp(1); + return isMarker; + } + + return c != '(' && isAllowedChar(c); + }); + }; + + while (!stream.eol() && --loopProtector > 0) { + ch = stream.peek(); + + switch (ch) { + case '(': // abbreviation group + stream.start = stream.pos; + if (stream.skipToPair('(', ')')) { + var inner = parseAbbreviation(stripped(stream.current())); + if ((multiplier = stream.match(/^\*(\d+)?/, true))) { + context._setRepeat(multiplier[1]); + } + + inner.children.forEach(addChild); + } else { + throw new Error('Invalid abbreviation: mo matching ")" found for character at ' + stream.pos); + } + break; + + case '>': // child operator + context = context.addChild(); + stream.next(); + break; + + case '+': // sibling operator + context = context.parent.addChild(); + stream.next(); + break; + + case '^': // climb up operator + var parent = context.parent || context; + context = (parent.parent || parent).addChild(); + stream.next(); + break; + + default: // consume abbreviation + consumeAbbr(); + context.setAbbreviation(stream.current()); + stream.start = stream.pos; + } + } + + if (loopProtector < 1) { + throw new Error('Endless loop detected'); + } + + return root; + } + + /** + * Splits attribute set into a list of attributes string + * @param {String} attrSet + * @return {Array} + */ + function splitAttributes(attrSet) { + attrSet = utils.trim(attrSet); + var parts = []; + + // split attribute set by spaces + var stream = stringStream(attrSet), ch; + while ((ch = stream.next())) { + if (ch == ' ') { + parts.push(utils.trim(stream.current())); + // skip spaces + while (stream.peek() == ' ') { + stream.next(); + } + + stream.start = stream.pos; + } else if (ch == '"' || ch == "'") { + // skip values in strings + if (!stream.skipString(ch)) { + throw new Error('Invalid attribute set'); + } + } + } + + parts.push(utils.trim(stream.current())); + return parts; + } + + /** + * Removes opening and closing quotes from given string + * @param {String} str + * @return {String} + */ + function unquote(str) { + var ch = str.charAt(0); + if (ch == '"' || ch == "'") { + str = str.substr(1); + var last = str.charAt(str.length - 1); + if (last === ch) { + str = str.substr(0, str.length - 1); + } + } + + return str; + } + + /** + * Extract attributes and their values from attribute set: + * [attr col=3 title="Quoted string"] (without square braces) + * @param {String} attrSet + * @returns {Array} + */ + function extractAttributes(attrSet) { + var reAttrName = /^[\w\-:\$@]+\.?$/; + return splitAttributes(attrSet).map(function(attr) { + // attribute name: [attr] + if (reAttrName.test(attr)) { + var value = ''; + if (attr.charAt(attr.length - 1) == '.') { + // a boolean attribute + attr = attr.substr(0, attr.length - 1); + value = attr; + } + return { + name: attr, + value: value + }; + } + + // attribute with value: [name=val], [name="val"] + if (~attr.indexOf('=')) { + var parts = attr.split('='); + return { + name: parts.shift(), + value: unquote(parts.join('=')) + }; + } + + // looks like it’s implied attribute + return { + name: DEFAULT_ATTR_NAME, + value: unquote(attr) + }; + }); + } + + /** + * Parses tag attributes extracted from abbreviation. If attributes found, + * returns object with element and attributes + * properties + * @param {String} abbr + * @returns {Object} Returns null if no attributes found in + * abbreviation + */ + function parseAttributes(abbr) { + /* + * Example of incoming data: + * #header + * .some.data + * .some.data#header + * [attr] + * #item[attr=Hello other="World"].class + */ + var result = []; + var attrMap = {'#': 'id', '.': 'class'}; + var nameEnd = null; + + /** @type StringStream */ + var stream = stringStream.create(abbr); + while (!stream.eol()) { + switch (stream.peek()) { + case '#': // id + case '.': // class + if (nameEnd === null) + nameEnd = stream.pos; + + var attrName = attrMap[stream.peek()]; + + stream.next(); + stream.start = stream.pos; + stream.eatWhile(reWord); + result.push({ + name: attrName, + value: stream.current() + }); + break; + case '[': //begin attribute set + if (nameEnd === null) + nameEnd = stream.pos; + + stream.start = stream.pos; + if (!stream.skipToPair('[', ']')) { + throw new Error('Invalid attribute set definition'); + } + + result = result.concat( + extractAttributes(stripped(stream.current())) + ); + break; + default: + stream.next(); + } + } + + if (!result.length) + return null; + + return { + element: abbr.substring(0, nameEnd), + attributes: optimizeAttributes(result) + }; + } + + /** + * Optimize attribute set: remove duplicates and merge class attributes + * @param attrs + */ + function optimizeAttributes(attrs) { + // clone all attributes to make sure that original objects are + // not modified + attrs = attrs.map(function(attr) { + return utils.clone(attr); + }); + + var lookup = {}; + + return attrs.filter(function(attr) { + if (!(attr.name in lookup)) { + return lookup[attr.name] = attr; + } + + var la = lookup[attr.name]; + + if (attr.name.toLowerCase() == 'class') { + la.value += (la.value.length ? ' ' : '') + attr.value; + } else { + la.value = attr.value; + la.isImplied = !!attr.isImplied; + } + + return false; + }); + } + + /** + * Extract text data from abbreviation: if a{hello} abbreviation + * is passed, returns object {element: 'a', text: 'hello'}. + * If nothing found, returns null + * @param {String} abbr + * + */ + function extractText(abbr) { + if (!~abbr.indexOf('{')) + return null; + + /** @type StringStream */ + var stream = stringStream.create(abbr); + while (!stream.eol()) { + switch (stream.peek()) { + case '[': + case '(': + stream.skipToPair(stream.peek(), pairs[stream.peek()]); break; + + case '{': + stream.start = stream.pos; + stream.skipToPair('{', '}'); + return { + element: abbr.substring(0, stream.start), + text: stripped(stream.current()) + }; + + default: + stream.next(); + } + } + } + + /** + * “Un-rolls“ contents of current node: recursively replaces all repeating + * children with their repeated clones + * @param {AbbreviationNode} node + * @returns {AbbreviationNode} + */ + function unroll(node) { + for (var i = node.children.length - 1, j, child, maxCount; i >= 0; i--) { + child = node.children[i]; + + if (child.isRepeating()) { + maxCount = j = child.repeatCount; + child.repeatCount = 1; + child.updateProperty('counter', 1); + child.updateProperty('maxCount', maxCount); + while (--j > 0) { + child.parent.addChild(child.clone(), i + 1) + .updateProperty('counter', j + 1) + .updateProperty('maxCount', maxCount); + } + } + } + + // to keep proper 'counter' property, we need to walk + // on children once again + node.children.forEach(unroll); + + return node; + } + + /** + * Optimizes tree node: replaces empty nodes with their children + * @param {AbbreviationNode} node + * @return {AbbreviationNode} + */ + function squash(node) { + for (var i = node.children.length - 1; i >= 0; i--) { + /** @type AbbreviationNode */ + var n = node.children[i]; + if (n.isGroup()) { + n.replace(squash(n).children); + } else if (n.isEmpty()) { + n.remove(); + } + } + + node.children.forEach(squash); + + return node; + } + + function isAllowedChar(ch) { + var charCode = ch.charCodeAt(0); + var specialChars = '#.*:$-_!@|%'; + + return (charCode > 64 && charCode < 91) // uppercase letter + || (charCode > 96 && charCode < 123) // lowercase letter + || (charCode > 47 && charCode < 58) // number + || specialChars.indexOf(ch) != -1; // special character + } + + // XXX add counter replacer function as output processor + outputProcessors.push(function(text, node) { + return utils.replaceCounter(text, node.counter, node.maxCount); + }); + + // XXX add tabstop updater + outputProcessors.push(tabStops.abbrOutputProcessor.bind(tabStops)); + + // include default pre- and postprocessors + [lorem, procResourceMatcher, procAttributes, procPastedContent, procTagName, procHref].forEach(function(mod) { + if (mod.preprocessor) { + preprocessors.push(mod.preprocessor.bind(mod)); + } + + if (mod.postprocessor) { + postprocessors.push(mod.postprocessor.bind(mod)); + } + }); + + return { + DEFAULT_ATTR_NAME: DEFAULT_ATTR_NAME, + + /** + * Parses abbreviation into tree with respect of groups, + * text nodes and attributes. Each node of the tree is a single + * abbreviation. Tree represents actual structure of the outputted + * result + * @memberOf abbreviationParser + * @param {String} abbr Abbreviation to parse + * @param {Object} options Additional options for parser and processors + * + * @return {AbbreviationNode} + */ + parse: function(abbr, options) { + options = options || {}; + + var tree = parseAbbreviation(abbr); + var that = this; + + if (options.contextNode) { + // add info about context node – + // a parent XHTML node in editor inside which abbreviation is + // expanded + tree._name = options.contextNode.name; + var attrLookup = {}; + tree._attributes.forEach(function(attr) { + attrLookup[attr.name] = attr; + }); + + options.contextNode.attributes.forEach(function(attr) { + if (attr.name in attrLookup) { + attrLookup[attr.name].value = attr.value; + } else { + attr = utils.clone(attr); + tree._attributes.push(attr); + attrLookup[attr.name] = attr; + } + }); + } + + // apply preprocessors + preprocessors.forEach(function(fn) { + fn(tree, options, that); + }); + + if ('counter' in options) { + tree.updateProperty('counter', options.counter); + } + + tree = squash(unroll(tree)); + + // apply postprocessors + postprocessors.forEach(function(fn) { + fn(tree, options, that); + }); + + return tree; + }, + + /** + * Expands given abbreviation into a formatted code structure. + * This is the main method that is used for expanding abbreviation + * @param {String} abbr Abbreviation to expand + * @param {Options} options Additional options for abbreviation + * expanding and transformation: `syntax`, `profile`, `contextNode` etc. + * @return {String} + */ + expand: function(abbr, options) { + if (!abbr) return ''; + if (typeof options == 'string') { + throw new Error('Deprecated use of `expand` method: `options` must be object'); + } + + options = options || {}; + + if (!options.syntax) { + options.syntax = utils.defaultSyntax(); + } + + var p = profile.get(options.profile, options.syntax); + tabStops.resetTabstopIndex(); + + var data = filters.extract(abbr); + var outputTree = this.parse(data[0], options); + + var filtersList = filters.composeList(options.syntax, p, data[1]); + filters.apply(outputTree, filtersList, p); + + return outputTree.valueOf(); + }, + + AbbreviationNode: AbbreviationNode, + + /** + * Add new abbreviation preprocessor. Preprocessor is a function + * that applies to a parsed abbreviation tree right after it get parsed. + * The passed tree is in unoptimized state. + * @param {Function} fn Preprocessor function. This function receives + * two arguments: parsed abbreviation tree (AbbreviationNode) + * and options hash that was passed to parse + * method + */ + addPreprocessor: function(fn) { + if (!~preprocessors.indexOf(fn)) { + preprocessors.push(fn); + } + }, + + /** + * Removes registered preprocessor + */ + removeFilter: function(fn) { + var ix = preprocessors.indexOf(fn); + if (~ix) { + preprocessors.splice(ix, 1); + } + }, + + /** + * Adds new abbreviation postprocessor. Postprocessor is a + * functinon that applies to optimized parsed abbreviation tree + * right before it returns from parse() method + * @param {Function} fn Postprocessor function. This function receives + * two arguments: parsed abbreviation tree (AbbreviationNode) + * and options hash that was passed to parse + * method + */ + addPostprocessor: function(fn) { + if (!~postprocessors.indexOf(fn)) { + postprocessors.push(fn); + } + }, + + /** + * Removes registered postprocessor function + */ + removePostprocessor: function(fn) { + var ix = postprocessors.indexOf(fn); + if (~ix) { + postprocessors.splice(ix, 1); + } + }, + + /** + * Registers output postprocessor. Output processor is a + * function that applies to output part (start, + * end and content) when + * AbbreviationNode.toString() method is called + */ + addOutputProcessor: function(fn) { + if (!~outputProcessors.indexOf(fn)) { + outputProcessors.push(fn); + } + }, + + /** + * Removes registered output processor + */ + removeOutputProcessor: function(fn) { + var ix = outputProcessors.indexOf(fn); + if (~ix) { + outputProcessors.splice(ix, 1); + } + }, + + /** + * Check if passed symbol is valid symbol for abbreviation expression + * @param {String} ch + * @return {Boolean} + */ + isAllowedChar: function(ch) { + ch = String(ch); // convert Java object to JS + return isAllowedChar(ch) || ~'>+^[](){}'.indexOf(ch); + } + }; +}); +},{"../assets/profile":"assets/profile.js","../assets/stringStream":"assets/stringStream.js","../assets/tabStops":"assets/tabStops.js","../filter/main":"filter/main.js","../generator/lorem":"generator/lorem.js","../utils/abbreviation":"utils/abbreviation.js","../utils/common":"utils/common.js","./processor/attributes":"parser/processor/attributes.js","./processor/href":"parser/processor/href.js","./processor/pastedContent":"parser/processor/pastedContent.js","./processor/resourceMatcher":"parser/processor/resourceMatcher.js","./processor/tagName":"parser/processor/tagName.js"}],"parser/css.js":[function(require,module,exports){ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var session = {tokens: null}; + + // walks around the source + var walker = { + init: function (source) { + // this.source = source.replace(/\r\n?/g, '\n'); + this.source = source; + this.ch = ''; + this.chnum = -1; + + // advance + this.nextChar(); + }, + nextChar: function () { + return this.ch = this.source.charAt(++this.chnum); + }, + peek: function() { + return this.source.charAt(this.chnum + 1); + } + }; + + // utility helpers + function isNameChar(c, cc) { + cc = cc || c.charCodeAt(0); + return ( + (cc >= 97 && cc <= 122 /* a-z */) || + (cc >= 65 && cc <= 90 /* A-Z */) || + /* + Experimental: include cyrillic ranges + since some letters, similar to latin ones, can + accidentally appear in CSS tokens + */ + (cc >= 1024 && cc <= 1279) || + c === '&' || /* selector placeholder (LESS, SCSS) */ + c === '_' || + c === '<' || /* comparisons (LESS, SCSS) */ + c === '>' || + c === '=' || + c === '-' + ); + } + + function isDigit(c, cc) { + cc = cc || c.charCodeAt(0); + return (cc >= 48 && cc <= 57); + } + + var isOp = (function () { + var opsa = "{}[]()+*=.,;:>~|\\%$#@^!".split(''), + opsmatcha = "*^|$~".split(''), + ops = {}, + opsmatch = {}, + i = 0; + for (; i < opsa.length; i += 1) { + ops[opsa[i]] = true; + } + for (i = 0; i < opsmatcha.length; i += 1) { + opsmatch[opsmatcha[i]] = true; + } + return function (ch, matchattr) { + if (matchattr) { + return ch in opsmatch; + } + return ch in ops; + }; + }()); + + // creates token objects and pushes them to a list + function tokener(value, type) { + session.tokens.push({ + value: value, + type: type || value, + start: null, + end: null + }); + } + + function getPosInfo(w) { + var errPos = w.chnum; + var source = w.source.replace(/\r\n?/g, '\n'); + var part = w.source.substring(0, errPos + 1).replace(/\r\n?/g, '\n'); + var lines = part.split('\n'); + var ch = (lines[lines.length - 1] || '').length; + var fullLine = source.split('\n')[lines.length - 1] || ''; + + var chunkSize = 100; + var offset = Math.max(0, ch - chunkSize); + var formattedLine = fullLine.substr(offset, chunkSize * 2) + '\n'; + for (var i = 0; i < ch - offset - 1; i++) { + formattedLine += '-'; + } + formattedLine += '^'; + + return { + line: lines.length, + ch: ch, + text: fullLine, + hint: formattedLine + }; + } + + function raiseError(message) { + var err = error(message); + var errObj = new Error(err.message, '', err.line); + errObj.line = err.line; + errObj.ch = err.ch; + errObj.name = err.name; + errObj.hint = err.hint; + + throw errObj; + } + + // oops + function error(m) { + var w = walker; + var info = getPosInfo(walker); + var tokens = session.tokens; + session.tokens = null; + + var message = 'CSS parsing error at line ' + info.line + ', char ' + info.ch + ': ' + m; + message += '\n' + info.hint; + return { + name: "ParseError", + message: message, + hint: info.hint, + line: info.line, + ch: info.ch + }; + } + + + // token handlers follow for: + // white space, comment, string, identifier, number, operator + function white() { + var c = walker.ch, + token = ''; + + while (c === " " || c === "\t") { + token += c; + c = walker.nextChar(); + } + + tokener(token, 'white'); + + } + + function comment() { + var w = walker, + c = w.ch, + token = c, + cnext; + + cnext = w.nextChar(); + + if (cnext === '/') { + // inline comment in SCSS and LESS + while (c && !(cnext === "\n" || cnext === "\r")) { + token += cnext; + c = cnext; + cnext = w.nextChar(); + } + } else if (cnext === '*') { + // multiline CSS commment + while (c && !(c === "*" && cnext === "/")) { + token += cnext; + c = cnext; + cnext = w.nextChar(); + } + } else { + // oops, not a comment, just a / + return tokener(token, token); + } + + token += cnext; + w.nextChar(); + tokener(token, 'comment'); + } + + function eatString() { + var w = walker, + c = w.ch, + q = c, + token = c, + cnext; + + c = w.nextChar(); + + while (c !== q) { + if (c === '\n') { + cnext = w.nextChar(); + if (cnext === "\\") { + token += c + cnext; + } else { + // end of line with no \ escape = bad + raiseError("Unterminated string"); + } + } else { + if (c === "\\") { + token += c + w.nextChar(); + } else { + token += c; + } + } + + c = w.nextChar(); + } + + token += c; + + return token; + } + + function str() { + var token = eatString(); + walker.nextChar(); + tokener(token, 'string'); + } + + function brace() { + var w = walker, + c = w.ch, + depth = 1, + token = c, + stop = false; + + c = w.nextChar(); + + while (c && !stop) { + if (c === '(') { + depth++; + } else if (c === ')') { + depth--; + if (!depth) { + stop = true; + } + } else if (c === '"' || c === "'") { + c = eatString(); + } else if (c === '') { + raiseError("Unterminated brace"); + } + + token += c; + c = w.nextChar(); + } + + tokener(token, 'brace'); + } + + function identifier(pre) { + var c = walker.ch; + var token = pre ? pre + c : c; + + c = walker.nextChar(); + var cc = c.charCodeAt(0); + while (isNameChar(c, cc) || isDigit(c, cc)) { + token += c; + c = walker.nextChar(); + cc = c.charCodeAt(0); + } + + tokener(token, 'identifier'); + } + + function num() { + var w = walker, + c = w.ch, + token = c, + point = token === '.', + nondigit; + + c = w.nextChar(); + nondigit = !isDigit(c); + + // .2px or .classname? + if (point && nondigit) { + // meh, NaN, could be a class name, so it's an operator for now + return tokener(token, '.'); + } + + // -2px or -moz-something + if (token === '-' && nondigit) { + return identifier('-'); + } + + while (c !== '' && (isDigit(c) || (!point && c === '.'))) { // not end of source && digit or first instance of . + if (c === '.') { + point = true; + } + token += c; + c = w.nextChar(); + } + + tokener(token, 'number'); + + } + + function op() { + var w = walker, + c = w.ch, + token = c, + next = w.nextChar(); + + if (next === "=" && isOp(token, true)) { + token += next; + tokener(token, 'match'); + w.nextChar(); + return; + } + + tokener(token, token); + } + + + // call the appropriate handler based on the first character in a token suspect + function tokenize() { + var ch = walker.ch; + + if (ch === " " || ch === "\t") { + return white(); + } + + if (ch === '/') { + return comment(); + } + + if (ch === '"' || ch === "'") { + return str(); + } + + if (ch === '(') { + return brace(); + } + + if (ch === '-' || ch === '.' || isDigit(ch)) { // tricky - char: minus (-1px) or dash (-moz-stuff) + return num(); + } + + if (isNameChar(ch)) { + return identifier(); + } + + if (isOp(ch)) { + return op(); + } + + if (ch === '\r') { + if (walker.peek() === '\n') { + ch += walker.nextChar(); + } + + tokener(ch, 'line'); + walker.nextChar(); + return; + } + + if (ch === '\n') { + tokener(ch, 'line'); + walker.nextChar(); + return; + } + + raiseError("Unrecognized character '" + ch + "'"); + } + + return { + /** + * Sprits given source into tokens + * @param {String} source + * @returns {Array} + */ + lex: function (source) { + walker.init(source); + session.tokens = []; + + // for empty source, return single space token + if (!source) { + session.tokens.push(this.white()); + } else { + while (walker.ch !== '') { + tokenize(); + } + } + + var tokens = session.tokens; + session.tokens = null; + return tokens; + }, + + /** + * Tokenizes CSS source. It's like `lex()` method, + * but also stores proper token indexes in source, + * so it's a bit slower + * @param {String} source + * @returns {Array} + */ + parse: function(source) { + // transform tokens + var tokens = this.lex(source), pos = 0, token; + for (var i = 0, il = tokens.length; i < il; i++) { + token = tokens[i]; + token.start = pos; + token.end = (pos += token.value.length); + } + return tokens; + }, + + white: function() { + return { + value: '', + type: 'white', + start: 0, + end: 0 + }; + }, + + toSource: function(toks) { + var i = 0, max = toks.length, src = ''; + for (; i < max; i++) { + src += toks[i].value; + } + return src; + } + }; +}); +},{}],"parser/processor/attributes.js":[function(require,module,exports){ +/** + * Resolves node attribute names: moves `default` attribute value + * from stub to real attribute. + * + * This resolver should be applied *after* resource matcher + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../../utils/common'); + + var findDefault = function(attr) { + return attr.isDefault; + }; + + var findImplied = function(attr) { + return attr.isImplied; + }; + + var findEmpty = function(attr) { + return !attr.value; + }; + + function resolveDefaultAttrs(node, parser) { + node.children.forEach(function(item) { + var attrList = item.attributeList(); + var defaultAttrValue = item.attribute(parser.DEFAULT_ATTR_NAME); + if (typeof defaultAttrValue !== 'undefined') { + // remove stub attribute + item.attribute(parser.DEFAULT_ATTR_NAME, null); + + if (attrList.length) { + // target for default value: + // 1. default attribute + // 2. implied attribute + // 3. first empty attribute + + // find attribute marked as default + var defaultAttr = utils.find(attrList, findDefault) + || utils.find(attrList, findImplied) + || utils.find(attrList, findEmpty); + + if (defaultAttr) { + var oldVal = item.attribute(defaultAttr.name); + var newVal = utils.replaceUnescapedSymbol(oldVal, '|', defaultAttrValue); + // no replacement, e.g. default value does not contains | symbol + if (oldVal == newVal) { + newVal = defaultAttrValue + } + + item.attribute(defaultAttr.name, newVal); + } + } + } else { + // if no default attribute value, remove implied attributes + attrList.forEach(function(attr) { + if (attr.isImplied) { + item.attribute(attr.name, null); + } + }); + } + + resolveDefaultAttrs(item, parser); + }); + } + + return { + /** + * @param {AbbreviationNode} tree + * @param {Object} options + * @param {abbreviation} parser + */ + preprocessor: function(tree, options, parser) { + resolveDefaultAttrs(tree, parser); + } + }; +}); +},{"../../utils/common":"utils/common.js"}],"parser/processor/href.js":[function(require,module,exports){ +/** + * A preptocessor for <a> tag: tests wrapped content + * for common URL patterns and, if matched, inserts it as + * `href` attribute + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../../assets/preferences'); + var utils = require('../../utils/common'); + var pc = require('./pastedContent'); + + prefs.define('href.autodetect', true, + 'Enables or disables automatic URL recognition when wrapping\ + text with <a> tag. With this option enabled,\ + if wrapped text matches URL or e-mail pattern it will be automatically\ + inserted into href attribute.'); + prefs.define('href.urlPattern', '^(?:(?:https?|ftp|file)://|www\\.|ftp\\.)(?:\\([-A-Z0-9+&@#/%=~_|$?!:,.]*\\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\\([-A-Z0-9+&@#/%=~_|$?!:,.]*\\)|[A-Z0-9+&@#/%=~_|$])', + 'RegExp pattern to match wrapped URLs. Matched content will be inserts\ + as-is into href attribute, only whitespace will be trimmed.'); + + prefs.define('href.emailPattern', '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,5}$', + 'RegExp pattern to match wrapped e-mails. Unlike href.urlPattern,\ + wrapped content will be prefixed with mailto: in href\ + attribute'); + + return { + /** + * @param {AbbreviationNode} tree + * @param {Object} options + */ + postprocessor: function(tree, options) { + if (!prefs.get('href.autodetect')) { + return; + } + + var reUrl = new RegExp(prefs.get('href.urlPattern'), 'i'); + var reEmail = new RegExp(prefs.get('href.emailPattern'), 'i'); + var reProto = /^([a-z]+:)?\/\//i; + + tree.findAll(function(item) { + if (item.name().toLowerCase() != 'a' || item.attribute('href')) { + return; + } + + var pastedContent = utils.trim(pc.pastedContent(item) || options.pastedContent); + if (pastedContent) { + if (reUrl.test(pastedContent)) { + // do we have protocol? + if (!reProto.test(pastedContent)) { + pastedContent = 'http://' + pastedContent; + } + + item.attribute('href', pastedContent); + } else if (reEmail.test(pastedContent)) { + item.attribute('href', 'mailto:' + pastedContent); + } + } + }); + } + }; +}); +},{"../../assets/preferences":"assets/preferences.js","../../utils/common":"utils/common.js","./pastedContent":"parser/processor/pastedContent.js"}],"parser/processor/pastedContent.js":[function(require,module,exports){ +/** + * Pasted content abbreviation processor. A pasted content is a content that + * should be inserted into implicitly repeated abbreviation nodes. + * This processor powers “Wrap With Abbreviation” action + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../../utils/common'); + var abbrUtils = require('../../utils/abbreviation'); + var stringStream = require('../../assets/stringStream'); + var range = require('../../assets/range'); + + var outputPlaceholder = '$#'; + + /** + * Locates output placeholders inside text + * @param {String} text + * @returns {Array} Array of ranges of output placeholder in text + */ + function locateOutputPlaceholder(text) { + var result = []; + + var stream = stringStream.create(text); + + while (!stream.eol()) { + if (stream.peek() == '\\') { + stream.next(); + } else { + stream.start = stream.pos; + if (stream.match(outputPlaceholder, true)) { + result.push(range.create(stream.start, outputPlaceholder)); + continue; + } + } + stream.next(); + } + + return result; + } + + /** + * Replaces output placeholders inside source with + * value + * @param {String} source + * @param {String} value + * @returns {String} + */ + function replaceOutputPlaceholders(source, value) { + var ranges = locateOutputPlaceholder(source); + + ranges.reverse().forEach(function(r) { + source = utils.replaceSubstring(source, value, r); + }); + + return source; + } + + /** + * Check if parsed node contains output placeholder – a target where + * pasted content should be inserted + * @param {AbbreviationNode} node + * @returns {Boolean} + */ + function hasOutputPlaceholder(node) { + if (locateOutputPlaceholder(node.content).length) + return true; + + // check if attributes contains placeholder + return !!utils.find(node.attributeList(), function(attr) { + return !!locateOutputPlaceholder(attr.value).length; + }); + } + + /** + * Insert pasted content into correct positions of parsed node + * @param {AbbreviationNode} node + * @param {String} content + * @param {Boolean} overwrite Overwrite node content if no value placeholders + * found instead of appending to existing content + */ + function insertPastedContent(node, content, overwrite) { + var nodesWithPlaceholders = node.findAll(function(item) { + return hasOutputPlaceholder(item); + }); + + if (hasOutputPlaceholder(node)) + nodesWithPlaceholders.unshift(node); + + if (nodesWithPlaceholders.length) { + nodesWithPlaceholders.forEach(function(item) { + item.content = replaceOutputPlaceholders(item.content, content); + item._attributes.forEach(function(attr) { + attr.value = replaceOutputPlaceholders(attr.value, content); + }); + }); + } else { + // on output placeholders in subtree, insert content in the deepest + // child node + var deepest = node.deepestChild() || node; + if (overwrite) { + deepest.content = content; + } else { + deepest.content = abbrUtils.insertChildContent(deepest.content, content); + } + } + } + + return { + pastedContent: function(item) { + var content = item.data('paste'); + if (Array.isArray(content)) { + return content[item.counter - 1]; + } else if (typeof content === 'function') { + return content(item.counter - 1, item.content); + } else if (content) { + return content; + } + }, + + /** + * @param {AbbreviationNode} tree + * @param {Object} options + */ + preprocessor: function(tree, options) { + if (options.pastedContent) { + var lines = utils.splitByLines(options.pastedContent, true).map(utils.trim); + + // set repeat count for implicitly repeated elements before + // tree is unrolled + tree.findAll(function(item) { + if (item.hasImplicitRepeat) { + item.data('paste', lines); + return item.repeatCount = lines.length; + } + }); + } + }, + + /** + * @param {AbbreviationNode} tree + * @param {Object} options + */ + postprocessor: function(tree, options) { + var that = this; + // for each node with pasted content, update text data + var targets = tree.findAll(function(item) { + var pastedContent = that.pastedContent(item); + if (pastedContent) { + insertPastedContent(item, pastedContent, !!item.data('pasteOverwrites')); + } + + return !!pastedContent; + }); + + if (!targets.length && options.pastedContent) { + // no implicitly repeated elements, put pasted content in + // the deepest child + insertPastedContent(tree, options.pastedContent); + } + } + }; +}); +},{"../../assets/range":"assets/range.js","../../assets/stringStream":"assets/stringStream.js","../../utils/abbreviation":"utils/abbreviation.js","../../utils/common":"utils/common.js"}],"parser/processor/resourceMatcher.js":[function(require,module,exports){ +/** + * Processor function that matches parsed AbbreviationNode + * against resources defined in resource module + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var resources = require('../../assets/resources'); + var elements = require('../../assets/elements'); + var utils = require('../../utils/common'); + var abbreviationUtils = require('../../utils/abbreviation'); + + /** + * Finds matched resources for child nodes of passed node + * element. A matched resource is a reference to snippets.json entry + * that describes output of parsed node + * @param {AbbreviationNode} node + * @param {String} syntax + */ + function matchResources(node, syntax, parser) { + // do a shallow copy because the children list can be modified during + // resource matching + node.children.slice(0).forEach(function(child) { + var r = resources.getMatchedResource(child, syntax); + if (typeof r === 'string') { + r = elements.create('snippet', r); + } + + child.data('resource', r); + var elemType = elements.type(r); + + if (elemType == 'snippet') { + var content = r.data; + var curContent = child._text || child.content; + if (curContent) { + content = abbreviationUtils.insertChildContent(content, curContent); + } + + child.content = content; + } else if (elemType == 'element') { + child._name = r.name; + if (Array.isArray(r.attributes)) { + child._attributes = [].concat(r.attributes, child._attributes); + } + } else if (elemType == 'reference') { + // it’s a reference to another abbreviation: + // parse it and insert instead of current child + /** @type AbbreviationNode */ + var subtree = parser.parse(r.data, { + syntax: syntax + }); + + // if context element should be repeated, check if we need to + // transfer repeated element to specific child node + if (child.repeatCount > 1) { + var repeatedChildren = subtree.findAll(function(node) { + return node.hasImplicitRepeat; + }); + + if (!repeatedChildren.length) { + repeatedChildren = subtree.children + } + + repeatedChildren.forEach(function(node) { + node.repeatCount = child.repeatCount; + node.hasImplicitRepeat = false; + }); + } + + // move child‘s children into the deepest child of new subtree + var deepestChild = subtree.deepestChild(); + if (deepestChild) { + child.children.forEach(function(c) { + deepestChild.addChild(c); + }); + deepestChild.content = child.content; + } + + // copy current attributes to children + subtree.children.forEach(function(node) { + child.attributeList().forEach(function(attr) { + node.attribute(attr.name, attr.value); + }); + }); + + child.replace(subtree.children); + } + + matchResources(child, syntax, parser); + }); + } + + return { + preprocessor: function(tree, options, parser) { + var syntax = options.syntax || utils.defaultSyntax(); + matchResources(tree, syntax, parser); + } + }; +}); +},{"../../assets/elements":"assets/elements.js","../../assets/resources":"assets/resources.js","../../utils/abbreviation":"utils/abbreviation.js","../../utils/common":"utils/common.js"}],"parser/processor/tagName.js":[function(require,module,exports){ +/** + * Resolves tag names in abbreviations with implied name + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var tagName = require('../../resolver/tagName'); + + /** + * Resolves implicit node names in parsed tree + * @param {AbbreviationNode} tree + */ + function resolveNodeNames(tree) { + tree.children.forEach(function(node) { + if (node.hasImplicitName() || node.data('forceNameResolving')) { + node._name = tagName.resolve(node.parent.name()); + node.data('nameResolved', true); + } + resolveNodeNames(node); + }); + + return tree; + } + + return { + postprocessor: resolveNodeNames + }; +}); +},{"../../resolver/tagName":"resolver/tagName.js"}],"parser/xml.js":[function(require,module,exports){ +/** + * HTML tokenizer by Marijn Haverbeke + * http://codemirror.net/ + * @constructor + * @memberOf __xmlParseDefine + * @param {Function} require + * @param {Underscore} _ + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var stringStream = require('../assets/stringStream'); + + var Kludges = { + autoSelfClosers : {}, + implicitlyClosed : {}, + contextGrabbers : {}, + doNotIndent : {}, + allowUnquoted : true, + allowMissing : true + }; + + // Return variables for tokenizers + var tagName = null, type = null; + + function inText(stream, state) { + function chain(parser) { + state.tokenize = parser; + return parser(stream, state); + } + + var ch = stream.next(); + if (ch == "<") { + if (stream.eat("!")) { + if (stream.eat("[")) { + if (stream.match("CDATA[")) + return chain(inBlock("atom", "]]>")); + else + return null; + } else if (stream.match("--")) + return chain(inBlock("comment", "-->")); + else if (stream.match("DOCTYPE", true, true)) { + stream.eatWhile(/[\w\._\-]/); + return chain(doctype(1)); + } else + return null; + } else if (stream.eat("?")) { + stream.eatWhile(/[\w\._\-]/); + state.tokenize = inBlock("meta", "?>"); + return "meta"; + } else { + type = stream.eat("/") ? "closeTag" : "openTag"; + stream.eatSpace(); + tagName = ""; + var c; + while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) + tagName += c; + state.tokenize = inTag; + return "tag"; + } + } else if (ch == "&") { + var ok; + if (stream.eat("#")) { + if (stream.eat("x")) { + ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); + } else { + ok = stream.eatWhile(/[\d]/) && stream.eat(";"); + } + } else { + ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); + } + return ok ? "atom" : "error"; + } else { + stream.eatWhile(/[^&<]/); + return "text"; + } + } + + function inTag(stream, state) { + var ch = stream.next(); + if (ch == ">" || (ch == "/" && stream.eat(">"))) { + state.tokenize = inText; + type = ch == ">" ? "endTag" : "selfcloseTag"; + return "tag"; + } else if (ch == "=") { + type = "equals"; + return null; + } else if (/[\'\"]/.test(ch)) { + state.tokenize = inAttribute(ch); + return state.tokenize(stream, state); + } else { + stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/); + return "word"; + } + } + + function inAttribute(quote) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.next() == quote) { + state.tokenize = inTag; + break; + } + } + return "string"; + }; + } + + function inBlock(style, terminator) { + return function(stream, state) { + while (!stream.eol()) { + if (stream.match(terminator)) { + state.tokenize = inText; + break; + } + stream.next(); + } + return style; + }; + } + + function doctype(depth) { + return function(stream, state) { + var ch; + while ((ch = stream.next()) !== null) { + if (ch == "<") { + state.tokenize = doctype(depth + 1); + return state.tokenize(stream, state); + } else if (ch == ">") { + if (depth == 1) { + state.tokenize = inText; + break; + } else { + state.tokenize = doctype(depth - 1); + return state.tokenize(stream, state); + } + } + } + return "meta"; + }; + } + + var curState = null, setStyle; + function pass() { + for (var i = arguments.length - 1; i >= 0; i--) + curState.cc.push(arguments[i]); + } + + function cont() { + pass.apply(null, arguments); + return true; + } + + function pushContext(tagName, startOfLine) { + var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName) + || (curState.context && curState.context.noIndent); + curState.context = { + prev : curState.context, + tagName : tagName, + indent : curState.indented, + startOfLine : startOfLine, + noIndent : noIndent + }; + } + + function popContext() { + if (curState.context) + curState.context = curState.context.prev; + } + + function element(type) { + if (type == "openTag") { + curState.tagName = tagName; + return cont(attributes, endtag(curState.startOfLine)); + } else if (type == "closeTag") { + var err = false; + if (curState.context) { + if (curState.context.tagName != tagName) { + if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) { + popContext(); + } + err = !curState.context || curState.context.tagName != tagName; + } + } else { + err = true; + } + + if (err) + setStyle = "error"; + return cont(endclosetag(err)); + } + return cont(); + } + + function endtag(startOfLine) { + return function(type) { + if (type == "selfcloseTag" + || (type == "endTag" && Kludges.autoSelfClosers + .hasOwnProperty(curState.tagName + .toLowerCase()))) { + maybePopContext(curState.tagName.toLowerCase()); + return cont(); + } + if (type == "endTag") { + maybePopContext(curState.tagName.toLowerCase()); + pushContext(curState.tagName, startOfLine); + return cont(); + } + return cont(); + }; + } + + function endclosetag(err) { + return function(type) { + if (err) + setStyle = "error"; + if (type == "endTag") { + popContext(); + return cont(); + } + setStyle = "error"; + return cont(arguments.callee); + }; + } + + function maybePopContext(nextTagName) { + var parentTagName; + while (true) { + if (!curState.context) { + return; + } + parentTagName = curState.context.tagName.toLowerCase(); + if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) + || !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { + return; + } + popContext(); + } + } + + function attributes(type) { + if (type == "word") { + setStyle = "attribute"; + return cont(attribute, attributes); + } + if (type == "endTag" || type == "selfcloseTag") + return pass(); + setStyle = "error"; + return cont(attributes); + } + + function attribute(type) { + if (type == "equals") + return cont(attvalue, attributes); + if (!Kludges.allowMissing) + setStyle = "error"; + return (type == "endTag" || type == "selfcloseTag") ? pass() + : cont(); + } + + function attvalue(type) { + if (type == "string") + return cont(attvaluemaybe); + if (type == "word" && Kludges.allowUnquoted) { + setStyle = "string"; + return cont(); + } + setStyle = "error"; + return (type == "endTag" || type == "selfCloseTag") ? pass() + : cont(); + } + + function attvaluemaybe(type) { + if (type == "string") + return cont(attvaluemaybe); + else + return pass(); + } + + function startState() { + return { + tokenize : inText, + cc : [], + indented : 0, + startOfLine : true, + tagName : null, + context : null + }; + } + + function token(stream, state) { + if (stream.sol()) { + state.startOfLine = true; + state.indented = 0; + } + + if (stream.eatSpace()) + return null; + + setStyle = type = tagName = null; + var style = state.tokenize(stream, state); + state.type = type; + if ((style || type) && style != "comment") { + curState = state; + while (true) { + var comb = state.cc.pop() || element; + if (comb(type || style)) + break; + } + } + state.startOfLine = false; + return setStyle || style; + } + + return { + /** + * @memberOf emmet.xmlParser + * @returns + */ + parse: function(data, offset) { + offset = offset || 0; + var state = startState(); + var stream = stringStream.create(data); + var tokens = []; + while (!stream.eol()) { + tokens.push({ + type: token(stream, state), + start: stream.start + offset, + end: stream.pos + offset + }); + stream.start = stream.pos; + } + + return tokens; + } + }; +}); + +},{"../assets/stringStream":"assets/stringStream.js"}],"plugin/file.js":[function(require,module,exports){ +/** + * Module for working with file. Shall implement + * IEmmetFile interface. + * + * Since implementation of this module depends + * greatly on current runtime, this module must be + * initialized with actual implementation first + * before use. E.g. + * require('./plugin/file')({ + * read: function() {...} + * }) + * + * By default, this module provides Node.JS implementation + */ + +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + + // hide it from Require.JS parser + (function(r) { + if (typeof define === 'undefined' || !define.amd) { + try { + fs = r('fs'); + path = r('path'); + } catch(e) {} + } + })(require); + + // module is a function that can extend itself + module.exports = function(obj) { + if (obj) { + utils.extend(module.exports, obj); + } + }; + + function bts(bytes) { + var out = []; + for (var i = 0, il = bytes.length; i < il; i++) { + out.push(String.fromCharCode(bytes[i])); + } + return out.join(''); + } + + function isURL(path) { + var re = /^https?:\/\//; + return re.test(path); + } + + return utils.extend(module.exports, { + _parseParams: function(args) { + var params = { + path: args[0], + size: 0 + }; + + args = utils.toArray(args, 1); + params.callback = args[args.length - 1]; + args = args.slice(0, args.length - 1); + if (args.length) { + params.size = args[0]; + } + + return params; + }, + + _read: function(params, callback) { + if (isURL(params.path)) { + var req = require(/^https:/.test(params.path) ? 'https' : 'http').get(params.path, function(res) { + var bufs = []; + var totalLength = 0; + var finished = false; + res + .on('data', function(chunk) { + totalLength += chunk.length; + bufs.push(chunk); + if (params.size && totalLength >= params.size) { + finished = true; + callback(null, Buffer.concat(bufs)); + req.abort(); + } + }) + .on('end', function() { + if (!finished) { + finished = true; + callback(null, Buffer.concat(bufs)); + } + }); + }).on('error', callback); + } else { + if (params.size) { + var fd = fs.openSync(params.path, 'r'); + var buf = new Buffer(params.size); + fs.read(fd, buf, 0, params.size, null, function(err, bytesRead) { + callback(err, buf) + }); + } else { + callback(null, fs.readFileSync(params.path)); + } + } + }, + + /** + * Reads binary file content and return it + * @param {String} path File's relative or absolute path + * @return {String} + */ + read: function(path, size, callback) { + var params = this._parseParams(arguments); + this._read(params, function(err, buf) { + params.callback(err, err ? '' : bts(buf)); + }); + }, + + /** + * Read file content and return it + * @param {String} path File's relative or absolute path + * @return {String} + */ + readText: function(path, size, callback) { + var params = this._parseParams(arguments); + this._read(params, function(err, buf) { + params.callback(err, err ? '' : buf.toString()); + }); + }, + + /** + * Locate file_name file that relates to editor_file. + * File name may be absolute or relative path + * + * Dealing with absolute path. + * Many modern editors have a "project" support as information unit, but you + * should not rely on project path to find file with absolute path. First, + * it requires user to create a project before using this method (and this + * is not very convenient). Second, project path doesn't always points to + * to website's document root folder: it may point, for example, to an + * upper folder which contains server-side scripts. + * + * For better result, you should use the following algorithm in locating + * absolute resources: + * 1) Get parent folder for editorFile as a start point + * 2) Append required fileName to start point and test if + * file exists + * 3) If it doesn't exists, move start point one level up (to parent folder) + * and repeat step 2. + * + * @param {String} editorFile + * @param {String} fileName + * @return {String} Returns null if fileName cannot be located + */ + locateFile: function(editorFile, fileName) { + if (isURL(fileName)) { + return fileName; + } + + var dirname = editorFile, f; + fileName = fileName.replace(/^\/+/, ''); + while (dirname && dirname !== path.dirname(dirname)) { + dirname = path.dirname(dirname); + f = path.join(dirname, fileName); + if (fs.existsSync(f)) + return f; + } + + return ''; + }, + + /** + * Creates absolute path by concatenating parent and fileName. + * If parent points to file, its parent directory is used + * @param {String} parent + * @param {String} fileName + * @return {String} + */ + createPath: function(parent, fileName, callback) { + var stat = fs.statSync(parent); + if (stat && !stat.isDirectory()) { + parent = path.dirname(parent); + } + + return callback(path.resolve(parent, fileName)); + }, + + /** + * Saves content as file + * @param {String} file File's absolute path + * @param {String} content File content + */ + save: function(file, content) { + fs.writeFileSync(file, content, 'ascii'); + }, + + /** + * Returns file extension in lower case + * @param {String} file + * @return {String} + */ + getExt: function(file) { + var m = (file || '').match(/\.([\w\-]+)$/); + return m ? m[1].toLowerCase() : ''; + } + + }); +}); +},{"../utils/common":"utils/common.js"}],"resolver/css.js":[function(require,module,exports){ +/** + * Resolver for fast CSS typing. Handles abbreviations with the following + * notation:
+ * + * (-vendor prefix)?property(value)*(!)? + * + *

+ * Abbreviation handling
+ * + * By default, Emmet searches for matching snippet definition for provided abbreviation. + * If snippet wasn't found, Emmet automatically generates element with + * abbreviation's name. For example, foo abbreviation will generate + * <foo></foo> output. + *

+ * This module will capture all expanded properties and upgrade them with values, + * vendor prefixes and !important declarations. All unmatched abbreviations will + * be automatically transformed into property-name: ${1} snippets. + * + * Vendor prefixes
+ * + * If CSS-property is preceded with dash, resolver should output property with + * all known vendor prefixes. For example, if brad + * abbreviation generates border-radius: ${value}; snippet, + * the -brad abbreviation should generate: + *

+ * -webkit-border-radius: ${value};
+ * -moz-border-radius: ${value};
+ * border-radius: ${value};
+ * 
+ * Note that o and ms prefixes are omitted since Opera and IE + * supports unprefixed property.

+ * + * Users can also provide an explicit list of one-character prefixes for any + * CSS property. For example, -wm-float will produce + * + *

+ * -webkit-float: ${1};
+ * -moz-float: ${1};
+ * float: ${1};
+ * 
+ * + * Although this example looks pointless, users can use this feature to write + * cutting-edge properties implemented by browser vendors recently. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + var resources = require('../assets/resources'); + var stringStream = require('../assets/stringStream'); + var ciu = require('../assets/caniuse'); + var utils = require('../utils/common'); + var template = require('../utils/template'); + var cssEditTree = require('../editTree/css'); + + var prefixObj = { + /** Real vendor prefix name */ + prefix: 'emmet', + + /** + * Indicates this prefix is obsolete and should't be used when user + * wants to generate all-prefixed properties + */ + obsolete: false, + + /** + * Returns prefixed CSS property name + * @param {String} name Unprefixed CSS property + */ + transformName: function(name) { + return '-' + this.prefix + '-' + name; + }, + + /** + * List of unprefixed CSS properties that supported by + * current prefix. This list is used to generate all-prefixed property + * @returns {Array} + */ + properties: function() { + return getProperties('css.' + this.prefix + 'Properties') || []; + }, + + /** + * Check if given property is supported by current prefix + * @param name + */ + supports: function(name) { + return ~this.properties().indexOf(name); + } + }; + + + /** + * List of registered one-character prefixes. Key is a one-character prefix, + * value is an prefixObj object + */ + var vendorPrefixes = {}; + + var defaultValue = '${1};'; + + // XXX module preferences + prefs.define('css.valueSeparator', ': ', + 'Defines a symbol that should be placed between CSS property and ' + + 'value when expanding CSS abbreviations.'); + prefs.define('css.propertyEnd', ';', + 'Defines a symbol that should be placed at the end of CSS property ' + + 'when expanding CSS abbreviations.'); + + prefs.define('stylus.valueSeparator', ' ', + 'Defines a symbol that should be placed between CSS property and ' + + 'value when expanding CSS abbreviations in Stylus dialect.'); + prefs.define('stylus.propertyEnd', '', + 'Defines a symbol that should be placed at the end of CSS property ' + + 'when expanding CSS abbreviations in Stylus dialect.'); + + prefs.define('sass.propertyEnd', '', + 'Defines a symbol that should be placed at the end of CSS property ' + + 'when expanding CSS abbreviations in SASS dialect.'); + + prefs.define('css.syntaxes', 'css, less, sass, scss, stylus, styl', + 'List of syntaxes that should be treated as CSS dialects.'); + + prefs.define('css.autoInsertVendorPrefixes', true, + 'Automatically generate vendor-prefixed copies of expanded CSS ' + + 'property. By default, Emmet will generate vendor-prefixed ' + + 'properties only when you put dash before abbreviation ' + + '(e.g. -bxsh). With this option enabled, you don’t ' + + 'need dashes before abbreviations: Emmet will produce ' + + 'vendor-prefixed properties for you.'); + + prefs.define('less.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for LESS syntax'); + prefs.define('scss.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for SCSS syntax'); + prefs.define('sass.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for SASS syntax'); + prefs.define('stylus.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for Stylus syntax'); + + var descTemplate = template('A comma-separated list of CSS properties that may have ' + + '<%= vendor %> vendor prefix. This list is used to generate ' + + 'a list of prefixed properties when expanding -property ' + + 'abbreviations. Empty list means that all possible CSS values may ' + + 'have <%= vendor %> prefix.'); + + var descAddonTemplate = template('A comma-separated list of additional CSS properties ' + + 'for css.<%= vendor %>Preperties preference. ' + + 'You should use this list if you want to add or remove a few CSS ' + + 'properties to original set. To add a new property, simply write its name, ' + + 'to remove it, precede property with hyphen.
' + + 'For example, to add foo property and remove border-radius one, ' + + 'the preference value will look like this: foo, -border-radius.'); + + // properties list is created from cssFeatures.html file + var props = { + 'webkit': 'animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-clip, background-composite, background-origin, background-size, border-fit, border-horizontal-spacing, border-image, border-vertical-spacing, box-align, box-direction, box-flex, box-flex-group, box-lines, box-ordinal-group, box-orient, box-pack, box-reflect, box-shadow, color-correction, column-break-after, column-break-before, column-break-inside, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-span, column-width, dashboard-region, font-smoothing, highlight, hyphenate-character, hyphenate-limit-after, hyphenate-limit-before, hyphens, line-box-contain, line-break, line-clamp, locale, margin-before-collapse, margin-after-collapse, marquee-direction, marquee-increment, marquee-repetition, marquee-style, mask-attachment, mask-box-image, mask-box-image-outset, mask-box-image-repeat, mask-box-image-slice, mask-box-image-source, mask-box-image-width, mask-clip, mask-composite, mask-image, mask-origin, mask-position, mask-repeat, mask-size, nbsp-mode, perspective, perspective-origin, rtl-ordering, text-combine, text-decorations-in-effect, text-emphasis-color, text-emphasis-position, text-emphasis-style, text-fill-color, text-orientation, text-security, text-stroke-color, text-stroke-width, transform, transition, transform-origin, transform-style, transition-delay, transition-duration, transition-property, transition-timing-function, user-drag, user-modify, user-select, writing-mode, svg-shadow, box-sizing, border-radius', + 'moz': 'animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-inline-policy, binding, border-bottom-colors, border-image, border-left-colors, border-right-colors, border-top-colors, box-align, box-direction, box-flex, box-ordinal-group, box-orient, box-pack, box-shadow, box-sizing, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-width, float-edge, font-feature-settings, font-language-override, force-broken-image-icon, hyphens, image-region, orient, outline-radius-bottomleft, outline-radius-bottomright, outline-radius-topleft, outline-radius-topright, perspective, perspective-origin, stack-sizing, tab-size, text-blink, text-decoration-color, text-decoration-line, text-decoration-style, text-size-adjust, transform, transform-origin, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-focus, user-input, user-modify, user-select, window-shadow, background-clip, border-radius', + 'ms': 'accelerator, backface-visibility, background-position-x, background-position-y, behavior, block-progression, box-align, box-direction, box-flex, box-line-progression, box-lines, box-ordinal-group, box-orient, box-pack, content-zoom-boundary, content-zoom-boundary-max, content-zoom-boundary-min, content-zoom-chaining, content-zoom-snap, content-zoom-snap-points, content-zoom-snap-type, content-zooming, filter, flow-from, flow-into, font-feature-settings, grid-column, grid-column-align, grid-column-span, grid-columns, grid-layer, grid-row, grid-row-align, grid-row-span, grid-rows, high-contrast-adjust, hyphenate-limit-chars, hyphenate-limit-lines, hyphenate-limit-zone, hyphens, ime-mode, interpolation-mode, layout-flow, layout-grid, layout-grid-char, layout-grid-line, layout-grid-mode, layout-grid-type, line-break, overflow-style, perspective, perspective-origin, perspective-origin-x, perspective-origin-y, scroll-boundary, scroll-boundary-bottom, scroll-boundary-left, scroll-boundary-right, scroll-boundary-top, scroll-chaining, scroll-rails, scroll-snap-points-x, scroll-snap-points-y, scroll-snap-type, scroll-snap-x, scroll-snap-y, scrollbar-arrow-color, scrollbar-base-color, scrollbar-darkshadow-color, scrollbar-face-color, scrollbar-highlight-color, scrollbar-shadow-color, scrollbar-track-color, text-align-last, text-autospace, text-justify, text-kashida-space, text-overflow, text-size-adjust, text-underline-position, touch-action, transform, transform-origin, transform-origin-x, transform-origin-y, transform-origin-z, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-select, word-break, wrap-flow, wrap-margin, wrap-through, writing-mode', + 'o': 'dashboard-region, animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, border-image, link, link-source, object-fit, object-position, tab-size, table-baseline, transform, transform-origin, transition, transition-delay, transition-duration, transition-property, transition-timing-function, accesskey, input-format, input-required, marquee-dir, marquee-loop, marquee-speed, marquee-style' + }; + + Object.keys(props).forEach(function(k) { + prefs.define('css.' + k + 'Properties', props[k], descTemplate({vendor: k})); + prefs.define('css.' + k + 'PropertiesAddon', '', descAddonTemplate({vendor: k})); + }); + + prefs.define('css.unitlessProperties', 'z-index, line-height, opacity, font-weight, zoom', + 'The list of properties whose values ​​must not contain units.'); + + prefs.define('css.intUnit', 'px', 'Default unit for integer values'); + prefs.define('css.floatUnit', 'em', 'Default unit for float values'); + + prefs.define('css.keywords', 'auto, inherit, all', + 'A comma-separated list of valid keywords that can be used in CSS abbreviations.'); + + prefs.define('css.keywordAliases', 'a:auto, i:inherit, s:solid, da:dashed, do:dotted, t:transparent', + 'A comma-separated list of keyword aliases, used in CSS abbreviation. ' + + 'Each alias should be defined as alias:keyword_name.'); + + prefs.define('css.unitAliases', 'e:em, p:%, x:ex, r:rem', + 'A comma-separated list of unit aliases, used in CSS abbreviation. ' + + 'Each alias should be defined as alias:unit_value.'); + + prefs.define('css.color.short', true, + 'Should color values like #ffffff be shortened to ' + + '#fff after abbreviation with color was expanded.'); + + prefs.define('css.color.case', 'keep', + 'Letter case of color values generated by abbreviations with color ' + + '(like c#0). Possible values are upper, ' + + 'lower and keep.'); + + prefs.define('css.fuzzySearch', true, + 'Enable fuzzy search among CSS snippet names. When enabled, every ' + + 'unknown snippet will be scored against available snippet ' + + 'names (not values or CSS properties!). The match with best score ' + + 'will be used to resolve snippet value. For example, with this ' + + 'preference enabled, the following abbreviations are equal: ' + + 'ov:h == ov-h == o-h == ' + + 'oh'); + + prefs.define('css.fuzzySearchMinScore', 0.3, + 'The minium score (from 0 to 1) that fuzzy-matched abbreviation should ' + + 'achive. Lower values may produce many false-positive matches, ' + + 'higher values may reduce possible matches.'); + + prefs.define('css.alignVendor', false, + 'If set to true, all generated vendor-prefixed properties ' + + 'will be aligned by real property name.'); + + + function isNumeric(ch) { + var code = ch && ch.charCodeAt(0); + return (ch && ch == '.' || (code > 47 && code < 58)); + } + + /** + * Check if provided snippet contains only one CSS property and value. + * @param {String} snippet + * @returns {Boolean} + */ + function isSingleProperty(snippet) { + snippet = utils.trim(snippet); + + // check if it doesn't contain a comment and a newline + if (/\/\*|\n|\r/.test(snippet)) { + return false; + } + + // check if it's a valid snippet definition + if (!/^[a-z0-9\-]+\s*\:/i.test(snippet)) { + return false; + } + + return snippet.replace(/\$\{.+?\}/g, '').split(':').length == 2; + } + + /** + * Normalizes abbreviated value to final CSS one + * @param {String} value + * @returns {String} + */ + function normalizeValue(value) { + if (value.charAt(0) == '-' && !/^\-[\.\d]/.test(value)) { + value = value.replace(/^\-+/, ''); + } + + var ch = value.charAt(0); + if (ch == '#') { + return normalizeHexColor(value); + } + + if (ch == '$') { + return utils.escapeText(value); + } + + return getKeyword(value); + } + + function normalizeHexColor(value) { + var hex = value.replace(/^#+/, '') || '0'; + if (hex.toLowerCase() == 't') { + return 'transparent'; + } + + var opacity = ''; + hex = hex.replace(/\.(\d+)$/, function(str) { + opacity = '0' + str; + return ''; + }); + + var repeat = utils.repeatString; + var color = null; + switch (hex.length) { + case 1: + color = repeat(hex, 6); + break; + case 2: + color = repeat(hex, 3); + break; + case 3: + color = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2); + break; + case 4: + color = hex + hex.substr(0, 2); + break; + case 5: + color = hex + hex.charAt(0); + break; + default: + color = hex.substr(0, 6); + } + + if (opacity) { + return toRgba(color, opacity); + } + + // color must be shortened? + if (prefs.get('css.color.short')) { + var p = color.split(''); + if (p[0] == p[1] && p[2] == p[3] && p[4] == p[5]) { + color = p[0] + p[2] + p[4]; + } + } + + // should transform case? + switch (prefs.get('css.color.case')) { + case 'upper': + color = color.toUpperCase(); + break; + case 'lower': + color = color.toLowerCase(); + break; + } + + return '#' + color; + } + + /** + * Transforms HEX color definition into RGBA one + * @param {String} color HEX color, 6 characters + * @param {String} opacity Opacity value + * @return {String} + */ + function toRgba(color, opacity) { + var r = parseInt(color.substr(0, 2), 16); + var g = parseInt(color.substr(2, 2), 16); + var b = parseInt(color.substr(4, 2), 16); + + return 'rgba(' + [r, g, b, opacity].join(', ') + ')'; + } + + function getKeyword(name) { + var aliases = prefs.getDict('css.keywordAliases'); + return name in aliases ? aliases[name] : name; + } + + function getUnit(name) { + var aliases = prefs.getDict('css.unitAliases'); + return name in aliases ? aliases[name] : name; + } + + function isValidKeyword(keyword) { + return ~prefs.getArray('css.keywords').indexOf(getKeyword(keyword)); + } + + /** + * Check if passed CSS property support specified vendor prefix + * @param {String} property + * @param {String} prefix + */ + function hasPrefix(property, prefix) { + var info = vendorPrefixes[prefix]; + + if (!info) + info = utils.find(vendorPrefixes, function(data) { + return data.prefix == prefix; + }); + + return info && info.supports(property); + } + + /** + * Finds available vendor prefixes for given CSS property. + * Search is performed within Can I Use database and internal + * property list + * @param {String} property CSS property name + * @return {Array} Array of resolved prefixes or null if + * prefixes are not available for this property at all. + * Empty array means prefixes are not available for current + * user-define era + */ + function findVendorPrefixes(property) { + var prefixes = ciu.resolvePrefixes(property); + if (!prefixes) { + // Can I Use database is disabled or prefixes are not + // available for this property + prefixes = []; + Object.keys(vendorPrefixes).forEach(function(key) { + if (hasPrefix(property, key)) { + prefixes.push(vendorPrefixes[key].prefix); + } + }); + + if (!prefixes.length) { + prefixes = null; + } + } + + return prefixes; + } + + /** + * Search for a list of supported prefixes for CSS property. This list + * is used to generate all-prefixed snippet + * @param {String} property CSS property name + * @returns {Array} + */ + function findInternalPrefixes(property, noAutofill) { + var result = []; + var prefixes = findVendorPrefixes(property); + + if (prefixes) { + var prefixMap = {}; + Object.keys(vendorPrefixes).forEach(function(key) { + prefixMap[vendorPrefixes[key].prefix] = key; + }); + + result = prefixes.map(function(prefix) { + return prefixMap[prefix]; + }); + } + + if (!result.length && !noAutofill) { + // add all non-obsolete prefixes + Object.keys(vendorPrefixes).forEach(function(prefix) { + if (!vendorPrefixes[prefix].obsolete) { + result.push(prefix); + } + }); + } + + return result; + } + + function addPrefix(name, obj) { + if (typeof obj === 'string') { + obj = {prefix: obj}; + } + + vendorPrefixes[name] = utils.extend({}, prefixObj, obj); + } + + function getSyntaxPreference(name, syntax) { + if (syntax) { + // hacky alias for Stylus dialect + if (syntax == 'styl') { + syntax = 'stylus'; + } + + var val = prefs.get(syntax + '.' + name); + if (typeof val !== 'undefined') { + return val; + } + } + + return prefs.get('css.' + name); + } + + /** + * Format CSS property according to current syntax dialect + * @param {String} property + * @param {String} syntax + * @returns {String} + */ + function formatProperty(property, syntax) { + var ix = property.indexOf(':'); + property = property.substring(0, ix).replace(/\s+$/, '') + + getSyntaxPreference('valueSeparator', syntax) + + utils.trim(property.substring(ix + 1)); + + return property.replace(/\s*;\s*$/, getSyntaxPreference('propertyEnd', syntax)); + } + + /** + * Transforms snippet value if required. For example, this transformation + * may add !important declaration to CSS property + * @param {String} snippet + * @param {Boolean} isImportant + * @returns {String} + */ + function transformSnippet(snippet, isImportant, syntax) { + if (typeof snippet !== 'string') { + snippet = snippet.data; + } + + if (!isSingleProperty(snippet)) { + return snippet; + } + + if (isImportant) { + if (~snippet.indexOf(';')) { + snippet = snippet.split(';').join(' !important;'); + } else { + snippet += ' !important'; + } + } + + return formatProperty(snippet, syntax); + } + + function getProperties(key) { + var list = prefs.getArray(key); + var addon = prefs.getArray(key + 'Addon'); + if (addon) { + addon.forEach(function(prop) { + if (prop.charAt(0) == '-') { + list = utils.without(list, prop.substr(1)); + } else { + if (prop.charAt(0) == '+') + prop = prop.substr(1); + + list.push(prop); + } + }); + } + + return list; + } + + /** + * Tries to produce properties with vendor-prefixed value + * @param {Object} snippetObj Parsed snippet object + * @return {Array} Array of properties with prefixed values + */ + function resolvePrefixedValues(snippetObj, isImportant, syntax) { + var prefixes = []; + var lookup = {}; + + var parts = cssEditTree.findParts(snippetObj.value); + parts.reverse(); + parts.forEach(function(p) { + var partValue = p.substring(snippetObj.value); + (findVendorPrefixes(partValue) || []).forEach(function(prefix) { + if (!lookup[prefix]) { + lookup[prefix] = snippetObj.value; + prefixes.push(prefix); + } + + lookup[prefix] = utils.replaceSubstring(lookup[prefix], '-' + prefix + '-' + partValue, p); + }); + }); + + return prefixes.map(function(prefix) { + return transformSnippet(snippetObj.name + ':' + lookup[prefix], isImportant, syntax); + }); + } + + + // TODO refactor, this looks awkward now + addPrefix('w', { + prefix: 'webkit' + }); + addPrefix('m', { + prefix: 'moz' + }); + addPrefix('s', { + prefix: 'ms' + }); + addPrefix('o', { + prefix: 'o' + }); + + + module = module || {}; + module.exports = { + /** + * Adds vendor prefix + * @param {String} name One-character prefix name + * @param {Object} obj Object describing vendor prefix + * @memberOf cssResolver + */ + addPrefix: addPrefix, + + /** + * Check if passed CSS property supports specified vendor prefix + * @param {String} property + * @param {String} prefix + */ + supportsPrefix: hasPrefix, + + resolve: function(node, syntax) { + var cssSyntaxes = prefs.getArray('css.syntaxes'); + if (cssSyntaxes && ~cssSyntaxes.indexOf(syntax) && node.isElement()) { + return this.expandToSnippet(node.abbreviation, syntax); + } + + return null; + }, + + /** + * Returns prefixed version of passed CSS property, only if this + * property supports such prefix + * @param {String} property + * @param {String} prefix + * @returns + */ + prefixed: function(property, prefix) { + return hasPrefix(property, prefix) + ? '-' + prefix + '-' + property + : property; + }, + + /** + * Returns list of all registered vendor prefixes + * @returns {Array} + */ + listPrefixes: function() { + return vendorPrefixes.map(function(obj) { + return obj.prefix; + }); + }, + + /** + * Returns object describing vendor prefix + * @param {String} name + * @returns {Object} + */ + getPrefix: function(name) { + return vendorPrefixes[name]; + }, + + /** + * Removes prefix object + * @param {String} name + */ + removePrefix: function(name) { + if (name in vendorPrefixes) + delete vendorPrefixes[name]; + }, + + /** + * Extract vendor prefixes from abbreviation + * @param {String} abbr + * @returns {Object} Object containing array of prefixes and clean + * abbreviation name + */ + extractPrefixes: function(abbr) { + if (abbr.charAt(0) != '-') { + return { + property: abbr, + prefixes: null + }; + } + + // abbreviation may either contain sequence of one-character prefixes + // or just dash, meaning that user wants to produce all possible + // prefixed properties + var i = 1, il = abbr.length, ch; + var prefixes = []; + + while (i < il) { + ch = abbr.charAt(i); + if (ch == '-') { + // end-sequence character found, stop searching + i++; + break; + } + + if (ch in vendorPrefixes) { + prefixes.push(ch); + } else { + // no prefix found, meaning user want to produce all + // vendor-prefixed properties + prefixes.length = 0; + i = 1; + break; + } + + i++; + } + + // reached end of abbreviation and no property name left + if (i == il -1) { + i = 1; + prefixes.length = 1; + } + + return { + property: abbr.substring(i), + prefixes: prefixes.length ? prefixes : 'all' + }; + }, + + /** + * Search for value substring in abbreviation + * @param {String} abbr + * @returns {String} Value substring + */ + findValuesInAbbreviation: function(abbr, syntax) { + syntax = syntax || 'css'; + + var i = 0, il = abbr.length, value = '', ch; + while (i < il) { + ch = abbr.charAt(i); + if (isNumeric(ch) || ch == '#' || ch == '$' || (ch == '-' && isNumeric(abbr.charAt(i + 1)))) { + value = abbr.substring(i); + break; + } + + i++; + } + + // try to find keywords in abbreviation + var property = abbr.substring(0, abbr.length - value.length); + var keywords = []; + // try to extract some commonly-used properties + while (~property.indexOf('-') && !resources.findSnippet(syntax, property)) { + var parts = property.split('-'); + var lastPart = parts.pop(); + if (!isValidKeyword(lastPart)) { + break; + } + + keywords.unshift(lastPart); + property = parts.join('-'); + } + + return keywords.join('-') + value; + }, + + parseValues: function(str) { + /** @type StringStream */ + var stream = stringStream.create(str); + var values = []; + var ch = null; + + while ((ch = stream.next())) { + if (ch == '$') { + stream.match(/^[^\$]+/, true); + values.push(stream.current()); + } else if (ch == '#') { + stream.match(/^t|[0-9a-f]+(\.\d+)?/i, true); + values.push(stream.current()); + } else if (ch == '-') { + if (isValidKeyword(utils.last(values)) || + ( stream.start && isNumeric(str.charAt(stream.start - 1)) ) + ) { + stream.start = stream.pos; + } + + stream.match(/^\-?[0-9]*(\.[0-9]+)?[a-z%\.]*/, true); + values.push(stream.current()); + } else { + stream.match(/^[0-9]*(\.[0-9]*)?[a-z%]*/, true); + values.push(stream.current()); + } + + stream.start = stream.pos; + } + + return values + .filter(function(item) { + return !!item; + }) + .map(normalizeValue); + }, + + /** + * Extracts values from abbreviation + * @param {String} abbr + * @returns {Object} Object containing array of values and clean + * abbreviation name + */ + extractValues: function(abbr) { + // search for value start + var abbrValues = this.findValuesInAbbreviation(abbr); + if (!abbrValues) { + return { + property: abbr, + values: null + }; + } + + return { + property: abbr.substring(0, abbr.length - abbrValues.length).replace(/-$/, ''), + values: this.parseValues(abbrValues) + }; + }, + + /** + * Normalizes value, defined in abbreviation. + * @param {String} value + * @param {String} property + * @returns {String} + */ + normalizeValue: function(value, property) { + property = (property || '').toLowerCase(); + var unitlessProps = prefs.getArray('css.unitlessProperties'); + return value.replace(/^(\-?[0-9\.]+)([a-z]*)$/, function(str, val, unit) { + if (!unit && (val == '0' || ~unitlessProps.indexOf(property))) + return val; + + if (!unit) + return val.replace(/\.$/, '') + prefs.get(~val.indexOf('.') ? 'css.floatUnit' : 'css.intUnit'); + + return val + getUnit(unit); + }); + }, + + /** + * Expands abbreviation into a snippet + * @param {String} abbr Abbreviation name to expand + * @param {String} value Abbreviation value + * @param {String} syntax Currect syntax or dialect. Default is 'css' + * @returns {Object} Array of CSS properties and values or predefined + * snippet (string or element) + */ + expand: function(abbr, value, syntax) { + syntax = syntax || 'css'; + var autoInsertPrefixes = prefs.get(syntax + '.autoInsertVendorPrefixes'); + + // check if snippet should be transformed to !important + var isImportant = /^(.+)\!$/.test(abbr); + if (isImportant) { + abbr = RegExp.$1; + } + + // check if we have abbreviated resource + var snippet = resources.findSnippet(syntax, abbr); + if (snippet && !autoInsertPrefixes) { + return transformSnippet(snippet, isImportant, syntax); + } + + // no abbreviated resource, parse abbreviation + var prefixData = this.extractPrefixes(abbr); + var valuesData = this.extractValues(prefixData.property); + var abbrData = utils.extend(prefixData, valuesData); + + if (!snippet) { + snippet = resources.findSnippet(syntax, abbrData.property); + } else { + abbrData.values = null; + } + + if (!snippet && prefs.get('css.fuzzySearch')) { + // let’s try fuzzy search + snippet = resources.fuzzyFindSnippet(syntax, abbrData.property, parseFloat(prefs.get('css.fuzzySearchMinScore'))); + } + + if (!snippet) { + if (!abbrData.property) { + return null; + } + snippet = abbrData.property + ':' + defaultValue; + } else if (typeof snippet !== 'string') { + snippet = snippet.data; + } + + if (!isSingleProperty(snippet)) { + return snippet; + } + + var snippetObj = this.splitSnippet(snippet); + var result = []; + if (!value && abbrData.values) { + value = abbrData.values.map(function(val) { + return this.normalizeValue(val, snippetObj.name); + }, this).join(' ') + ';'; + } + + snippetObj.value = value || snippetObj.value; + + var prefixes = abbrData.prefixes == 'all' || (!abbrData.prefixes && autoInsertPrefixes) + ? findInternalPrefixes(snippetObj.name, autoInsertPrefixes && abbrData.prefixes != 'all') + : abbrData.prefixes; + + + var names = [], propName; + (prefixes || []).forEach(function(p) { + if (p in vendorPrefixes) { + propName = vendorPrefixes[p].transformName(snippetObj.name); + names.push(propName); + result.push(transformSnippet(propName + ':' + snippetObj.value, + isImportant, syntax)); + } + }); + + // put the original property + result.push(transformSnippet(snippetObj.name + ':' + snippetObj.value, isImportant, syntax)); + names.push(snippetObj.name); + + result = resolvePrefixedValues(snippetObj, isImportant, syntax).concat(result); + + if (prefs.get('css.alignVendor')) { + var pads = utils.getStringsPads(names); + result = result.map(function(prop, i) { + return pads[i] + prop; + }); + } + + return result; + }, + + /** + * Same as expand method but transforms output into + * Emmet snippet + * @param {String} abbr + * @param {String} syntax + * @returns {String} + */ + expandToSnippet: function(abbr, syntax) { + var snippet = this.expand(abbr, null, syntax); + if (snippet === null) { + return null; + } + + if (Array.isArray(snippet)) { + return snippet.join('\n'); + } + + if (typeof snippet !== 'string') { + return snippet.data; + } + + return snippet + ''; + }, + + /** + * Split snippet into a CSS property-value pair + * @param {String} snippet + */ + splitSnippet: function(snippet) { + snippet = utils.trim(snippet); + if (snippet.indexOf(':') == -1) { + return { + name: snippet, + value: defaultValue + }; + } + + var pair = snippet.split(':'); + + return { + name: utils.trim(pair.shift()), + // replace ${0} tabstop to produce valid vendor-prefixed values + // where possible + value: utils.trim(pair.join(':')).replace(/^(\$\{0\}|\$0)(\s*;?)$/, '${1}$2') + }; + }, + + getSyntaxPreference: getSyntaxPreference, + transformSnippet: transformSnippet, + vendorPrefixes: findVendorPrefixes + }; + + return module.exports; +}); +},{"../assets/caniuse":"assets/caniuse.js","../assets/preferences":"assets/preferences.js","../assets/resources":"assets/resources.js","../assets/stringStream":"assets/stringStream.js","../editTree/css":"editTree/css.js","../utils/common":"utils/common.js","../utils/template":"utils/template.js"}],"resolver/cssGradient.js":[function(require,module,exports){ +/** + * 'Expand Abbreviation' handler that parses gradient definition from under + * cursor and updates CSS rule with vendor-prefixed values. + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var prefs = require('../assets/preferences'); + var resources = require('../assets/resources'); + var utils = require('../utils/common'); + var stringStream = require('../assets/stringStream'); + var cssResolver = require('./css'); + var range = require('../assets/range'); + var cssEditTree = require('../editTree/css'); + var editorUtils = require('../utils/editor'); + var linearGradient = require('./gradient/linear'); + + var cssSyntaxes = ['css', 'less', 'sass', 'scss', 'stylus', 'styl']; + + // XXX define preferences + prefs.define('css.gradient.prefixes', 'webkit, moz, o', + 'A comma-separated list of vendor-prefixes for which values should ' + + 'be generated.'); + + prefs.define('css.gradient.oldWebkit', false, + 'Generate gradient definition for old Webkit implementations'); + + prefs.define('css.gradient.omitDefaultDirection', true, + 'Do not output default direction definition in generated gradients.'); + + prefs.define('css.gradient.defaultProperty', 'background-image', + 'When gradient expanded outside CSS value context, it will produce ' + + 'properties with this name.'); + + prefs.define('css.gradient.fallback', false, + 'With this option enabled, CSS gradient generator will produce ' + + 'background-color property with gradient first color ' + + 'as fallback for old browsers.'); + + /** + * Resolves property name (abbreviation): searches for snippet definition in + * 'resources' and returns new name of matched property + */ + function resolvePropertyName(name, syntax) { + var snippet = resources.findSnippet(syntax, name); + + if (!snippet && prefs.get('css.fuzzySearch')) { + var minScore = parseFloat(prefs.get('css.fuzzySearchMinScore')); + snippet = resources.fuzzyFindSnippet(syntax, name, minScore); + } + + if (snippet) { + if (typeof snippet !== 'string') { + snippet = snippet.data; + } + + return cssResolver.splitSnippet(snippet).name; + } + } + + /** + * Returns vendor prefixes for given gradient type + * @param {String} type Gradient type (currently, 'linear-gradient' + * is the only supported value) + * @return {Array} + */ + function getGradientPrefixes(type) { + var prefixes = cssResolver.vendorPrefixes(type); + if (!prefixes) { + // disabled Can I Use, fallback to property list + prefixes = prefs.getArray('css.gradient.prefixes'); + } + + return prefixes || []; + } + + function getPrefixedNames(type) { + var prefixes = getGradientPrefixes(type); + var names = prefixes + ? prefixes.map(function(p) { + return '-' + p + '-' + type; + }) + : []; + + names.push(type); + + return names; + } + + /** + * Returns list of CSS properties with gradient + * @param {Array} gradient List of gradient objects + * @param {CSSEditElement} property Original CSS property + * @returns {Array} + */ + function getPropertiesForGradient(gradients, property) { + var props = []; + var propertyName = property.name(); + var omitDir = prefs.get('css.gradient.omitDefaultDirection'); + + if (prefs.get('css.gradient.fallback') && ~propertyName.toLowerCase().indexOf('background')) { + props.push({ + name: 'background-color', + value: '${1:' + gradients[0].gradient.colorStops[0].color + '}' + }); + } + + var value = property.value(); + getGradientPrefixes('linear-gradient').forEach(function(prefix) { + var name = cssResolver.prefixed(propertyName, prefix); + if (prefix == 'webkit' && prefs.get('css.gradient.oldWebkit')) { + try { + props.push({ + name: name, + value: insertGradientsIntoCSSValue(gradients, value, { + prefix: prefix, + oldWebkit: true, + omitDefaultDirection: omitDir + }) + }); + } catch(e) {} + } + + props.push({ + name: name, + value: insertGradientsIntoCSSValue(gradients, value, { + prefix: prefix, + omitDefaultDirection: omitDir + }) + }); + }); + + return props.sort(function(a, b) { + return b.name.length - a.name.length; + }); + } + + /** + * Replaces old gradient definitions in given CSS property value + * with new ones, preserving original formatting + * @param {Array} gradients List of CSS gradients + * @param {String} value Original CSS value + * @param {Object} options Options for gradient’s stringify() method + * @return {String} + */ + function insertGradientsIntoCSSValue(gradients, value, options) { + // gradients *should* passed in order they actually appear in CSS property + // iterate over it in backward direction to preserve gradient locations + options = options || {}; + gradients = utils.clone(gradients); + gradients.reverse().forEach(function(item, i) { + var suffix = !i && options.placeholder ? options.placeholder : ''; + var str = options.oldWebkit ? item.gradient.stringifyOldWebkit(options) : item.gradient.stringify(options); + value = utils.replaceSubstring(value, str + suffix, item.matchedPart); + }); + + return value; + } + + /** + * Returns list of properties with the same meaning + * (e.g. vendor-prefixed + original name) + * @param {String} property CSS property name + * @return {Array} + */ + function similarPropertyNames(property) { + if (typeof property !== 'string') { + property = property.name(); + } + + var similarProps = (cssResolver.vendorPrefixes(property) || []).map(function(prefix) { + return '-' + prefix + '-' + property; + }); + similarProps.push(property); + return similarProps; + } + + /** + * Pastes gradient definition into CSS rule with correct vendor-prefixes + * @param {EditElement} property Matched CSS property + * @param {Array} gradients List of gradients to insert + */ + function pasteGradient(property, gradients) { + var rule = property.parent; + var alignVendor = prefs.get('css.alignVendor'); + var omitDir = prefs.get('css.gradient.omitDefaultDirection'); + + // we may have aligned gradient definitions: find the smallest value + // separator + var sep = property.styleSeparator; + var before = property.styleBefore; + + // first, remove all properties within CSS rule with the same name and + // gradient definition + rule.getAll(similarPropertyNames(property)).forEach(function(item) { + if (item != property && /gradient/i.test(item.value())) { + if (item.styleSeparator.length < sep.length) { + sep = item.styleSeparator; + } + if (item.styleBefore.length < before.length) { + before = item.styleBefore; + } + rule.remove(item); + } + }); + + if (alignVendor) { + // update prefix + if (before != property.styleBefore) { + var fullRange = property.fullRange(); + rule._updateSource(before, fullRange.start, fullRange.start + property.styleBefore.length); + property.styleBefore = before; + } + + // update separator value + if (sep != property.styleSeparator) { + rule._updateSource(sep, property.nameRange().end, property.valueRange().start); + property.styleSeparator = sep; + } + } + + var value = property.value(); + + // create list of properties to insert + var propsToInsert = getPropertiesForGradient(gradients, property); + + // align prefixed values + if (alignVendor) { + var names = [], values = []; + propsToInsert.forEach(function(item) { + names.push(item.name); + values.push(item.value); + }); + values.push(property.value()); + names.push(property.name()); + + var valuePads = utils.getStringsPads(values.map(function(v) { + return v.substring(0, v.indexOf('(')); + })); + + var namePads = utils.getStringsPads(names); + property.name(namePads[namePads.length - 1] + property.name()); + + propsToInsert.forEach(function(prop, i) { + prop.name = namePads[i] + prop.name; + prop.value = valuePads[i] + prop.value; + }); + + property.value(valuePads[valuePads.length - 1] + property.value()); + } + + // put vendor-prefixed definitions before current rule + propsToInsert.forEach(function(prop) { + rule.add(prop.name, prop.value, rule.indexOf(property)); + }); + + // put vanilla-clean gradient definition into current rule + property.value(insertGradientsIntoCSSValue(gradients, value, { + placeholder: '${2}', + omitDefaultDirection: omitDir + })); + } + + /** + * Validates caret position relatively to located gradients + * in CSS rule. In other words, it checks if it’s safe to + * expand gradients for current caret position or not. + * + * See issue https://github.com/sergeche/emmet-sublime/issues/411 + * + * @param {Array} gradients List of parsed gradients + * @param {Number} caretPos Current caret position + * @param {String} syntax Current document syntax + * @return {Boolean} + */ + function isValidCaretPosition(gradients, caretPos, syntax) { + syntax = syntax || 'css'; + if (syntax == 'css' || syntax == 'less' || syntax == 'scss') { + return true; + } + + var offset = gradients.property.valueRange(true).start; + var parts = gradients.gradients; + + // in case of preprocessors where properties are separated with + // newlines, make sure there’s no gradient definition past + // current caret position. + for (var i = parts.length - 1; i >= 0; i--) { + if (parts[i].matchedPart.start + offset >= caretPos) { + return false; + } + } + + return true; + } + + module = module || {}; + return module.exports = { + /** + * Search for gradient definitions inside CSS property value + * @returns {Array} Array of matched gradients + */ + findGradients: function(cssProp) { + var value = cssProp.value(); + var gradients = []; + var that = this; + cssProp.valueParts().forEach(function(part) { + var partValue = part.substring(value); + if (linearGradient.isLinearGradient(partValue)) { + var gradient = linearGradient.parse(partValue); + if (gradient) { + gradients.push({ + gradient: gradient, + matchedPart: part + }); + } + } + }); + + return gradients.length ? gradients : null; + }, + + /** + * Returns list of gradients found in CSS property + * of given CSS code in specified (caret) position + * @param {String} css CSS code snippet + * @param {Number} pos Character index where to start searching for CSS property + * @return {Array} + */ + gradientsFromCSSProperty: function(css, pos) { + var cssProp = cssEditTree.propertyFromPosition(css, pos); + if (cssProp) { + var grd = this.findGradients(cssProp); + if (grd) { + return { + property: cssProp, + gradients: grd + }; + } + } + + return null; + }, + + /** + * Handler for “Expand Abbreviation” action + * @param {IEmmetEditor} editor + * @param {String} syntax + * @param {String} profile + * return {Boolean} + */ + expandAbbreviationHandler: function(editor, syntax, profile) { + var info = editorUtils.outputInfo(editor, syntax, profile); + if (!~cssSyntaxes.indexOf(info.syntax)) { + return false; + } + + // let's see if we are expanding gradient definition + var caret = editor.getCaretPos(); + var content = info.content; + var gradients = this.gradientsFromCSSProperty(content, caret); + if (gradients) { + if (!isValidCaretPosition(gradients, caret, info.syntax)) { + return false; + } + + var cssProperty = gradients.property; + var cssRule = cssProperty.parent; + var ruleStart = cssRule.options.offset || 0; + var ruleEnd = ruleStart + cssRule.toString().length; + + // Handle special case: + // user wrote gradient definition between existing CSS + // properties and did not finished it with semicolon. + // In this case, we have semicolon right after gradient + // definition and re-parse rule again + if (/[\n\r]/.test(cssProperty.value())) { + // insert semicolon at the end of gradient definition + var insertPos = cssProperty.valueRange(true).start + utils.last(gradients.gradients).matchedPart.end; + content = utils.replaceSubstring(content, ';', insertPos); + + var _gradients = this.gradientsFromCSSProperty(content, caret); + if (_gradients) { + gradients = _gradients; + cssProperty = gradients.property; + cssRule = cssProperty.parent; + } + } + + // make sure current property has terminating semicolon + cssProperty.end(';'); + + // resolve CSS property name + var resolvedName = resolvePropertyName(cssProperty.name(), syntax); + if (resolvedName) { + cssProperty.name(resolvedName); + } + + pasteGradient(cssProperty, gradients.gradients); + editor.replaceContent(cssRule.toString(), ruleStart, ruleEnd, true); + return true; + } + + return this.expandGradientOutsideValue(editor, syntax); + }, + + /** + * Tries to expand gradient outside CSS value + * @param {IEmmetEditor} editor + * @param {String} syntax + */ + expandGradientOutsideValue: function(editor, syntax) { + var propertyName = prefs.get('css.gradient.defaultProperty'); + var omitDir = prefs.get('css.gradient.omitDefaultDirection'); + + if (!propertyName) { + return false; + } + + // assuming that gradient definition is written on new line, + // do a simplified parsing + var content = String(editor.getContent()); + /** @type Range */ + var lineRange = range.create(editor.getCurrentLineRange()); + + // get line content and adjust range with padding + var line = lineRange.substring(content) + .replace(/^\s+/, function(pad) { + lineRange.start += pad.length; + return ''; + }) + .replace(/\s+$/, function(pad) { + lineRange.end -= pad.length; + return ''; + }); + + // trick parser: make it think that we’re parsing actual CSS property + var fakeCSS = 'a{' + propertyName + ': ' + line + ';}'; + var gradients = this.gradientsFromCSSProperty(fakeCSS, fakeCSS.length - 2); + if (gradients) { + var props = getPropertiesForGradient(gradients.gradients, gradients.property); + props.push({ + name: gradients.property.name(), + value: insertGradientsIntoCSSValue(gradients.gradients, gradients.property.value(), { + placeholder: '${2}', + omitDefaultDirection: omitDir + }) + }); + + var sep = cssResolver.getSyntaxPreference('valueSeparator', syntax); + var end = cssResolver.getSyntaxPreference('propertyEnd', syntax); + + if (prefs.get('css.alignVendor')) { + var pads = utils.getStringsPads(props.map(function(prop) { + return prop.value.substring(0, prop.value.indexOf('(')); + })); + props.forEach(function(prop, i) { + prop.value = pads[i] + prop.value; + }); + } + + props = props.map(function(item) { + return item.name + sep + item.value + end; + }); + + editor.replaceContent(props.join('\n'), lineRange.start, lineRange.end); + return true; + } + + return false; + }, + + /** + * Handler for “Reflect CSS Value“ action + * @param {String} property + */ + reflectValueHandler: function(property) { + var omitDir = prefs.get('css.gradient.omitDefaultDirection'); + var gradients = this.findGradients(property); + if (!gradients) { + return false; + } + + var that = this; + var value = property.value(); + + // reflect value for properties with the same name + property.parent.getAll(similarPropertyNames(property)).forEach(function(prop) { + if (prop === property) { + return; + } + + // make sure current property contains gradient definition, + // otherwise – skip it + var localGradients = that.findGradients(prop); + if (localGradients) { + // detect vendor prefix for current property + var localValue = prop.value(); + var dfn = localGradients[0].matchedPart.substring(localValue); + var prefix = ''; + if (/^\s*\-([a-z]+)\-/.test(dfn)) { + prefix = RegExp.$1; + } + + prop.value(insertGradientsIntoCSSValue(gradients, value, { + prefix: prefix, + omitDefaultDirection: omitDir + })); + } + }); + + return true; + } + }; +}); +},{"../assets/preferences":"assets/preferences.js","../assets/range":"assets/range.js","../assets/resources":"assets/resources.js","../assets/stringStream":"assets/stringStream.js","../editTree/css":"editTree/css.js","../utils/common":"utils/common.js","../utils/editor":"utils/editor.js","./css":"resolver/css.js","./gradient/linear":"resolver/gradient/linear.js"}],"resolver/gradient/linear.js":[function(require,module,exports){ +/** + * CSS linear gradient definition + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var stringStream = require('../../assets/stringStream'); + var utils = require('../../utils/common'); + + // all directions are expressed in “new style” degrees + var directions = { + 'bottom': 0, + 'bottom left': 45, + 'left': 90, + 'top left': 135, + 'top': 180, + 'top right': 225, + 'right': 270, + 'bottom right': 315, + + 'to top': 0, + 'to top right': 45, + 'to right': 90, + 'to bottom right': 135, + 'to bottom': 180, + 'to bottom left': 225, + 'to left': 270, + 'to top left': 315 + }; + + var defaultDirections = ['top', 'to bottom', '0deg']; + + + var reLinearGradient = /^\s*(\-[a-z]+\-)?(lg|linear\-gradient)\s*\(/i; + var reDeg = /(\d+)deg/i; + var reKeyword = /top|bottom|left|right/i; + + function LinearGradient(dfn) { + this.colorStops = []; + this.direction = 180; + + // extract tokens + var stream = stringStream.create(utils.trim(dfn)); + var ch, cur; + while ((ch = stream.next())) { + if (stream.peek() == ',') { + // Is it a first entry? Check if it’s a direction + cur = stream.current(); + + if (!this.colorStops.length && (reDeg.test(cur) || reKeyword.test(cur))) { + this.direction = resolveDirection(cur); + } else { + this.addColorStop(cur); + } + + stream.next(); + stream.eatSpace(); + stream.start = stream.pos; + } else if (ch == '(') { // color definition, like 'rgb(0,0,0)' + stream.skipTo(')'); + } + } + + // add last token + this.addColorStop(stream.current()); + } + + LinearGradient.prototype = { + type: 'linear-gradient', + addColorStop: function(color, ix) { + color = normalizeSpace(color || ''); + if (!color) { + return; + } + + color = this.parseColorStop(color); + + if (typeof ix === 'undefined') { + this.colorStops.push(color); + } else { + this.colorStops.splice(ix, 0, color); + } + }, + + /** + * Parses color stop definition + * @param {String} colorStop + * @returns {Object} + */ + parseColorStop: function(colorStop) { + colorStop = normalizeSpace(colorStop); + + // find color declaration + // first, try complex color declaration, like rgb(0,0,0) + var color = null; + colorStop = colorStop.replace(/^(\w+\(.+?\))\s*/, function(str, c) { + color = c; + return ''; + }); + + if (!color) { + // try simple declaration, like yellow, #fco, #ffffff, etc. + var parts = colorStop.split(' '); + color = parts[0]; + colorStop = parts[1] || ''; + } + + var result = { + color: color + }; + + if (colorStop) { + // there's position in color stop definition + colorStop.replace(/^(\-?[\d\.]+)([a-z%]+)?$/, function(str, pos, unit) { + result.position = pos; + if (~pos.indexOf('.')) { + unit = ''; + } else if (!unit) { + unit = '%'; + } + + if (unit) { + result.unit = unit; + } + }); + } + + return result; + }, + + stringify: function(options) { + options = options || {}; + var fn = 'linear-gradient'; + if (options.prefix) { + fn = '-' + options.prefix + '-' + fn; + } + + // transform color-stops + var parts = this.colorStops.map(function(cs) { + var pos = cs.position ? ' ' + cs.position + (cs.unit || '') : ''; + return cs.color + pos; + }); + + var dir = stringifyDirection(this.direction, !!options.prefix); + if (!options.omitDefaultDirection || !~defaultDirections.indexOf(dir)) { + parts.unshift(dir); + } + + return fn + '(' + parts.join(', ') + ')'; + }, + + stringifyOldWebkit: function() { + var colorStops = this.colorStops.map(function(item) { + return utils.clone(item); + }); + + // normalize color-stops position + colorStops.forEach(function(cs) { + if (!('position' in cs)) // implied position + return; + + if (~cs.position.indexOf('.') || cs.unit == '%') { + cs.position = parseFloat(cs.position) / (cs.unit == '%' ? 100 : 1); + } else { + throw "Can't convert color stop '" + (cs.position + (cs.unit || '')) + "'"; + } + }); + + this._fillImpliedPositions(colorStops); + + // transform color-stops into string representation + colorStops = colorStops.map(function(cs, i) { + if (!cs.position && !i) { + return 'from(' + cs.color + ')'; + } + + if (cs.position == 1 && i == colorStops.length - 1) { + return 'to(' + cs.color + ')'; + } + + return 'color-stop(' + (cs.position.toFixed(2).replace(/\.?0+$/, '')) + ', ' + cs.color + ')'; + }); + + return '-webkit-gradient(linear, ' + + oldWebkitDirection((this.direction + 180) % 360) + + ', ' + + colorStops.join(', ') + + ')'; + }, + + /** + * Fills-out implied positions in color-stops. This function is useful for + * old Webkit gradient definitions + */ + _fillImpliedPositions: function(colorStops) { + var from = 0; + + colorStops.forEach(function(cs, i) { + // make sure that first and last positions are defined + if (!i) { + return cs.position = cs.position || 0; + } + + if (i == colorStops.length - 1 && !('position' in cs)) { + cs.position = 1; + } + + if ('position' in cs) { + var start = colorStops[from].position || 0; + var step = (cs.position - start) / (i - from); + colorStops.slice(from, i).forEach(function(cs2, j) { + cs2.position = start + step * j; + }); + + from = i; + } + }); + }, + + valueOf: function() { + return this.stringify(); + } + }; + + function normalizeSpace(str) { + return utils.trim(str).replace(/\s+/g, ' '); + } + + /** + * Resolves textual direction to degrees + * @param {String} dir Direction to resolve + * @return {Number} + */ + function resolveDirection(dir) { + if (typeof dir == 'number') { + return dir; + } + + dir = normalizeSpace(dir).toLowerCase(); + if (reDeg.test(dir)) { + return +RegExp.$1; + } + + var prefix = /^to\s/.test(dir) ? 'to ' : ''; + var left = ~dir.indexOf('left') && 'left'; + var right = ~dir.indexOf('right') && 'right'; + var top = ~dir.indexOf('top') && 'top'; + var bottom = ~dir.indexOf('bottom') && 'bottom'; + + var key = normalizeSpace(prefix + (top || bottom || '') + ' ' + (left || right || '')); + return directions[key] || 0; + } + + /** + * Tries to find keyword for given direction, expressed in degrees + * @param {Number} dir Direction (degrees) + * @param {Boolean} oldStyle Use old style keywords (e.g. "top" instead of "to bottom") + * @return {String} Keyword or Ndeg expression + */ + function stringifyDirection(dir, oldStyle) { + var reNewStyle = /^to\s/; + var keys = Object.keys(directions).filter(function(k) { + var hasPrefix = reNewStyle.test(k); + return oldStyle ? !hasPrefix : hasPrefix; + }); + + for (var i = 0; i < keys.length; i++) { + if (directions[keys[i]] == dir) { + return keys[i]; + } + } + + if (oldStyle) { + dir = (dir + 270) % 360; + } + + return dir + 'deg'; + } + + /** + * Creates direction definition for old Webkit gradients + * @param {String} direction + * @returns {String} + */ + function oldWebkitDirection(dir) { + dir = stringifyDirection(dir, true); + + if(reDeg.test(dir)) { + throw "The direction is an angle that can’t be converted."; + } + + var v = function(pos) { + return ~dir.indexOf(pos) ? '100%' : '0'; + }; + + return v('left') + ' ' + v('top') + ', ' + v('right') + ' ' + v('bottom'); + } + + return { + /** + * Parses gradient definition into an object. + * This object can be used to transform gradient into various + * forms + * @param {String} gradient Gradient definition + * @return {LinearGradient} + */ + parse: function(gradient) { + // cut out all redundant data + if (this.isLinearGradient(gradient)) { + gradient = gradient.replace(/^\s*[\-a-z]+\s*\(|\)\s*$/ig, ''); + } else { + throw 'Invalid linear gradient definition:\n' + gradient; + } + + return new LinearGradient(gradient); + }, + + /** + * Check if given string can be parsed as linear gradient + * @param {String} str + * @return {Boolean} + */ + isLinearGradient: function(str) { + return reLinearGradient.test(str); + }, + + resolveDirection: resolveDirection, + stringifyDirection: stringifyDirection + }; +}); +},{"../../assets/stringStream":"assets/stringStream.js","../../utils/common":"utils/common.js"}],"resolver/tagName.js":[function(require,module,exports){ +/** + * Module for resolving tag names: returns best matched tag name for child + * element based on passed parent's tag name. Also provides utility function + * for element type detection (inline, block-level, empty) + */ +if (typeof module === 'object' && typeof define !== 'function') { + var define = function (factory) { + module.exports = factory(require, exports, module); + }; +} + +define(function(require, exports, module) { + var utils = require('../utils/common'); + + var elementTypes = { +// empty: 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,keygen,command'.split(','), + empty: [], + blockLevel: 'address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,link,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul,h1,h2,h3,h4,h5,h6'.split(','), + inlineLevel: 'a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'.split(',') + }; + + var elementMap = { + 'p': 'span', + 'ul': 'li', + 'ol': 'li', + 'table': 'tr', + 'tr': 'td', + 'tbody': 'tr', + 'thead': 'tr', + 'tfoot': 'tr', + 'colgroup': 'col', + 'select': 'option', + 'optgroup': 'option', + 'audio': 'source', + 'video': 'source', + 'object': 'param', + 'map': 'area' + }; + + return { + /** + * Returns best matched child element name for passed parent's + * tag name + * @param {String} name + * @returns {String} + * @memberOf tagName + */ + resolve: function(name) { + name = (name || '').toLowerCase(); + + if (name in elementMap) + return this.getMapping(name); + + if (this.isInlineLevel(name)) + return 'span'; + + return 'div'; + }, + + /** + * Returns mapped child element name for passed parent's name + * @param {String} name + * @returns {String} + */ + getMapping: function(name) { + return elementMap[name.toLowerCase()]; + }, + + /** + * Check if passed element name belongs to inline-level element + * @param {String} name + * @returns {Boolean} + */ + isInlineLevel: function(name) { + return this.isTypeOf(name, 'inlineLevel'); + }, + + /** + * Check if passed element belongs to block-level element. + * For better matching of unknown elements (for XML, for example), + * you should use !this.isInlineLevel(name) + * @returns {Boolean} + */ + isBlockLevel: function(name) { + return this.isTypeOf(name, 'blockLevel'); + }, + + /** + * Check if passed element is void (i.e. should not have closing tag). + * @returns {Boolean} + */ + isEmptyElement: function(name) { + return this.isTypeOf(name, 'empty'); + }, + + /** + * Generic function for testing if element name belongs to specified + * elements collection + * @param {String} name Element name + * @param {String} type Collection name + * @returns {Boolean} + */ + isTypeOf: function(name, type) { + return ~elementTypes[type].indexOf(name); + }, + + /** + * Adds new parent–child mapping + * @param {String} parent + * @param {String} child + */ + addMapping: function(parent, child) { + elementMap[parent] = child; + }, + + /** + * Removes parent-child mapping + */ + removeMapping: function(parent) { + if (parent in elementMap) + delete elementMap[parent]; + }, + + /** + * Adds new element into collection + * @param {String} name Element name + * @param {String} collection Collection name + */ + addElementToCollection: function(name, collection) { + if (!elementTypes[collection]) + elementTypes[collection] = []; + + var col = this.getCollection(collection); + if (!~col.indexOf(name)) { + col.push(name); + } + }, + + /** + * Removes element name from specified collection + * @param {String} name Element name + * @param {String} collection Collection name + * @returns + */ + removeElementFromCollection: function(name, collection) { + if (collection in elementTypes) { + elementTypes[collection] = utils.without(this.getCollection(collection), name); + } + }, + + /** + * Returns elements name collection + * @param {String} name Collection name + * @returns {Array} + */ + getCollection: function(name) { + return elementTypes[name]; + } + }; +}); +},{"../utils/common":"utils/common.js"}],"snippets.json":[function(require,module,exports){ +module.exports={ + "variables": { + "lang": "en", + "locale": "en-US", + "charset": "UTF-8", + "indentation": "\t", + "newline": "\n" + }, + + "css": { + "filters": "css", + "profile": "css", + "snippets": { + "@i": "@import url(|);", + "@import": "@import url(|);", + "@m": "@media ${1:screen} {\n\t|\n}", + "@media": "@media ${1:screen} {\n\t|\n}", + "@f": "@font-face {\n\tfont-family:|;\n\tsrc:url(|);\n}", + "@f+": "@font-face {\n\tfont-family: '${1:FontName}';\n\tsrc: url('${2:FileName}.eot');\n\tsrc: url('${2:FileName}.eot?#iefix') format('embedded-opentype'),\n\t\t url('${2:FileName}.woff') format('woff'),\n\t\t url('${2:FileName}.ttf') format('truetype'),\n\t\t url('${2:FileName}.svg#${1:FontName}') format('svg');\n\tfont-style: ${3:normal};\n\tfont-weight: ${4:normal};\n}", + + "@kf": "@-webkit-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-o-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-moz-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}", + + "anim": "animation:|;", + "anim-": "animation:${1:name} ${2:duration} ${3:timing-function} ${4:delay} ${5:iteration-count} ${6:direction} ${7:fill-mode};", + "animdel": "animation-delay:${1:time};", + + "animdir": "animation-direction:${1:normal};", + "animdir:n": "animation-direction:normal;", + "animdir:r": "animation-direction:reverse;", + "animdir:a": "animation-direction:alternate;", + "animdir:ar": "animation-direction:alternate-reverse;", + + "animdur": "animation-duration:${1:0}s;", + + "animfm": "animation-fill-mode:${1:both};", + "animfm:f": "animation-fill-mode:forwards;", + "animfm:b": "animation-fill-mode:backwards;", + "animfm:bt": "animation-fill-mode:both;", + "animfm:bh": "animation-fill-mode:both;", + + "animic": "animation-iteration-count:${1:1};", + "animic:i": "animation-iteration-count:infinite;", + + "animn": "animation-name:${1:none};", + + "animps": "animation-play-state:${1:running};", + "animps:p": "animation-play-state:paused;", + "animps:r": "animation-play-state:running;", + + "animtf": "animation-timing-function:${1:linear};", + "animtf:e": "animation-timing-function:ease;", + "animtf:ei": "animation-timing-function:ease-in;", + "animtf:eo": "animation-timing-function:ease-out;", + "animtf:eio": "animation-timing-function:ease-in-out;", + "animtf:l": "animation-timing-function:linear;", + "animtf:cb": "animation-timing-function:cubic-bezier(${1:0.1}, ${2:0.7}, ${3:1.0}, ${3:0.1});", + + "ap": "appearance:${none};", + + "!": "!important", + "pos": "position:${1:relative};", + "pos:s": "position:static;", + "pos:a": "position:absolute;", + "pos:r": "position:relative;", + "pos:f": "position:fixed;", + "t": "top:|;", + "t:a": "top:auto;", + "r": "right:|;", + "r:a": "right:auto;", + "b": "bottom:|;", + "b:a": "bottom:auto;", + "l": "left:|;", + "l:a": "left:auto;", + "z": "z-index:|;", + "z:a": "z-index:auto;", + "fl": "float:${1:left};", + "fl:n": "float:none;", + "fl:l": "float:left;", + "fl:r": "float:right;", + "cl": "clear:${1:both};", + "cl:n": "clear:none;", + "cl:l": "clear:left;", + "cl:r": "clear:right;", + "cl:b": "clear:both;", + + "colm": "columns:|;", + "colmc": "column-count:|;", + "colmf": "column-fill:|;", + "colmg": "column-gap:|;", + "colmr": "column-rule:|;", + "colmrc": "column-rule-color:|;", + "colmrs": "column-rule-style:|;", + "colmrw": "column-rule-width:|;", + "colms": "column-span:|;", + "colmw": "column-width:|;", + + "d": "display:${1:block};", + "d:n": "display:none;", + "d:b": "display:block;", + "d:f": "display:flex;", + "d:if": "display:inline-flex;", + "d:i": "display:inline;", + "d:ib": "display:inline-block;", + "d:ib+": "display: inline-block;\n*display: inline;\n*zoom: 1;", + "d:li": "display:list-item;", + "d:ri": "display:run-in;", + "d:cp": "display:compact;", + "d:tb": "display:table;", + "d:itb": "display:inline-table;", + "d:tbcp": "display:table-caption;", + "d:tbcl": "display:table-column;", + "d:tbclg": "display:table-column-group;", + "d:tbhg": "display:table-header-group;", + "d:tbfg": "display:table-footer-group;", + "d:tbr": "display:table-row;", + "d:tbrg": "display:table-row-group;", + "d:tbc": "display:table-cell;", + "d:rb": "display:ruby;", + "d:rbb": "display:ruby-base;", + "d:rbbg": "display:ruby-base-group;", + "d:rbt": "display:ruby-text;", + "d:rbtg": "display:ruby-text-group;", + "v": "visibility:${1:hidden};", + "v:v": "visibility:visible;", + "v:h": "visibility:hidden;", + "v:c": "visibility:collapse;", + "ov": "overflow:${1:hidden};", + "ov:v": "overflow:visible;", + "ov:h": "overflow:hidden;", + "ov:s": "overflow:scroll;", + "ov:a": "overflow:auto;", + "ovx": "overflow-x:${1:hidden};", + "ovx:v": "overflow-x:visible;", + "ovx:h": "overflow-x:hidden;", + "ovx:s": "overflow-x:scroll;", + "ovx:a": "overflow-x:auto;", + "ovy": "overflow-y:${1:hidden};", + "ovy:v": "overflow-y:visible;", + "ovy:h": "overflow-y:hidden;", + "ovy:s": "overflow-y:scroll;", + "ovy:a": "overflow-y:auto;", + "ovs": "overflow-style:${1:scrollbar};", + "ovs:a": "overflow-style:auto;", + "ovs:s": "overflow-style:scrollbar;", + "ovs:p": "overflow-style:panner;", + "ovs:m": "overflow-style:move;", + "ovs:mq": "overflow-style:marquee;", + "zoo": "zoom:1;", + "zm": "zoom:1;", + "cp": "clip:|;", + "cp:a": "clip:auto;", + "cp:r": "clip:rect(${1:top} ${2:right} ${3:bottom} ${4:left});", + "bxz": "box-sizing:${1:border-box};", + "bxz:cb": "box-sizing:content-box;", + "bxz:bb": "box-sizing:border-box;", + "bxsh": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:color};", + "bxsh:r": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:spread }rgb(${6:0}, ${7:0}, ${8:0});", + "bxsh:ra": "box-shadow:${1:inset }${2:h} ${3:v} ${4:blur} ${5:spread }rgba(${6:0}, ${7:0}, ${8:0}, .${9:5});", + "bxsh:n": "box-shadow:none;", + "m": "margin:|;", + "m:a": "margin:auto;", + "mt": "margin-top:|;", + "mt:a": "margin-top:auto;", + "mr": "margin-right:|;", + "mr:a": "margin-right:auto;", + "mb": "margin-bottom:|;", + "mb:a": "margin-bottom:auto;", + "ml": "margin-left:|;", + "ml:a": "margin-left:auto;", + "p": "padding:|;", + "pt": "padding-top:|;", + "pr": "padding-right:|;", + "pb": "padding-bottom:|;", + "pl": "padding-left:|;", + "w": "width:|;", + "w:a": "width:auto;", + "h": "height:|;", + "h:a": "height:auto;", + "maw": "max-width:|;", + "maw:n": "max-width:none;", + "mah": "max-height:|;", + "mah:n": "max-height:none;", + "miw": "min-width:|;", + "mih": "min-height:|;", + "mar": "max-resolution:${1:res};", + "mir": "min-resolution:${1:res};", + "ori": "orientation:|;", + "ori:l": "orientation:landscape;", + "ori:p": "orientation:portrait;", + "ol": "outline:|;", + "ol:n": "outline:none;", + "olo": "outline-offset:|;", + "olw": "outline-width:|;", + "olw:tn": "outline-width:thin;", + "olw:m": "outline-width:medium;", + "olw:tc": "outline-width:thick;", + "ols": "outline-style:|;", + "ols:n": "outline-style:none;", + "ols:dt": "outline-style:dotted;", + "ols:ds": "outline-style:dashed;", + "ols:s": "outline-style:solid;", + "ols:db": "outline-style:double;", + "ols:g": "outline-style:groove;", + "ols:r": "outline-style:ridge;", + "ols:i": "outline-style:inset;", + "ols:o": "outline-style:outset;", + "olc": "outline-color:#${1:000};", + "olc:i": "outline-color:invert;", + "bfv": "backface-visibility:|;", + "bfv:h": "backface-visibility:hidden;", + "bfv:v": "backface-visibility:visible;", + "bd": "border:|;", + "bd+": "border:${1:1px} ${2:solid} ${3:#000};", + "bd:n": "border:none;", + "bdbk": "border-break:${1:close};", + "bdbk:c": "border-break:close;", + "bdcl": "border-collapse:|;", + "bdcl:c": "border-collapse:collapse;", + "bdcl:s": "border-collapse:separate;", + "bdc": "border-color:#${1:000};", + "bdc:t": "border-color:transparent;", + "bdi": "border-image:url(|);", + "bdi:n": "border-image:none;", + "bdti": "border-top-image:url(|);", + "bdti:n": "border-top-image:none;", + "bdri": "border-right-image:url(|);", + "bdri:n": "border-right-image:none;", + "bdbi": "border-bottom-image:url(|);", + "bdbi:n": "border-bottom-image:none;", + "bdli": "border-left-image:url(|);", + "bdli:n": "border-left-image:none;", + "bdci": "border-corner-image:url(|);", + "bdci:n": "border-corner-image:none;", + "bdci:c": "border-corner-image:continue;", + "bdtli": "border-top-left-image:url(|);", + "bdtli:n": "border-top-left-image:none;", + "bdtli:c": "border-top-left-image:continue;", + "bdtri": "border-top-right-image:url(|);", + "bdtri:n": "border-top-right-image:none;", + "bdtri:c": "border-top-right-image:continue;", + "bdbri": "border-bottom-right-image:url(|);", + "bdbri:n": "border-bottom-right-image:none;", + "bdbri:c": "border-bottom-right-image:continue;", + "bdbli": "border-bottom-left-image:url(|);", + "bdbli:n": "border-bottom-left-image:none;", + "bdbli:c": "border-bottom-left-image:continue;", + "bdf": "border-fit:${1:repeat};", + "bdf:c": "border-fit:clip;", + "bdf:r": "border-fit:repeat;", + "bdf:sc": "border-fit:scale;", + "bdf:st": "border-fit:stretch;", + "bdf:ow": "border-fit:overwrite;", + "bdf:of": "border-fit:overflow;", + "bdf:sp": "border-fit:space;", + "bdlen": "border-length:|;", + "bdlen:a": "border-length:auto;", + "bdsp": "border-spacing:|;", + "bds": "border-style:|;", + "bds:n": "border-style:none;", + "bds:h": "border-style:hidden;", + "bds:dt": "border-style:dotted;", + "bds:ds": "border-style:dashed;", + "bds:s": "border-style:solid;", + "bds:db": "border-style:double;", + "bds:dtds": "border-style:dot-dash;", + "bds:dtdtds": "border-style:dot-dot-dash;", + "bds:w": "border-style:wave;", + "bds:g": "border-style:groove;", + "bds:r": "border-style:ridge;", + "bds:i": "border-style:inset;", + "bds:o": "border-style:outset;", + "bdw": "border-width:|;", + "bdtw": "border-top-width:|;", + "bdrw": "border-right-width:|;", + "bdbw": "border-bottom-width:|;", + "bdlw": "border-left-width:|;", + "bdt": "border-top:|;", + "bt": "border-top:|;", + "bdt+": "border-top:${1:1px} ${2:solid} ${3:#000};", + "bdt:n": "border-top:none;", + "bdts": "border-top-style:|;", + "bdts:n": "border-top-style:none;", + "bdtc": "border-top-color:#${1:000};", + "bdtc:t": "border-top-color:transparent;", + "bdr": "border-right:|;", + "br": "border-right:|;", + "bdr+": "border-right:${1:1px} ${2:solid} ${3:#000};", + "bdr:n": "border-right:none;", + "bdrst": "border-right-style:|;", + "bdrst:n": "border-right-style:none;", + "bdrc": "border-right-color:#${1:000};", + "bdrc:t": "border-right-color:transparent;", + "bdb": "border-bottom:|;", + "bb": "border-bottom:|;", + "bdb+": "border-bottom:${1:1px} ${2:solid} ${3:#000};", + "bdb:n": "border-bottom:none;", + "bdbs": "border-bottom-style:|;", + "bdbs:n": "border-bottom-style:none;", + "bdbc": "border-bottom-color:#${1:000};", + "bdbc:t": "border-bottom-color:transparent;", + "bdl": "border-left:|;", + "bl": "border-left:|;", + "bdl+": "border-left:${1:1px} ${2:solid} ${3:#000};", + "bdl:n": "border-left:none;", + "bdls": "border-left-style:|;", + "bdls:n": "border-left-style:none;", + "bdlc": "border-left-color:#${1:000};", + "bdlc:t": "border-left-color:transparent;", + "bdrs": "border-radius:|;", + "bdtrrs": "border-top-right-radius:|;", + "bdtlrs": "border-top-left-radius:|;", + "bdbrrs": "border-bottom-right-radius:|;", + "bdblrs": "border-bottom-left-radius:|;", + "bg": "background:#${1:000};", + "bg+": "background:${1:#fff} url(${2}) ${3:0} ${4:0} ${5:no-repeat};", + "bg:n": "background:none;", + "bg:ie": "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${1:x}.png',sizingMethod='${2:crop}');", + "bgc": "background-color:#${1:fff};", + "bgc:t": "background-color:transparent;", + "bgi": "background-image:url(|);", + "bgi:n": "background-image:none;", + "bgr": "background-repeat:|;", + "bgr:n": "background-repeat:no-repeat;", + "bgr:x": "background-repeat:repeat-x;", + "bgr:y": "background-repeat:repeat-y;", + "bgr:sp": "background-repeat:space;", + "bgr:rd": "background-repeat:round;", + "bga": "background-attachment:|;", + "bga:f": "background-attachment:fixed;", + "bga:s": "background-attachment:scroll;", + "bgp": "background-position:${1:0} ${2:0};", + "bgpx": "background-position-x:|;", + "bgpy": "background-position-y:|;", + "bgbk": "background-break:|;", + "bgbk:bb": "background-break:bounding-box;", + "bgbk:eb": "background-break:each-box;", + "bgbk:c": "background-break:continuous;", + "bgcp": "background-clip:${1:padding-box};", + "bgcp:bb": "background-clip:border-box;", + "bgcp:pb": "background-clip:padding-box;", + "bgcp:cb": "background-clip:content-box;", + "bgcp:nc": "background-clip:no-clip;", + "bgo": "background-origin:|;", + "bgo:pb": "background-origin:padding-box;", + "bgo:bb": "background-origin:border-box;", + "bgo:cb": "background-origin:content-box;", + "bgsz": "background-size:|;", + "bgsz:a": "background-size:auto;", + "bgsz:ct": "background-size:contain;", + "bgsz:cv": "background-size:cover;", + "c": "color:#${1:000};", + "c:r": "color:rgb(${1:0}, ${2:0}, ${3:0});", + "c:ra": "color:rgba(${1:0}, ${2:0}, ${3:0}, .${4:5});", + "cm": "/* |${child} */", + "cnt": "content:'|';", + "cnt:n": "content:normal;", + "cnt:oq": "content:open-quote;", + "cnt:noq": "content:no-open-quote;", + "cnt:cq": "content:close-quote;", + "cnt:ncq": "content:no-close-quote;", + "cnt:a": "content:attr(|);", + "cnt:c": "content:counter(|);", + "cnt:cs": "content:counters(|);", + + "tbl": "table-layout:|;", + "tbl:a": "table-layout:auto;", + "tbl:f": "table-layout:fixed;", + "cps": "caption-side:|;", + "cps:t": "caption-side:top;", + "cps:b": "caption-side:bottom;", + "ec": "empty-cells:|;", + "ec:s": "empty-cells:show;", + "ec:h": "empty-cells:hide;", + "lis": "list-style:|;", + "lis:n": "list-style:none;", + "lisp": "list-style-position:|;", + "lisp:i": "list-style-position:inside;", + "lisp:o": "list-style-position:outside;", + "list": "list-style-type:|;", + "list:n": "list-style-type:none;", + "list:d": "list-style-type:disc;", + "list:c": "list-style-type:circle;", + "list:s": "list-style-type:square;", + "list:dc": "list-style-type:decimal;", + "list:dclz": "list-style-type:decimal-leading-zero;", + "list:lr": "list-style-type:lower-roman;", + "list:ur": "list-style-type:upper-roman;", + "lisi": "list-style-image:|;", + "lisi:n": "list-style-image:none;", + "q": "quotes:|;", + "q:n": "quotes:none;", + "q:ru": "quotes:'\\00AB' '\\00BB' '\\201E' '\\201C';", + "q:en": "quotes:'\\201C' '\\201D' '\\2018' '\\2019';", + "ct": "content:|;", + "ct:n": "content:normal;", + "ct:oq": "content:open-quote;", + "ct:noq": "content:no-open-quote;", + "ct:cq": "content:close-quote;", + "ct:ncq": "content:no-close-quote;", + "ct:a": "content:attr(|);", + "ct:c": "content:counter(|);", + "ct:cs": "content:counters(|);", + "coi": "counter-increment:|;", + "cor": "counter-reset:|;", + "va": "vertical-align:${1:top};", + "va:sup": "vertical-align:super;", + "va:t": "vertical-align:top;", + "va:tt": "vertical-align:text-top;", + "va:m": "vertical-align:middle;", + "va:bl": "vertical-align:baseline;", + "va:b": "vertical-align:bottom;", + "va:tb": "vertical-align:text-bottom;", + "va:sub": "vertical-align:sub;", + "ta": "text-align:${1:left};", + "ta:l": "text-align:left;", + "ta:c": "text-align:center;", + "ta:r": "text-align:right;", + "ta:j": "text-align:justify;", + "ta-lst": "text-align-last:|;", + "tal:a": "text-align-last:auto;", + "tal:l": "text-align-last:left;", + "tal:c": "text-align-last:center;", + "tal:r": "text-align-last:right;", + "td": "text-decoration:${1:none};", + "td:n": "text-decoration:none;", + "td:u": "text-decoration:underline;", + "td:o": "text-decoration:overline;", + "td:l": "text-decoration:line-through;", + "te": "text-emphasis:|;", + "te:n": "text-emphasis:none;", + "te:ac": "text-emphasis:accent;", + "te:dt": "text-emphasis:dot;", + "te:c": "text-emphasis:circle;", + "te:ds": "text-emphasis:disc;", + "te:b": "text-emphasis:before;", + "te:a": "text-emphasis:after;", + "th": "text-height:|;", + "th:a": "text-height:auto;", + "th:f": "text-height:font-size;", + "th:t": "text-height:text-size;", + "th:m": "text-height:max-size;", + "ti": "text-indent:|;", + "ti:-": "text-indent:-9999px;", + "tj": "text-justify:|;", + "tj:a": "text-justify:auto;", + "tj:iw": "text-justify:inter-word;", + "tj:ii": "text-justify:inter-ideograph;", + "tj:ic": "text-justify:inter-cluster;", + "tj:d": "text-justify:distribute;", + "tj:k": "text-justify:kashida;", + "tj:t": "text-justify:tibetan;", + "tov": "text-overflow:${ellipsis};", + "tov:e": "text-overflow:ellipsis;", + "tov:c": "text-overflow:clip;", + "to": "text-outline:|;", + "to+": "text-outline:${1:0} ${2:0} ${3:#000};", + "to:n": "text-outline:none;", + "tr": "text-replace:|;", + "tr:n": "text-replace:none;", + "tt": "text-transform:${1:uppercase};", + "tt:n": "text-transform:none;", + "tt:c": "text-transform:capitalize;", + "tt:u": "text-transform:uppercase;", + "tt:l": "text-transform:lowercase;", + "tw": "text-wrap:|;", + "tw:n": "text-wrap:normal;", + "tw:no": "text-wrap:none;", + "tw:u": "text-wrap:unrestricted;", + "tw:s": "text-wrap:suppress;", + "tsh": "text-shadow:${1:hoff} ${2:voff} ${3:blur} ${4:#000};", + "tsh:r": "text-shadow:${1:h} ${2:v} ${3:blur} rgb(${4:0}, ${5:0}, ${6:0});", + "tsh:ra": "text-shadow:${1:h} ${2:v} ${3:blur} rgba(${4:0}, ${5:0}, ${6:0}, .${7:5});", + "tsh+": "text-shadow:${1:0} ${2:0} ${3:0} ${4:#000};", + "tsh:n": "text-shadow:none;", + "trf": "transform:|;", + "trf:skx": "transform: skewX(${1:angle});", + "trf:sky": "transform: skewY(${1:angle});", + "trf:sc": "transform: scale(${1:x}, ${2:y});", + "trf:scx": "transform: scaleX(${1:x});", + "trf:scy": "transform: scaleY(${1:y});", + "trf:scz": "transform: scaleZ(${1:z});", + "trf:sc3": "transform: scale3d(${1:x}, ${2:y}, ${3:z});", + "trf:r": "transform: rotate(${1:angle});", + "trf:rx": "transform: rotateX(${1:angle});", + "trf:ry": "transform: rotateY(${1:angle});", + "trf:rz": "transform: rotateZ(${1:angle});", + "trf:t": "transform: translate(${1:x}, ${2:y});", + "trf:tx": "transform: translateX(${1:x});", + "trf:ty": "transform: translateY(${1:y});", + "trf:tz": "transform: translateZ(${1:z});", + "trf:t3": "transform: translate3d(${1:tx}, ${2:ty}, ${3:tz});", + "trfo": "transform-origin:|;", + "trfs": "transform-style:${1:preserve-3d};", + "trs": "transition:${1:prop} ${2:time};", + "trsde": "transition-delay:${1:time};", + "trsdu": "transition-duration:${1:time};", + "trsp": "transition-property:${1:prop};", + "trstf": "transition-timing-function:${1:tfunc};", + "lh": "line-height:|;", + "whs": "white-space:|;", + "whs:n": "white-space:normal;", + "whs:p": "white-space:pre;", + "whs:nw": "white-space:nowrap;", + "whs:pw": "white-space:pre-wrap;", + "whs:pl": "white-space:pre-line;", + "whsc": "white-space-collapse:|;", + "whsc:n": "white-space-collapse:normal;", + "whsc:k": "white-space-collapse:keep-all;", + "whsc:l": "white-space-collapse:loose;", + "whsc:bs": "white-space-collapse:break-strict;", + "whsc:ba": "white-space-collapse:break-all;", + "wob": "word-break:|;", + "wob:n": "word-break:normal;", + "wob:k": "word-break:keep-all;", + "wob:ba": "word-break:break-all;", + "wos": "word-spacing:|;", + "wow": "word-wrap:|;", + "wow:nm": "word-wrap:normal;", + "wow:n": "word-wrap:none;", + "wow:u": "word-wrap:unrestricted;", + "wow:s": "word-wrap:suppress;", + "wow:b": "word-wrap:break-word;", + "wm": "writing-mode:${1:lr-tb};", + "wm:lrt": "writing-mode:lr-tb;", + "wm:lrb": "writing-mode:lr-bt;", + "wm:rlt": "writing-mode:rl-tb;", + "wm:rlb": "writing-mode:rl-bt;", + "wm:tbr": "writing-mode:tb-rl;", + "wm:tbl": "writing-mode:tb-lr;", + "wm:btl": "writing-mode:bt-lr;", + "wm:btr": "writing-mode:bt-rl;", + "lts": "letter-spacing:|;", + "lts-n": "letter-spacing:normal;", + "f": "font:|;", + "f+": "font:${1:1em} ${2:Arial,sans-serif};", + "fw": "font-weight:|;", + "fw:n": "font-weight:normal;", + "fw:b": "font-weight:bold;", + "fw:br": "font-weight:bolder;", + "fw:lr": "font-weight:lighter;", + "fs": "font-style:${italic};", + "fs:n": "font-style:normal;", + "fs:i": "font-style:italic;", + "fs:o": "font-style:oblique;", + "fv": "font-variant:|;", + "fv:n": "font-variant:normal;", + "fv:sc": "font-variant:small-caps;", + "fz": "font-size:|;", + "fza": "font-size-adjust:|;", + "fza:n": "font-size-adjust:none;", + "ff": "font-family:|;", + "ff:s": "font-family:serif;", + "ff:ss": "font-family:sans-serif;", + "ff:c": "font-family:cursive;", + "ff:f": "font-family:fantasy;", + "ff:m": "font-family:monospace;", + "ff:a": "font-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;", + "ff:t": "font-family: \"Times New Roman\", Times, Baskerville, Georgia, serif;", + "ff:v": "font-family: Verdana, Geneva, sans-serif;", + "fef": "font-effect:|;", + "fef:n": "font-effect:none;", + "fef:eg": "font-effect:engrave;", + "fef:eb": "font-effect:emboss;", + "fef:o": "font-effect:outline;", + "fem": "font-emphasize:|;", + "femp": "font-emphasize-position:|;", + "femp:b": "font-emphasize-position:before;", + "femp:a": "font-emphasize-position:after;", + "fems": "font-emphasize-style:|;", + "fems:n": "font-emphasize-style:none;", + "fems:ac": "font-emphasize-style:accent;", + "fems:dt": "font-emphasize-style:dot;", + "fems:c": "font-emphasize-style:circle;", + "fems:ds": "font-emphasize-style:disc;", + "fsm": "font-smooth:|;", + "fsm:a": "font-smooth:auto;", + "fsm:n": "font-smooth:never;", + "fsm:aw": "font-smooth:always;", + "fst": "font-stretch:|;", + "fst:n": "font-stretch:normal;", + "fst:uc": "font-stretch:ultra-condensed;", + "fst:ec": "font-stretch:extra-condensed;", + "fst:c": "font-stretch:condensed;", + "fst:sc": "font-stretch:semi-condensed;", + "fst:se": "font-stretch:semi-expanded;", + "fst:e": "font-stretch:expanded;", + "fst:ee": "font-stretch:extra-expanded;", + "fst:ue": "font-stretch:ultra-expanded;", + "op": "opacity:|;", + "op+": "opacity: $1;\nfilter: alpha(opacity=$2);", + "op:ie": "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);", + "op:ms": "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';", + "rsz": "resize:|;", + "rsz:n": "resize:none;", + "rsz:b": "resize:both;", + "rsz:h": "resize:horizontal;", + "rsz:v": "resize:vertical;", + "cur": "cursor:${pointer};", + "cur:a": "cursor:auto;", + "cur:d": "cursor:default;", + "cur:c": "cursor:crosshair;", + "cur:ha": "cursor:hand;", + "cur:he": "cursor:help;", + "cur:m": "cursor:move;", + "cur:p": "cursor:pointer;", + "cur:t": "cursor:text;", + "fxd": "flex-direction:|;", + "fxd:r": "flex-direction:row;", + "fxd:rr": "flex-direction:row-reverse;", + "fxd:c": "flex-direction:column;", + "fxd:cr": "flex-direction:column-reverse;", + "fxw": "flex-wrap: |;", + "fxw:n": "flex-wrap:nowrap;", + "fxw:w": "flex-wrap:wrap;", + "fxw:wr": "flex-wrap:wrap-reverse;", + "fxf": "flex-flow:|;", + "jc": "justify-content:|;", + "jc:fs": "justify-content:flex-start;", + "jc:fe": "justify-content:flex-end;", + "jc:c": "justify-content:center;", + "jc:sb": "justify-content:space-between;", + "jc:sa": "justify-content:space-around;", + "ai": "align-items:|;", + "ai:fs": "align-items:flex-start;", + "ai:fe": "align-items:flex-end;", + "ai:c": "align-items:center;", + "ai:b": "align-items:baseline;", + "ai:s": "align-items:stretch;", + "ac": "align-content:|;", + "ac:fs": "align-content:flex-start;", + "ac:fe": "align-content:flex-end;", + "ac:c": "align-content:center;", + "ac:sb": "align-content:space-between;", + "ac:sa": "align-content:space-around;", + "ac:s": "align-content:stretch;", + "ord": "order:|;", + "fxg": "flex-grow:|;", + "fxsh": "flex-shrink:|;", + "fxb": "flex-basis:|;", + "fx": "flex:|;", + "as": "align-self:|;", + "as:a": "align-self:auto;", + "as:fs": "align-self:flex-start;", + "as:fe": "align-self:flex-end;", + "as:c": "align-self:center;", + "as:b": "align-self:baseline;", + "as:s": "align-self:stretch;", + "pgbb": "page-break-before:|;", + "pgbb:au": "page-break-before:auto;", + "pgbb:al": "page-break-before:always;", + "pgbb:l": "page-break-before:left;", + "pgbb:r": "page-break-before:right;", + "pgbi": "page-break-inside:|;", + "pgbi:au": "page-break-inside:auto;", + "pgbi:av": "page-break-inside:avoid;", + "pgba": "page-break-after:|;", + "pgba:au": "page-break-after:auto;", + "pgba:al": "page-break-after:always;", + "pgba:l": "page-break-after:left;", + "pgba:r": "page-break-after:right;", + "orp": "orphans:|;", + "us": "user-select:${none};", + "wid": "widows:|;", + "wfsm": "-webkit-font-smoothing:${antialiased};", + "wfsm:a": "-webkit-font-smoothing:antialiased;", + "wfsm:s": "-webkit-font-smoothing:subpixel-antialiased;", + "wfsm:sa": "-webkit-font-smoothing:subpixel-antialiased;", + "wfsm:n": "-webkit-font-smoothing:none;" + } + }, + + "html": { + "filters": "html", + "profile": "html", + "snippets": { + "!!!": "", + "!!!4t": "", + "!!!4s": "", + "!!!xt": "", + "!!!xs": "", + "!!!xxs": "", + + "c": "", + "cc:ie6": "", + "cc:ie": "", + "cc:noie": "\n\t${child}|\n" + }, + + "abbreviations": { + "!": "html:5", + "a": "", + "a:link": "", + "a:mail": "", + "abbr": "", + "acr|acronym": "", + "base": "", + "basefont": "", + "br": "
", + "frame": "", + "hr": "
", + "bdo": "", + "bdo:r": "", + "bdo:l": "", + "col": "", + "link": "", + "link:css": "", + "link:print": "", + "link:favicon": "", + "link:touch": "", + "link:rss": "", + "link:atom": "", + "link:im|link:import": "", + "meta": "", + "meta:utf": "", + "meta:win": "", + "meta:vp": "", + "meta:compat": "", + "style": "