From 5ec20c793a478d4f7ceed23f170715eca72175e0 Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 13:50:24 -0800 Subject: [PATCH 01/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/23c7f5bc5406 Author: David Flanagan Desc: Merge pull request #13393 from davidflanagan/bug915001 Merge pull request #13300 from davidflanagan/bug915001hd ======== https://hg.mozilla.org/integration/gaia-central/rev/1c8b364321f5 Author: David Flanagan Desc: Merge pull request #13300 from davidflanagan/bug915001hd Bug 915001 - save edited images using tiles and display a progress bar r=hshih(cherry picked from commit d19550e2fb7331d5e4a54e8e998753378e7fd44a) Conflicts: apps/gallery/index.html apps/gallery/js/ImageEditor.js fix lint --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 5528d86cb36..79c96f512c9 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "fe012cdbca542f414a72b0cba9cfb50a4aaf62ae", + "revision": "23c7f5bc5406fda54714286917693dd45ae2428a", "repo_path": "/integration/gaia-central" } From b05d840edc67771f54351936c2205cd8253e4cc0 Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 14:00:25 -0800 Subject: [PATCH 02/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/32137585357b Author: Bob Silverberg Desc: Merge pull request #13387 from zacc/bug_935052_phone bug 935052 - fall back to top-most frame after closing call in dialer te... ======== https://hg.mozilla.org/integration/gaia-central/rev/23c37e4351af Author: Zac Campbell Desc: bug 935052 - fall back to top-most frame after closing call in dialer tests --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 79c96f512c9..bd083bdf609 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "23c7f5bc5406fda54714286917693dd45ae2428a", + "revision": "32137585357bdd255676c852199cf47e8caf8147", "repo_path": "/integration/gaia-central" } From 7fc47e7db3179ddc33f97e5a4fd98d9bb34f26bc Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 14:25:24 -0800 Subject: [PATCH 03/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/d29ac061b001 Author: Ran Ben Aharon Desc: Merge pull request #13369 from EverythingMe/v1.2-apikey Bug 934768 - [e.me] API key change for v1.2 [r=crdlc] ======== https://hg.mozilla.org/integration/gaia-central/rev/7f4206970f84 Author: Ran Ben Aharon Desc: Bug 934768 - [e.me] API key change for v1.2 [r=crdlc] --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index bd083bdf609..5b1bf1824d7 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "32137585357bdd255676c852199cf47e8caf8147", + "revision": "d29ac061b00125419d1864836101a97503306d1d", "repo_path": "/integration/gaia-central" } From 21fbf0c03285514a53a063aeb4da106ad6bd4c7e Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 18:30:29 -0800 Subject: [PATCH 04/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/5b8850486f3c Author: Luke Chang Desc: Merge pull request #13222 from luke-chang/919370_unit_test_for_pinyin Bug 919370 - [Test][Keyboard] Unit test for Pinyin IME, r=rudylu ======== https://hg.mozilla.org/integration/gaia-central/rev/24e14352a81a Author: Luke Chang Desc: Bug 919370 - [Test][Keyboard] Unit test for Pinyin IME - also modified the latin and suggest unit test to prevent the conflict of global variables --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 5b1bf1824d7..593b9a7482a 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "d29ac061b00125419d1864836101a97503306d1d", + "revision": "5b8850486f3ce31ea3650cb1ada6d3c221dbf6cf", "repo_path": "/integration/gaia-central" } From 4486903fa61e917b476b0fee06d5717b68a44765 Mon Sep 17 00:00:00 2001 From: Gene Lian Date: Tue, 5 Nov 2013 21:50:38 +0800 Subject: [PATCH 05/53] Bug 927711 - B2G MMS : Handle message delivered timestamp for delivery report (part 1, DOM API IDL). r=hsinyi --- dom/mobilemessage/interfaces/nsIDOMMozMmsMessage.idl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dom/mobilemessage/interfaces/nsIDOMMozMmsMessage.idl b/dom/mobilemessage/interfaces/nsIDOMMozMmsMessage.idl index e096f2e605d..e054fcb9b88 100644 --- a/dom/mobilemessage/interfaces/nsIDOMMozMmsMessage.idl +++ b/dom/mobilemessage/interfaces/nsIDOMMozMmsMessage.idl @@ -19,9 +19,11 @@ dictionary MmsDeliveryInfo { DOMString? receiver; DOMString? deliveryStatus; + jsval deliveryTimestamp; // Date object; null if not available (e.g., + // |delivery| = "received" or not yet delivered). }; -[scriptable, builtinclass, uuid(85bfc639-0d8f-43fa-8c12-6bd2958bf219)] +[scriptable, builtinclass, uuid(3593c914-420a-11e3-a297-a3bdd768257f)] interface nsIDOMMozMmsMessage : nsISupports { /** From 5ce683eca90765974b24a12add20764fbc20380b Mon Sep 17 00:00:00 2001 From: Gene Lian Date: Wed, 6 Nov 2013 10:30:25 +0800 Subject: [PATCH 06/53] Bug 927711 - B2G MMS : Handle message delivered timestamp for delivery report (part 2, implementation). r=ctai --- dom/mobilemessage/src/MmsMessage.cpp | 37 +++++++++++++++++++ dom/mobilemessage/src/gonk/MmsService.js | 26 ++++++------- .../src/gonk/MobileMessageDatabaseService.js | 26 ++++++++++++- dom/mobilemessage/src/ipc/SmsTypes.ipdlh | 1 + 4 files changed, 75 insertions(+), 15 deletions(-) diff --git a/dom/mobilemessage/src/MmsMessage.cpp b/dom/mobilemessage/src/MmsMessage.cpp index 2c6815f73b3..9650eaccfa6 100644 --- a/dom/mobilemessage/src/MmsMessage.cpp +++ b/dom/mobilemessage/src/MmsMessage.cpp @@ -15,6 +15,7 @@ #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType #include "mozilla/dom/mobilemessage/SmsTypes.h" #include "nsDOMFile.h" +#include "nsCxPusher.h" using namespace mozilla::idl; using namespace mozilla::dom::mobilemessage; @@ -100,8 +101,11 @@ MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData) for (uint32_t i = 0; i < len; i++) { MmsDeliveryInfo info; const MmsDeliveryInfoData &infoData = aData.deliveryInfo()[i]; + + // Prepare |info.receiver|. info.receiver = infoData.receiver(); + // Prepare |info.deliveryStatus|. nsString statusStr; switch (infoData.deliveryStatus()) { case eDeliveryStatus_NotApplicable: @@ -127,6 +131,20 @@ MmsMessage::MmsMessage(const mobilemessage::MmsMessageData& aData) MOZ_CRASH("We shouldn't get any other delivery status!"); } info.deliveryStatus = statusStr; + + // Prepare |info.deliveryTimestamp|. + info.deliveryTimestamp = JSVAL_NULL; + if (infoData.deliveryTimestamp() != 0) { + AutoJSContext cx; + JS::Rooted + dateObj(cx, JS_NewDateObjectMsec(cx, infoData.deliveryTimestamp())); + if (!dateObj) { + NS_WARNING("MmsMessage: Unable to create Date for deliveryTimestamp."); + } else { + info.deliveryTimestamp = OBJECT_TO_JSVAL(dateObj); + } + } + mDeliveryInfo.AppendElement(info); } } @@ -327,8 +345,11 @@ MmsMessage::GetData(ContentParent* aParent, for (uint32_t i = 0; i < mDeliveryInfo.Length(); i++) { MmsDeliveryInfoData infoData; const MmsDeliveryInfo &info = mDeliveryInfo[i]; + + // Prepare |infoData.receiver|. infoData.receiver().Assign(info.receiver); + // Prepare |infoData.deliveryStatus|. DeliveryStatus status; if (info.deliveryStatus.Equals(DELIVERY_STATUS_NOT_APPLICABLE)) { status = eDeliveryStatus_NotApplicable; @@ -346,6 +367,15 @@ MmsMessage::GetData(ContentParent* aParent, return false; } infoData.deliveryStatus() = status; + + // Prepare |infoData.deliveryTimestamp|. + if (info.deliveryTimestamp == JSVAL_NULL) { + infoData.deliveryTimestamp() = 0; + } else { + AutoJSContext cx; + convertTimeToInt(cx, info.deliveryTimestamp, infoData.deliveryTimestamp()); + } + aData.deliveryInfo().AppendElement(infoData); } @@ -484,6 +514,13 @@ MmsMessage::GetDeliveryInfo(JSContext* aCx, JS::Value* aDeliveryInfo) return NS_ERROR_FAILURE; } + // Get |info.deliveryTimestamp|. + if (!JS_DefineProperty(aCx, infoJsObj, + "deliveryTimestamp", info.deliveryTimestamp, + NULL, NULL, JSPROP_ENUMERATE)) { + return NS_ERROR_FAILURE; + } + tmpJsVal = OBJECT_TO_JSVAL(infoJsObj); if (!JS_SetElement(aCx, deliveryInfo, i, &tmpJsVal)) { return NS_ERROR_FAILURE; diff --git a/dom/mobilemessage/src/gonk/MmsService.js b/dom/mobilemessage/src/gonk/MmsService.js index e610de53b88..24d0d0ec17a 100644 --- a/dom/mobilemessage/src/gonk/MmsService.js +++ b/dom/mobilemessage/src/gonk/MmsService.js @@ -1544,19 +1544,19 @@ MmsService.prototype = { // because the system message mechamism will rewrap the object // based on the content window, which needs to know the properties. gSystemMessenger.broadcastMessage(aName, { - type: aDomMessage.type, - id: aDomMessage.id, - threadId: aDomMessage.threadId, - delivery: aDomMessage.delivery, - deliveryInfo: aDomMessage.deliveryInfo, - sender: aDomMessage.sender, - receivers: aDomMessage.receivers, - timestamp: aDomMessage.timestamp, - read: aDomMessage.read, - subject: aDomMessage.subject, - smil: aDomMessage.smil, - attachments: aDomMessage.attachments, - expiryDate: aDomMessage.expiryDate + type: aDomMessage.type, + id: aDomMessage.id, + threadId: aDomMessage.threadId, + delivery: aDomMessage.delivery, + deliveryInfo: aDomMessage.deliveryInfo, + sender: aDomMessage.sender, + receivers: aDomMessage.receivers, + timestamp: aDomMessage.timestamp, + read: aDomMessage.read, + subject: aDomMessage.subject, + smil: aDomMessage.smil, + attachments: aDomMessage.attachments, + expiryDate: aDomMessage.expiryDate }); }, diff --git a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js index 9a47fb33563..e5e91e2fa57 100644 --- a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js +++ b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js @@ -1588,7 +1588,7 @@ MobileMessageDatabaseService.prototype = { if (messageRecord.deliveryStatus != deliveryStatus) { messageRecord.deliveryStatus = deliveryStatus; - // Update the delivery timestamp if it's successfully delivered. + // Update |deliveryTimestamp| if it's successfully delivered. if (deliveryStatus == DELIVERY_STATUS_SUCCESS) { messageRecord.deliveryTimestamp = Date.now(); } @@ -1601,6 +1601,12 @@ MobileMessageDatabaseService.prototype = { for (let i = 0; i < deliveryInfo.length; i++) { if (deliveryInfo[i].deliveryStatus != deliveryStatus) { deliveryInfo[i].deliveryStatus = deliveryStatus; + + // Update |deliveryTimestamp| if it's successfully delivered. + if (deliveryStatus == DELIVERY_STATUS_SUCCESS) { + deliveryInfo[i].deliveryTimestamp = Date.now(); + } + isRecordUpdated = true; } } @@ -1655,6 +1661,12 @@ MobileMessageDatabaseService.prototype = { } if (deliveryInfo[j].deliveryStatus != deliveryStatus) { deliveryInfo[j].deliveryStatus = deliveryStatus; + + // Update |deliveryTimestamp| if it's successfully delivered. + if (deliveryStatus == DELIVERY_STATUS_SUCCESS) { + deliveryInfo[j].deliveryTimestamp = Date.now(); + } + isRecordUpdated = true; } } @@ -1765,6 +1777,14 @@ MobileMessageDatabaseService.prototype = { if (aMessage.type == "mms") { aMessage.transactionIdIndex = aMessage.transactionId; aMessage.isReadReportSent = false; + + // If |deliveryTimestamp| is not specified, use 0 as default. + let deliveryInfo = aMessage.deliveryInfo; + for (let i = 0; i < deliveryInfo.length; i++) { + if (deliveryInfo[i].deliveryTimestamp == undefined) { + deliveryInfo[i].deliveryTimestamp = 0; + } + } } if (aMessage.type == "sms") { @@ -1818,7 +1838,9 @@ MobileMessageDatabaseService.prototype = { aMessage.deliveryInfo = []; for (let i = 0; i < receivers.length; i++) { aMessage.deliveryInfo.push({ - receiver: receivers[i], deliveryStatus: deliveryStatus }); + receiver: receivers[i], + deliveryStatus: deliveryStatus, + deliveryTimestamp: 0 }); } } diff --git a/dom/mobilemessage/src/ipc/SmsTypes.ipdlh b/dom/mobilemessage/src/ipc/SmsTypes.ipdlh index 24cb173e4c9..5a53846f5dd 100644 --- a/dom/mobilemessage/src/ipc/SmsTypes.ipdlh +++ b/dom/mobilemessage/src/ipc/SmsTypes.ipdlh @@ -50,6 +50,7 @@ struct MmsDeliveryInfoData { nsString receiver; DeliveryStatus deliveryStatus; + uint64_t deliveryTimestamp; }; struct MmsMessageData From 3d8450994dd4c32bd58fb745b30ca4f0d1d21fea Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 18:55:23 -0800 Subject: [PATCH 07/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/6489f84d8564 Author: gasolin Desc: Merge pull request #13051 from gasolin/issue-917367 Bug 917367 - No notification visible indicator implemented for when getU..., r=alive ======== https://hg.mozilla.org/integration/gaia-central/rev/2d636b01ef55 Author: gasolin Desc: Bug 917367 - No notification visible indicator implemented for when getUserMedia audio is active --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 593b9a7482a..345ad299f72 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "5b8850486f3ce31ea3650cb1ada6d3c221dbf6cf", + "revision": "6489f84d85645253962cb0197df693d63e9a42e6", "repo_path": "/integration/gaia-central" } From d4256d98acc78f6bb41a67cc0e7bd825b6e2f277 Mon Sep 17 00:00:00 2001 From: Reuben Morais Date: Wed, 6 Nov 2013 01:32:42 -0200 Subject: [PATCH 08/53] Backed out 4 changesets (bug 853356) for breaking permission prompts. --- b2g/components/ContentPermissionPrompt.js | 244 +++++------------- browser/components/nsBrowserGlue.js | 16 +- .../metro/base/content/helperui/IndexedDB.js | 4 +- .../components/ContentPermissionPrompt.js | 28 +- content/base/src/nsDocument.cpp | 16 +- dom/apps/src/PermissionsTable.jsm | 5 - dom/base/nsContentPermissionHelper.cpp | 215 +++++---------- dom/base/nsContentPermissionHelper.h | 67 ++--- dom/devicestorage/nsDeviceStorage.cpp | 45 ++-- .../base/nsIContentPermissionPrompt.idl | 24 +- dom/ipc/PBrowser.ipdl | 9 +- dom/ipc/PContentPermission.ipdlh | 14 - dom/ipc/TabChild.cpp | 8 +- dom/ipc/TabChild.h | 6 +- dom/ipc/TabParent.cpp | 6 +- dom/ipc/TabParent.h | 3 +- dom/ipc/moz.build | 1 - dom/media/MediaManager.cpp | 37 +-- dom/media/MediaManager.h | 4 +- dom/media/MediaPermissionGonk.cpp | 78 ++---- dom/media/tests/mochitest/Makefile.in | 6 - .../test_getUserMedia_permission.html | 77 ------ dom/src/geolocation/nsGeolocation.cpp | 22 +- dom/src/notification/DesktopNotification.cpp | 22 +- dom/src/notification/Notification.cpp | 23 +- .../components/ContentPermissionPrompt.js | 24 +- .../content/MockPermissionPrompt.jsm | 32 +-- webapprt/ContentPermission.js | 28 +- 28 files changed, 343 insertions(+), 721 deletions(-) delete mode 100644 dom/ipc/PContentPermission.ipdlh delete mode 100644 dom/media/tests/mochitest/test_getUserMedia_permission.html diff --git a/b2g/components/ContentPermissionPrompt.js b/b2g/components/ContentPermissionPrompt.js index 05ed5c01880..0b163cbd44f 100644 --- a/b2g/components/ContentPermissionPrompt.js +++ b/b2g/components/ContentPermissionPrompt.js @@ -5,7 +5,7 @@ "use strict" function debug(str) { - //dump("-*- ContentPermissionPrompt: " + str + "\n"); + //dump("-*- ContentPermissionPrompt: " + s + "\n"); } const Ci = Components.interfaces; @@ -13,14 +13,11 @@ const Cr = Components.results; const Cu = Components.utils; const Cc = Components.classes; -const PROMPT_FOR_UNKNOWN = ["audio-capture", - "desktop-notification", - "geolocation", - "video-capture"]; +const PROMPT_FOR_UNKNOWN = ["geolocation", "desktop-notification", + "audio-capture"]; // Due to privary issue, permission requests like GetUserMedia should prompt // every time instead of providing session persistence. -const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"]; -const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"]; +const PERMISSION_NO_SESSION = ["audio-capture"]; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); @@ -44,21 +41,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "@mozilla.org/telephony/audiomanager;1", "nsIAudioManager"); -/** - * aTypesInfo is an array of {permission, access, action, deny} which keeps - * the information of each permission. This arrary is initialized in - * ContentPermissionPrompt.prompt and used among functions. - * - * aTypesInfo[].permission : permission name - * aTypesInfo[].access : permission name + request.access - * aTypesInfo[].action : the default action of this permission - * aTypesInfo[].deny : true if security manager denied this app's origin - * principal. - * Note: - * aTypesInfo[].permission will be sent to prompt only when - * aTypesInfo[].action is PROMPT_ACTION and aTypesInfo[].deny is false. - */ -function rememberPermission(aTypesInfo, aPrincipal, aSession) +function rememberPermission(aPermission, aPrincipal, aSession) { function convertPermToAllow(aPerm, aPrincipal) { @@ -66,13 +49,12 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession) permissionManager.testExactPermissionFromPrincipal(aPrincipal, aPerm); if (type == Ci.nsIPermissionManager.PROMPT_ACTION || (type == Ci.nsIPermissionManager.UNKNOWN_ACTION && - PROMPT_FOR_UNKNOWN.indexOf(aPerm) >= 0)) { - debug("add " + aPerm + " to permission manager with ALLOW_ACTION"); + PROMPT_FOR_UNKNOWN.indexOf(aPermission) >= 0)) { if (!aSession) { permissionManager.addFromPrincipal(aPrincipal, aPerm, Ci.nsIPermissionManager.ALLOW_ACTION); - } else if (PERMISSION_NO_SESSION.indexOf(aPerm) < 0) { + } else if (PERMISSION_NO_SESSION.indexOf(aPermission) < 0) { permissionManager.addFromPrincipal(aPrincipal, aPerm, Ci.nsIPermissionManager.ALLOW_ACTION, @@ -81,18 +63,14 @@ function rememberPermission(aTypesInfo, aPrincipal, aSession) } } - for (let i in aTypesInfo) { - // Expand the permission to see if we have multiple access properties - // to convert - let perm = aTypesInfo[i].permission; - let access = PermissionsTable[perm].access; - if (access) { - for (let idx in access) { - convertPermToAllow(perm + "-" + access[idx], aPrincipal); - } - } else { - convertPermToAllow(perm, aPrincipal); + // Expand the permission to see if we have multiple access properties to convert + let access = PermissionsTable[aPermission].access; + if (access) { + for (let idx in access) { + convertPermToAllow(aPermission + "-" + access[idx], aPrincipal); } + } else { + convertPermToAllow(aPermission, aPrincipal); } } @@ -100,63 +78,23 @@ function ContentPermissionPrompt() {} ContentPermissionPrompt.prototype = { - handleExistingPermission: function handleExistingPermission(request, - typesInfo) { - typesInfo.forEach(function(type) { - type.action = - Services.perms.testExactPermissionFromPrincipal(request.principal, - type.access); - }); - - // If all permissions are allowed already, call allow() without prompting. - let checkAllowPermission = function(type) { - if (type.action == Ci.nsIPermissionManager.ALLOW_ACTION) { - return true; - } - return false; - } - if (typesInfo.every(checkAllowPermission)) { - debug("all permission requests are allowed"); + handleExistingPermission: function handleExistingPermission(request) { + let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access : + request.type; + let result = Services.perms.testExactPermissionFromPrincipal(request.principal, access); + if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { request.allow(); return true; } - - // If all permissions are DENY_ACTION or UNKNOWN_ACTION, call cancel() - // without prompting. - let checkDenyPermission = function(type) { - if (type.action == Ci.nsIPermissionManager.DENY_ACTION || - type.action == Ci.nsIPermissionManager.UNKNOWN_ACTION && - PROMPT_FOR_UNKNOWN.indexOf(type.access) < 0) { - return true; - } - return false; - } - if (typesInfo.every(checkDenyPermission)) { - debug("all permission requests are denied"); + if (result == Ci.nsIPermissionManager.DENY_ACTION || + result == Ci.nsIPermissionManager.UNKNOWN_ACTION && PROMPT_FOR_UNKNOWN.indexOf(access) < 0) { request.cancel(); return true; } return false; }, - // multiple requests should be audio and video - checkMultipleRequest: function checkMultipleRequest(typesInfo) { - if (typesInfo.length == 1) { - return true; - } else if (typesInfo.length > 1) { - let checkIfAllowMultiRequest = function(type) { - return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1); - } - if (typesInfo.every(checkIfAllowMultiRequest)) { - debug("legal multiple requests"); - return true; - } - } - - return false; - }, - - handledByApp: function handledByApp(request, typesInfo) { + handledByApp: function handledByApp(request) { if (request.principal.appId == Ci.nsIScriptSecurityManager.NO_APP_ID || request.principal.appId == Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID) { // This should not really happen @@ -168,94 +106,49 @@ ContentPermissionPrompt.prototype = { .getService(Ci.nsIAppsService); let app = appsService.getAppByLocalId(request.principal.appId); - // Check each permission if it's denied by permission manager with app's - // URL. - let checkIfDenyAppPrincipal = function(type) { - let url = Services.io.newURI(app.origin, null, null); - let principal = secMan.getAppCodebasePrincipal(url, - request.principal.appId, - /*mozbrowser*/false); - let result = Services.perms.testExactPermissionFromPrincipal(principal, - type.access); + let url = Services.io.newURI(app.origin, null, null); + let principal = secMan.getAppCodebasePrincipal(url, request.principal.appId, + /*mozbrowser*/false); + let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access : + request.type; + let result = Services.perms.testExactPermissionFromPrincipal(principal, access); - if (result == Ci.nsIPermissionManager.ALLOW_ACTION || - result == Ci.nsIPermissionManager.PROMPT_ACTION) { - type.deny = false; - } - return type.deny; - } - if (typesInfo.every(checkIfDenyAppPrincipal)) { - request.cancel(); - return true; + if (result == Ci.nsIPermissionManager.ALLOW_ACTION || + result == Ci.nsIPermissionManager.PROMPT_ACTION) { + return false; } - return false; + request.cancel(); + return true; }, - handledByPermissionType: function handledByPermissionType(request, typesInfo) { - for (let i in typesInfo) { - if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) && - permissionSpecificChecker[typesInfo[i].permission](request)) { - return true; - } - } - - return false; + handledByPermissionType: function handledByPermissionType(request) { + return permissionSpecificChecker.hasOwnProperty(request.type) + ? permissionSpecificChecker[request.type](request) + : false; }, _id: 0, prompt: function(request) { if (secMan.isSystemPrincipal(request.principal)) { request.allow(); - return; + return true; } - // Initialize the typesInfo and set the default value. - let typesInfo = []; - let perms = request.types.QueryInterface(Ci.nsIArray); - for (let idx = 0; idx < perms.length; idx++) { - let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType); - let tmp = { - permission: perm.type, - access: (perm.access && perm.access !== "unused") ? - perm.type + "-" + perm.access : perm.type, - deny: true, - action: Ci.nsIPermissionManager.UNKNOWN_ACTION - }; - typesInfo.push(tmp); - } - if (typesInfo.length == 0) { - request.cancel(); - return; - } - - if(!this.checkMultipleRequest(typesInfo)) { - request.cancel(); - return; - } - - if (this.handledByApp(request, typesInfo) || - this.handledByPermissionType(request, typesInfo)) { + if (this.handledByApp(request) || + this.handledByPermissionType(request)) { return; } // returns true if the request was handled - if (this.handleExistingPermission(request, typesInfo)) { + if (this.handleExistingPermission(request)) return; - } - - // prompt PROMPT_ACTION request only. - typesInfo.forEach(function(aType, aIndex) { - if (aType.action != Ci.nsIPermissionManager.PROMPT_ACTION || aType.deny) { - typesInfo.splice(aIndex); - } - }); let frame = request.element; let requestId = this._id++; if (!frame) { - this.delegatePrompt(request, requestId, typesInfo); + this.delegatePrompt(request, requestId); return; } @@ -270,7 +163,7 @@ ContentPermissionPrompt.prototype = { if (evt.detail.visible === true) return; - self.cancelPrompt(request, requestId, typesInfo); + self.cancelPrompt(request, requestId); cancelRequest(); } @@ -287,7 +180,7 @@ ContentPermissionPrompt.prototype = { // away but the request is still here. frame.addEventListener("mozbrowservisibilitychange", onVisibilityChange); - self.delegatePrompt(request, requestId, typesInfo, function onCallback() { + self.delegatePrompt(request, requestId, function onCallback() { frame.removeEventListener("mozbrowservisibilitychange", onVisibilityChange); }); }; @@ -298,17 +191,22 @@ ContentPermissionPrompt.prototype = { } }, - cancelPrompt: function(request, requestId, typesInfo) { - this.sendToBrowserWindow("cancel-permission-prompt", request, requestId, - typesInfo); + cancelPrompt: function(request, requestId) { + this.sendToBrowserWindow("cancel-permission-prompt", request, requestId); }, - delegatePrompt: function(request, requestId, typesInfo, callback) { + delegatePrompt: function(request, requestId, callback) { + let access = (request.access && request.access !== "unused") ? request.type + "-" + request.access : + request.type; + let principal = request.principal; - this.sendToBrowserWindow("permission-prompt", request, requestId, typesInfo, - function(type, remember) { + this._permission = access; + this._uri = principal.URI.spec; + this._origin = principal.origin; + + this.sendToBrowserWindow("permission-prompt", request, requestId, function(type, remember) { if (type == "permission-allow") { - rememberPermission(typesInfo, request.principal, !remember); + rememberPermission(request.type, principal, !remember); if (callback) { callback(); } @@ -316,20 +214,14 @@ ContentPermissionPrompt.prototype = { return; } - let addDenyPermission = function(type) { - debug("add " + type.permission + - " to permission manager with DENY_ACTION"); - if (remember) { - Services.perms.addFromPrincipal(request.principal, type.access, - Ci.nsIPermissionManager.DENY_ACTION); - } else { - Services.perms.addFromPrincipal(request.principal, type.access, - Ci.nsIPermissionManager.DENY_ACTION, - Ci.nsIPermissionManager.EXPIRE_SESSION, - 0); - } + if (remember) { + Services.perms.addFromPrincipal(principal, access, + Ci.nsIPermissionManager.DENY_ACTION); + } else { + Services.perms.addFromPrincipal(principal, access, + Ci.nsIPermissionManager.DENY_ACTION, + Ci.nsIPermissionManager.EXPIRE_SESSION, 0); } - typesInfo.forEach(addDenyPermission); if (callback) { callback(); @@ -338,7 +230,7 @@ ContentPermissionPrompt.prototype = { }); }, - sendToBrowserWindow: function(type, request, requestId, typesInfo, callback) { + sendToBrowserWindow: function(type, request, requestId, callback) { let browser = Services.wm.getMostRecentWindow("navigator:browser"); let content = browser.getContentWindow(); if (!content) @@ -361,15 +253,10 @@ ContentPermissionPrompt.prototype = { principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED) ? true : request.remember; - let permissions = []; - for (let i in typesInfo) { - debug("prompt " + typesInfo[i].permission); - permissions.push(typesInfo[i].permission); - } let details = { type: type, - permissions: permissions, + permission: request.type, id: requestId, origin: principal.origin, isApp: isApp, @@ -402,5 +289,6 @@ ContentPermissionPrompt.prototype = { }; })(); + //module initialization this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]); diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index efb5425a62f..839fe0460ab 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -1995,21 +1995,13 @@ ContentPermissionPrompt.prototype = { prompt: function CPP_prompt(request) { - // Only allow exactly one permission rquest here. - let types = request.types.QueryInterface(Ci.nsIArray); - if (types.length != 1) { - request.cancel(); - return; - } - let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); - const kFeatureKeys = { "geolocation" : "geo", "desktop-notification" : "desktop-notification", "pointerLock" : "pointerLock", }; // Make sure that we support the request. - if (!(perm.type in kFeatureKeys)) { + if (!(request.type in kFeatureKeys)) { return; } @@ -2021,7 +2013,7 @@ ContentPermissionPrompt.prototype = { return; var autoAllow = false; - var permissionKey = kFeatureKeys[perm.type]; + var permissionKey = kFeatureKeys[request.type]; var result = Services.perms.testExactPermissionFromPrincipal(requestingPrincipal, permissionKey); if (result == Ci.nsIPermissionManager.DENY_ACTION) { @@ -2032,14 +2024,14 @@ ContentPermissionPrompt.prototype = { if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { autoAllow = true; // For pointerLock, we still want to show a warning prompt. - if (perm.type != "pointerLock") { + if (request.type != "pointerLock") { request.allow(); return; } } // Show the prompt. - switch (perm.type) { + switch (request.type) { case "geolocation": this._promptGeo(request); break; diff --git a/browser/metro/base/content/helperui/IndexedDB.js b/browser/metro/base/content/helperui/IndexedDB.js index c62fc4734da..8c347ab5e36 100644 --- a/browser/metro/base/content/helperui/IndexedDB.js +++ b/browser/metro/base/content/helperui/IndexedDB.js @@ -44,8 +44,6 @@ let IndexedDB = { } let prompt = Cc["@mozilla.org/content-permission/prompt;1"].createInstance(Ci.nsIContentPermissionPrompt); - let types = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - types.appendElement({type: type, access: "unused"}, false); // If the user waits a long time before responding, we default to UNKNOWN_ACTION. let timeoutId = setTimeout(function() { @@ -62,7 +60,7 @@ let IndexedDB = { } prompt.prompt({ - types: types, + type: type, uri: Services.io.newURI(payload.location, null, null), window: null, element: aMessage.target, diff --git a/browser/metro/components/ContentPermissionPrompt.js b/browser/metro/components/ContentPermissionPrompt.js index c6ac9f5a589..44a69c2d566 100644 --- a/browser/metro/components/ContentPermissionPrompt.js +++ b/browser/metro/components/ContentPermissionPrompt.js @@ -56,8 +56,8 @@ ContentPermissionPrompt.prototype = { return chromeWin.Browser.getNotificationBox(request.element); }, - handleExistingPermission: function handleExistingPermission(request, type) { - let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type); + handleExistingPermission: function handleExistingPermission(request) { + let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type); if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { request.allow(); return true; @@ -70,28 +70,20 @@ ContentPermissionPrompt.prototype = { }, prompt: function(request) { - // Only allow exactly one permission rquest here. - let types = request.types.QueryInterface(Ci.nsIArray); - if (types.length != 1) { - request.cancel(); - return; - } - let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); - // returns true if the request was handled - if (this.handleExistingPermission(request, perm.type)) + if (this.handleExistingPermission(request)) return; let pm = Services.perms; let notificationBox = this.getNotificationBoxForRequest(request); let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); - let notification = notificationBox.getNotificationWithValue(perm.type); + let notification = notificationBox.getNotificationWithValue(request.type); if (notification) return; - let entityName = kEntities[perm.type]; - let icon = kIcons[perm.type] || ""; + let entityName = kEntities[request.type]; + let icon = kIcons[request.type] || ""; let buttons = [{ label: browserBundle.GetStringFromName(entityName + ".allow"), @@ -104,7 +96,7 @@ ContentPermissionPrompt.prototype = { label: browserBundle.GetStringFromName("contentPermissions.alwaysForSite"), accessKey: "", callback: function(notification) { - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION); request.allow(); } }, @@ -112,7 +104,7 @@ ContentPermissionPrompt.prototype = { label: browserBundle.GetStringFromName("contentPermissions.neverForSite"), accessKey: "", callback: function(notification) { - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION); request.cancel(); } }]; @@ -120,12 +112,12 @@ ContentPermissionPrompt.prototype = { let message = browserBundle.formatStringFromName(entityName + ".wantsTo", [request.principal.URI.host], 1); let newBar = notificationBox.appendNotification(message, - perm.type, + request.type, icon, notificationBox.PRIORITY_WARNING_MEDIUM, buttons); - if (perm.type == "geolocation") { + if (request.type == "geolocation") { // Add the "learn more" link. let link = newBar.ownerDocument.createElement("label"); link.setAttribute("value", browserBundle.GetStringFromName("geolocation.learnMore")); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 096542ec948..d4e7f1e0d9d 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -215,8 +215,6 @@ #include "mozilla/dom/XPathEvaluator.h" #include "nsIDocumentEncoder.h" #include "nsIStructuredCloneContainer.h" -#include "nsIMutableArray.h" -#include "nsContentPermissionHelper.h" using namespace mozilla; using namespace mozilla::dom; @@ -10649,11 +10647,17 @@ NS_IMPL_ISUPPORTS_INHERITED1(nsPointerLockPermissionRequest, nsIContentPermissionRequest) NS_IMETHODIMP -nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes) +nsPointerLockPermissionRequest::GetType(nsACString& aType) { - return CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aType = "pointerLock"; + return NS_OK; +} + +NS_IMETHODIMP +nsPointerLockPermissionRequest::GetAccess(nsACString& aAccess) +{ + aAccess = "unused"; + return NS_OK; } NS_IMETHODIMP diff --git a/dom/apps/src/PermissionsTable.jsm b/dom/apps/src/PermissionsTable.jsm index d78a696fbc0..86643af14cc 100644 --- a/dom/apps/src/PermissionsTable.jsm +++ b/dom/apps/src/PermissionsTable.jsm @@ -302,11 +302,6 @@ this.PermissionsTable = { geolocation: { privileged: PROMPT_ACTION, certified: PROMPT_ACTION }, - "video-capture": { - app: PROMPT_ACTION, - privileged: PROMPT_ACTION, - certified: PROMPT_ACTION - }, }; /** diff --git a/dom/base/nsContentPermissionHelper.cpp b/dom/base/nsContentPermissionHelper.cpp index 50510512970..b4b3c87dca5 100644 --- a/dom/base/nsContentPermissionHelper.cpp +++ b/dom/base/nsContentPermissionHelper.cpp @@ -2,155 +2,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "nsContentPermissionHelper.h" +#include "nsIContentPermissionPrompt.h" #include "nsCOMPtr.h" #include "nsIDOMElement.h" #include "nsIPrincipal.h" #include "mozilla/dom/Element.h" -#include "mozilla/dom/PContentPermission.h" -#include "mozilla/dom/PermissionMessageUtils.h" -#include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/dom/TabParent.h" #include "mozilla/unused.h" #include "nsComponentManagerUtils.h" -#include "nsArrayUtils.h" -#include "nsIMutableArray.h" -#include "nsContentPermissionHelper.h" using mozilla::unused; // using namespace mozilla::dom; -namespace mozilla { -namespace dom { - -class ContentPermissionRequestParent : public PContentPermissionRequestParent -{ - public: - ContentPermissionRequestParent(const nsTArray& aRequests, - Element* element, - const IPC::Principal& principal); - virtual ~ContentPermissionRequestParent(); - - bool IsBeingDestroyed(); - - nsCOMPtr mPrincipal; - nsCOMPtr mElement; - nsCOMPtr mProxy; - nsTArray mRequests; - - private: - virtual bool Recvprompt(); - virtual void ActorDestroy(ActorDestroyReason why); -}; - -ContentPermissionRequestParent::ContentPermissionRequestParent(const nsTArray& aRequests, - Element* aElement, - const IPC::Principal& aPrincipal) -{ - MOZ_COUNT_CTOR(ContentPermissionRequestParent); - - mPrincipal = aPrincipal; - mElement = aElement; - mRequests = aRequests; -} - -ContentPermissionRequestParent::~ContentPermissionRequestParent() -{ - MOZ_COUNT_DTOR(ContentPermissionRequestParent); -} - -bool -ContentPermissionRequestParent::Recvprompt() -{ - mProxy = new nsContentPermissionRequestProxy(); - NS_ASSERTION(mProxy, "Alloc of request proxy failed"); - if (NS_FAILED(mProxy->Init(mRequests, this))) { - mProxy->Cancel(); - } - return true; -} - -void -ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) -{ - if (mProxy) { - mProxy->OnParentDestroyed(); - } -} - -bool -ContentPermissionRequestParent::IsBeingDestroyed() -{ - // When TabParent::Destroy() is called, we are being destroyed. It's unsafe - // to send out any message now. - TabParent* tabParent = static_cast(Manager()); - return tabParent->IsDestroyed(); -} - -NS_IMPL_ISUPPORTS1(ContentPermissionType, nsIContentPermissionType) - -ContentPermissionType::ContentPermissionType(const nsACString& aType, - const nsACString& aAccess) -{ - mType = aType; - mAccess = aAccess; -} - -ContentPermissionType::~ContentPermissionType() -{ -} - -NS_IMETHODIMP -ContentPermissionType::GetType(nsACString& aType) -{ - aType = mType; - return NS_OK; -} - -NS_IMETHODIMP -ContentPermissionType::GetAccess(nsACString& aAccess) -{ - aAccess = mAccess; - return NS_OK; -} - -uint32_t -ConvertPermissionRequestToArray(nsTArray& aSrcArray, - nsIMutableArray* aDesArray) -{ - uint32_t len = aSrcArray.Length(); - for (uint32_t i = 0; i < len; i++) { - nsRefPtr cpt = - new ContentPermissionType(aSrcArray[i].type(), aSrcArray[i].access()); - aDesArray->AppendElement(cpt, false); - } - return len; -} - -nsresult -CreatePermissionArray(const nsACString& aType, - const nsACString& aAccess, - nsIArray** aTypesArray) -{ - nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - nsRefPtr permType = new ContentPermissionType(aType, - aAccess); - types->AppendElement(permType, false); - types.forget(aTypesArray); - - return NS_OK; -} - -PContentPermissionRequestParent* -CreateContentPermissionRequestParent(const nsTArray& aRequests, - Element* element, - const IPC::Principal& principal) -{ - return new ContentPermissionRequestParent(aRequests, element, principal); -} - -} // namespace dom -} // namespace mozilla - nsContentPermissionRequestProxy::nsContentPermissionRequestProxy() { MOZ_COUNT_CTOR(nsContentPermissionRequestProxy); @@ -162,12 +26,14 @@ nsContentPermissionRequestProxy::~nsContentPermissionRequestProxy() } nsresult -nsContentPermissionRequestProxy::Init(const nsTArray& requests, +nsContentPermissionRequestProxy::Init(const nsACString & type, + const nsACString & access, ContentPermissionRequestParent* parent) { NS_ASSERTION(parent, "null parent"); mParent = parent; - mPermissionRequests = requests; + mType = type; + mAccess = access; nsCOMPtr prompt = do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID); if (!prompt) { @@ -187,14 +53,17 @@ nsContentPermissionRequestProxy::OnParentDestroyed() NS_IMPL_ISUPPORTS1(nsContentPermissionRequestProxy, nsIContentPermissionRequest) NS_IMETHODIMP -nsContentPermissionRequestProxy::GetTypes(nsIArray** aTypes) +nsContentPermissionRequestProxy::GetType(nsACString & aType) { - nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - if (ConvertPermissionRequestToArray(mPermissionRequests, types)) { - types.forget(aTypes); - return NS_OK; - } - return NS_ERROR_FAILURE; + aType = mType; + return NS_OK; +} + +NS_IMETHODIMP +nsContentPermissionRequestProxy::GetAccess(nsACString & aAccess) +{ + aAccess = mAccess; + return NS_OK; } NS_IMETHODIMP @@ -265,3 +134,55 @@ nsContentPermissionRequestProxy::Allow() mParent = nullptr; return NS_OK; } + +namespace mozilla { +namespace dom { + +ContentPermissionRequestParent::ContentPermissionRequestParent(const nsACString& aType, + const nsACString& aAccess, + Element* aElement, + const IPC::Principal& aPrincipal) +{ + MOZ_COUNT_CTOR(ContentPermissionRequestParent); + + mPrincipal = aPrincipal; + mElement = aElement; + mType = aType; + mAccess = aAccess; +} + +ContentPermissionRequestParent::~ContentPermissionRequestParent() +{ + MOZ_COUNT_DTOR(ContentPermissionRequestParent); +} + +bool +ContentPermissionRequestParent::Recvprompt() +{ + mProxy = new nsContentPermissionRequestProxy(); + NS_ASSERTION(mProxy, "Alloc of request proxy failed"); + if (NS_FAILED(mProxy->Init(mType, mAccess, this))) { + mProxy->Cancel(); + } + return true; +} + +void +ContentPermissionRequestParent::ActorDestroy(ActorDestroyReason why) +{ + if (mProxy) { + mProxy->OnParentDestroyed(); + } +} + +bool +ContentPermissionRequestParent::IsBeingDestroyed() +{ + // When TabParent::Destroy() is called, we are being destroyed. It's unsafe + // to send out any message now. + TabParent* tabParent = static_cast(Manager()); + return tabParent->IsDestroyed(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/nsContentPermissionHelper.h b/dom/base/nsContentPermissionHelper.h index 1baf2768b92..9a750c6efb5 100644 --- a/dom/base/nsContentPermissionHelper.h +++ b/dom/base/nsContentPermissionHelper.h @@ -6,75 +6,60 @@ #define nsContentPermissionHelper_h #include "nsIContentPermissionPrompt.h" -#include "nsTArray.h" -#include "nsIMutableArray.h" +#include "nsString.h" + +#include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/dom/PContentPermissionRequestParent.h" class nsContentPermissionRequestProxy; -// Forward declare IPC::Principal here which is defined in -// PermissionMessageUtils.h. Include this file will transitively includes -// "windows.h" and it defines -// #define CreateEvent CreateEventW -// #define LoadImage LoadImageW -// That will mess up windows build. -namespace IPC { -class Principal; -} - namespace mozilla { namespace dom { class Element; -class PermissionRequest; -class ContentPermissionRequestParent; -class PContentPermissionRequestParent; -class ContentPermissionType : public nsIContentPermissionType +class ContentPermissionRequestParent : public PContentPermissionRequestParent { -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTPERMISSIONTYPE + public: + ContentPermissionRequestParent(const nsACString& type, + const nsACString& access, + Element* element, + const IPC::Principal& principal); + virtual ~ContentPermissionRequestParent(); - ContentPermissionType(const nsACString& aType, const nsACString& aAccess); - virtual ~ContentPermissionType(); + bool IsBeingDestroyed(); -protected: + nsCOMPtr mPrincipal; + nsCOMPtr mElement; + nsCOMPtr mProxy; nsCString mType; nsCString mAccess; + + private: + virtual bool Recvprompt(); + virtual void ActorDestroy(ActorDestroyReason why); }; -uint32_t ConvertPermissionRequestToArray(nsTArray& aSrcArray, - nsIMutableArray* aDesArray); - -nsresult CreatePermissionArray(const nsACString& aType, - const nsACString& aAccess, - nsIArray** aTypesArray); - -PContentPermissionRequestParent* -CreateContentPermissionRequestParent(const nsTArray& aRequests, - Element* element, - const IPC::Principal& principal); - } // namespace dom } // namespace mozilla class nsContentPermissionRequestProxy : public nsIContentPermissionRequest { public: - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTPERMISSIONREQUEST - nsContentPermissionRequestProxy(); virtual ~nsContentPermissionRequestProxy(); - nsresult Init(const nsTArray& requests, - mozilla::dom::ContentPermissionRequestParent* parent); + nsresult Init(const nsACString& type, const nsACString& access, mozilla::dom::ContentPermissionRequestParent* parent); void OnParentDestroyed(); + NS_DECL_ISUPPORTS + NS_DECL_NSICONTENTPERMISSIONREQUEST + private: // Non-owning pointer to the ContentPermissionRequestParent object which owns this proxy. mozilla::dom::ContentPermissionRequestParent* mParent; - nsTArray mPermissionRequests; + nsCString mType; + nsCString mAccess; }; - #endif // nsContentPermissionHelper_h + diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index 5659fb0176a..9c503523e25 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -49,7 +49,6 @@ #include "nsIStringBundle.h" #include "nsIDocument.h" #include -#include "nsContentPermissionHelper.h" #include "mozilla/dom/DeviceStorageBinding.h" @@ -1696,14 +1695,17 @@ nsDOMDeviceStorageCursor::GetStorageType(nsAString & aType) } NS_IMETHODIMP -nsDOMDeviceStorageCursor::GetTypes(nsIArray** aTypes) +nsDOMDeviceStorageCursor::GetType(nsACString & aType) { - nsCString type; - nsresult rv = - DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); - NS_ENSURE_SUCCESS(rv, rv); + return DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, + aType); +} - return CreatePermissionArray(type, NS_LITERAL_CSTRING("read"), aTypes); +NS_IMETHODIMP +nsDOMDeviceStorageCursor::GetAccess(nsACString & aAccess) +{ + aAccess = NS_LITERAL_CSTRING("read"); + return NS_OK; } NS_IMETHODIMP @@ -2178,10 +2180,8 @@ public: if (NS_FAILED(rv)) { return rv; } - nsTArray permArray; - permArray.AppendElement(PermissionRequest(type, access)); child->SendPContentPermissionRequestConstructor( - this, permArray, IPC::Principal(mPrincipal)); + this, type, access, IPC::Principal(mPrincipal)); Sendprompt(); return NS_OK; @@ -2195,23 +2195,26 @@ public: return NS_OK; } - NS_IMETHODIMP GetTypes(nsIArray** aTypes) + NS_IMETHOD GetType(nsACString & aType) { nsCString type; - nsresult rv = - DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, type); + nsresult rv + = DeviceStorageTypeChecker::GetPermissionForType(mFile->mStorageType, + aType); if (NS_FAILED(rv)) { return rv; } + return NS_OK; + } - nsCString access; - rv = DeviceStorageTypeChecker::GetAccessForRequest( - DeviceStorageRequestType(mRequestType), access); + NS_IMETHOD GetAccess(nsACString & aAccess) + { + nsresult rv = DeviceStorageTypeChecker::GetAccessForRequest( + DeviceStorageRequestType(mRequestType), aAccess); if (NS_FAILED(rv)) { return rv; } - - return CreatePermissionArray(type, access, aTypes); + return NS_OK; } NS_IMETHOD GetPrincipal(nsIPrincipal * *aRequestingPrincipal) @@ -3188,10 +3191,8 @@ nsDOMDeviceStorage::EnumerateInternal(const nsAString& aPath, if (aRv.Failed()) { return nullptr; } - nsTArray permArray; - permArray.AppendElement(PermissionRequest(type, NS_LITERAL_CSTRING("read"))); - child->SendPContentPermissionRequestConstructor(r, - permArray, + child->SendPContentPermissionRequestConstructor(r, type, + NS_LITERAL_CSTRING("read"), IPC::Principal(mPrincipal)); r->Sendprompt(); diff --git a/dom/interfaces/base/nsIContentPermissionPrompt.idl b/dom/interfaces/base/nsIContentPermissionPrompt.idl index c51f5ed0bb7..0fdda0ea66e 100644 --- a/dom/interfaces/base/nsIContentPermissionPrompt.idl +++ b/dom/interfaces/base/nsIContentPermissionPrompt.idl @@ -7,13 +7,15 @@ interface nsIPrincipal; interface nsIDOMWindow; interface nsIDOMElement; -interface nsIArray; /** - * Interface provides the request type and its access. + * Interface allows access to a content to request + * permission to perform a privileged operation such as + * geolocation. */ -[scriptable, builtinclass, uuid(384b6cc4-a66b-4bea-98e0-eb10562a9ba4)] -interface nsIContentPermissionType : nsISupports { +[scriptable, uuid(1de67000-2de8-11e2-81c1-0800200c9a66)] +interface nsIContentPermissionRequest : nsISupports { + /** * The type of the permission request, such as * "geolocation". @@ -25,22 +27,8 @@ interface nsIContentPermissionType : nsISupports { * "read". */ readonly attribute ACString access; -}; -/** - * Interface allows access to a content to request - * permission to perform a privileged operation such as - * geolocation. - */ -[scriptable, uuid(69a39d88-d1c4-4ba9-9b19-bafc7a1bb783)] -interface nsIContentPermissionRequest : nsISupports { /** - * The array will include the request types. Elements of this array are - * nsIContentPermissionType object. - */ - readonly attribute nsIArray types; - - /* * The principal of the permission request. */ readonly attribute nsIPrincipal principal; diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index b531ecb399c..ea39cb6b26d 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -16,7 +16,6 @@ include protocol PIndexedDB; include DOMTypes; include JavaScriptTypes; include URIParams; -include PContentPermission; using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h"; @@ -203,8 +202,10 @@ parent: * Initiates an asynchronous request for permission for the * provided principal. * - * @param aRequests - * The array of permissions to request. + * @param aType + * The type of permission to request. + * @param aAccess + * Access type. "read" for example. * @param aPrincipal * The principal of the request. * @@ -212,7 +213,7 @@ parent: * principals that can live in the content process should * provided. */ - PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal); + PContentPermissionRequest(nsCString aType, nsCString aAccess, Principal principal); PContentDialog(uint32_t aType, nsCString aName, nsCString aFeatures, int32_t[] aIntParams, nsString[] aStringParams); diff --git a/dom/ipc/PContentPermission.ipdlh b/dom/ipc/PContentPermission.ipdlh deleted file mode 100644 index 5db4f3b669f..00000000000 --- a/dom/ipc/PContentPermission.ipdlh +++ /dev/null @@ -1,14 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -namespace mozilla { -namespace dom { - -struct PermissionRequest { - nsCString type; - nsCString access; -}; - -} // namespace dom -} // namespace mozilla diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index fbaaae7a310..f5fa0cbcd5f 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1148,11 +1148,12 @@ TabChild::ArraysToParams(const InfallibleTArray& aIntParams, #ifdef DEBUG PContentPermissionRequestChild* TabChild:: SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor, - const InfallibleTArray& aRequests, + const nsCString& aType, + const nsCString& aAccess, const IPC::Principal& aPrincipal) { PCOMContentPermissionRequestChild* child = static_cast(aActor); - PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aRequests, aPrincipal); + PContentPermissionRequestChild* request = PBrowserChild::SendPContentPermissionRequestConstructor(aActor, aType, aAccess, aPrincipal); child->mIPCOpen = true; return request; } @@ -2007,8 +2008,7 @@ TabChild::DeallocPContentDialogChild(PContentDialogChild* aDialog) } PContentPermissionRequestChild* -TabChild::AllocPContentPermissionRequestChild(const InfallibleTArray& aRequests, - const IPC::Principal& aPrincipal) +TabChild::AllocPContentPermissionRequestChild(const nsCString& aType, const nsCString& aAccess, const IPC::Principal&) { NS_RUNTIMEABORT("unused"); return nullptr; diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 28e76145bc3..095ec72784a 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -269,11 +269,13 @@ public: #ifdef DEBUG virtual PContentPermissionRequestChild* SendPContentPermissionRequestConstructor(PContentPermissionRequestChild* aActor, - const InfallibleTArray& aRequests, + const nsCString& aType, + const nsCString& aAccess, const IPC::Principal& aPrincipal); #endif /* DEBUG */ - virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const InfallibleTArray& aRequests, + virtual PContentPermissionRequestChild* AllocPContentPermissionRequestChild(const nsCString& aType, + const nsCString& aAccess, const IPC::Principal& aPrincipal); virtual bool DeallocPContentPermissionRequestChild(PContentPermissionRequestChild* actor); diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index f9f8e3dc39d..863445a92dd 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -14,7 +14,6 @@ #include "mozilla/BrowserElementParent.h" #include "mozilla/docshell/OfflineCacheUpdateParent.h" #include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/PContentPermissionRequestParent.h" #include "mozilla/Hal.h" #include "mozilla/ipc/DocumentRendererParent.h" #include "mozilla/layers/CompositorParent.h" @@ -571,10 +570,9 @@ TabParent::DeallocPDocumentRendererParent(PDocumentRendererParent* actor) } PContentPermissionRequestParent* -TabParent::AllocPContentPermissionRequestParent(const InfallibleTArray& aRequests, - const IPC::Principal& aPrincipal) +TabParent::AllocPContentPermissionRequestParent(const nsCString& type, const nsCString& access, const IPC::Principal& principal) { - return CreateContentPermissionRequestParent(aRequests, mFrameElement, aPrincipal); + return new ContentPermissionRequestParent(type, access, mFrameElement, principal); } bool diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index 9928052af71..bfbc9644ebc 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -215,8 +215,7 @@ public: virtual bool DeallocPDocumentRendererParent(PDocumentRendererParent* actor); virtual PContentPermissionRequestParent* - AllocPContentPermissionRequestParent(const InfallibleTArray& aRequests, - const IPC::Principal& aPrincipal); + AllocPContentPermissionRequestParent(const nsCString& aType, const nsCString& aAccess, const IPC::Principal& aPrincipal); virtual bool DeallocPContentPermissionRequestParent(PContentPermissionRequestParent* actor); virtual POfflineCacheUpdateParent* AllocPOfflineCacheUpdateParent( diff --git a/dom/ipc/moz.build b/dom/ipc/moz.build index 59aa034dcbe..254f7038be4 100644 --- a/dom/ipc/moz.build +++ b/dom/ipc/moz.build @@ -64,7 +64,6 @@ IPDL_SOURCES += [ 'PBrowser.ipdl', 'PContent.ipdl', 'PContentDialog.ipdl', - 'PContentPermission.ipdlh', 'PContentPermissionRequest.ipdl', 'PCrashReporter.ipdl', 'PDocumentRenderer.ipdl', diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 4c57f56b591..145552749f6 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -43,7 +43,7 @@ #include "MediaEngineWebRTC.h" #endif -#ifdef MOZ_B2G +#ifdef MOZ_WIDGET_GONK #include "MediaPermissionGonk.h" #endif @@ -810,6 +810,7 @@ public: , mListener(aListener) , mPrefs(aPrefs) , mDeviceChosen(false) + , mBackendChosen(false) , mManager(MediaManager::GetInstance()) {} @@ -831,11 +832,15 @@ public: , mListener(aListener) , mPrefs(aPrefs) , mDeviceChosen(false) + , mBackendChosen(true) , mBackend(aBackend) , mManager(MediaManager::GetInstance()) {} ~GetUserMediaRunnable() { + if (mBackendChosen) { + delete mBackend; + } } NS_IMETHOD @@ -843,7 +848,10 @@ public: { NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread"); - mBackend = mManager->GetBackend(mWindowID); + // Was a backend provided? + if (!mBackendChosen) { + mBackend = mManager->GetBackend(mWindowID); + } // Was a device provided? if (!mDeviceChosen) { @@ -1030,6 +1038,7 @@ private: MediaEnginePrefs mPrefs; bool mDeviceChosen; + bool mBackendChosen; MediaEngine* mBackend; nsRefPtr mManager; // get ref to this when creating the runnable @@ -1247,10 +1256,10 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, // Force MediaManager to startup before we try to access it from other threads // Hack: should init singleton earlier unless it's expensive (mem or CPU) (void) MediaManager::Get(); -#ifdef MOZ_B2G +#ifdef MOZ_WIDGET_GONK // Initialize MediaPermissionManager before send out any permission request. (void) MediaPermissionManager::GetInstance(); -#endif //MOZ_B2G +#endif //MOZ_WIDGET_GONK } // Store the WindowID in a hash table and mark as active. The entry is removed @@ -1302,7 +1311,7 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, if (c.mFake) { // Fake stream from default backend. gUMRunnable = new GetUserMediaRunnable(c, onSuccess.forget(), - onError.forget(), windowID, listener, mPrefs, GetBackend(windowID, true)); + onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault()); } else { // Stream from default device from WebRTC backend. gUMRunnable = new GetUserMediaRunnable(c, onSuccess.forget(), @@ -1383,26 +1392,22 @@ MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow, } MediaEngine* -MediaManager::GetBackend(uint64_t aWindowId, bool aFake) +MediaManager::GetBackend(uint64_t aWindowId) { // Plugin backends as appropriate. The default engine also currently // includes picture support for Android. // This IS called off main-thread. MutexAutoLock lock(mMutex); if (!mBackend) { - if (aFake) { - mBackend = new MediaEngineDefault(); - } else { #if defined(MOZ_WEBRTC) -#ifndef MOZ_B2G_CAMERA - mBackend = new MediaEngineWebRTC(); + #ifndef MOZ_B2G_CAMERA + mBackend = new MediaEngineWebRTC(); + #else + mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId); + #endif #else - mBackend = new MediaEngineWebRTC(mCameraManager, aWindowId); + mBackend = new MediaEngineDefault(); #endif -#else - mBackend = new MediaEngineDefault(); -#endif - } } return mBackend; } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index fc236478220..6e00da0079c 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -405,7 +405,7 @@ public: NS_DECL_NSIOBSERVER NS_DECL_NSIMEDIAMANAGERSERVICE - MediaEngine* GetBackend(uint64_t aWindowId = 0, bool aFake = false); + MediaEngine* GetBackend(uint64_t aWindowId = 0); StreamListeners *GetWindowListeners(uint64_t aWindowId) { NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread"); @@ -469,7 +469,7 @@ private: static StaticRefPtr sSingleton; -#ifdef MOZ_B2G_CAMERA +#ifdef MOZ_WIDGET_GONK nsRefPtr mCameraManager; #endif }; diff --git a/dom/media/MediaPermissionGonk.cpp b/dom/media/MediaPermissionGonk.cpp index ecf2a1889db..a4f18ed0ae6 100644 --- a/dom/media/MediaPermissionGonk.cpp +++ b/dom/media/MediaPermissionGonk.cpp @@ -20,36 +20,14 @@ #include "mozilla/dom/MediaStreamTrackBinding.h" #include "nsISupportsPrimitives.h" #include "nsServiceManagerUtils.h" -#include "nsArrayUtils.h" -#include "nsContentPermissionHelper.h" #include "mozilla/dom/PermissionMessageUtils.h" #define AUDIO_PERMISSION_NAME "audio-capture" -#define VIDEO_PERMISSION_NAME "video-capture" - -using namespace mozilla::dom; namespace mozilla { static MediaPermissionManager *gMediaPermMgr = nullptr; -static uint32_t -ConvertArrayToPermissionRequest(nsIArray* aSrcArray, - nsTArray& aDesArray) -{ - uint32_t len = 0; - aSrcArray->GetLength(&len); - for (uint32_t i = 0; i < len; i++) { - nsCOMPtr cpt = do_QueryElementAt(aSrcArray, i); - nsAutoCString type; - nsAutoCString access; - cpt->GetType(type); - cpt->GetAccess(access); - aDesArray.AppendElement(PermissionRequest(type, access)); - } - return len; -} - // Helper function for notifying permission granted static nsresult NotifyPermissionAllow(const nsAString &aCallID, nsTArray > &aDevices) @@ -115,7 +93,6 @@ public: private: bool mAudio; // Request for audio permission - bool mVideo; // Request for video permission nsRefPtr mRequest; nsTArray > mDevices; // candiate device list }; @@ -131,7 +108,6 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtrGetConstraints(constraints); mAudio = constraints.mAudio; - mVideo = constraints.mVideo; for (uint32_t i = 0; i < aDevices.Length(); ++i) { nsCOMPtr device(aDevices[i]); @@ -140,34 +116,10 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - if (mAudio) { - nsCOMPtr AudioType = - new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME), - NS_LITERAL_CSTRING("unused")); - types->AppendElement(AudioType, false); - } - if (mVideo) { - nsCOMPtr VideoType = - new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME), - NS_LITERAL_CSTRING("unused")); - types->AppendElement(VideoType, false); - } - NS_IF_ADDREF(*aTypes = types); - - return NS_OK; -} - NS_IMETHODIMP MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) { @@ -183,6 +135,24 @@ MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) return NS_OK; } +NS_IMETHODIMP +MediaPermissionRequest::GetType(nsACString &aType) +{ + if (mAudio) { + aType = AUDIO_PERMISSION_NAME; + return NS_OK; + } + + return NS_OK; +} + +NS_IMETHODIMP +MediaPermissionRequest::GetAccess(nsACString &aAccess) +{ + aAccess = "unused"; + return NS_OK; +} + NS_IMETHODIMP MediaPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow) { @@ -308,12 +278,13 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr &req) dom::TabChild* child = dom::TabChild::GetFrom(window->GetDocShell()); NS_ENSURE_TRUE(child, NS_ERROR_FAILURE); - nsCOMPtr typeArray; - rv = req->GetTypes(getter_AddRefs(typeArray)); + nsAutoCString type; + rv = req->GetType(type); NS_ENSURE_SUCCESS(rv, rv); - nsTArray permArray; - ConvertArrayToPermissionRequest(typeArray, permArray); + nsAutoCString access; + rv = req->GetAccess(access); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr principal; rv = req->GetPrincipal(getter_AddRefs(principal)); @@ -321,7 +292,8 @@ MediaDeviceSuccessCallback::DoPrompt(nsRefPtr &req) req->AddRef(); child->SendPContentPermissionRequestConstructor(req, - permArray, + type, + access, IPC::Principal(principal)); req->Sendprompt(); diff --git a/dom/media/tests/mochitest/Makefile.in b/dom/media/tests/mochitest/Makefile.in index b2406a19562..f0beca99b9a 100644 --- a/dom/media/tests/mochitest/Makefile.in +++ b/dom/media/tests/mochitest/Makefile.in @@ -7,9 +7,3 @@ ifdef MOZ_WEBRTC_LEAKING_TESTS MOCHITEST_FILES += \ $(NULL) endif - -ifdef MOZ_B2G_CAMERA -MOCHITEST_FILES += \ - test_getUserMedia_permission.html \ - $(NULL) -endif diff --git a/dom/media/tests/mochitest/test_getUserMedia_permission.html b/dom/media/tests/mochitest/test_getUserMedia_permission.html deleted file mode 100644 index 3cca7a88337..00000000000 --- a/dom/media/tests/mochitest/test_getUserMedia_permission.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - mozGetUserMedia Permission Test - - - - - - -Display camera/microphone permission acquisition prompt - - - - diff --git a/dom/src/geolocation/nsGeolocation.cpp b/dom/src/geolocation/nsGeolocation.cpp index 36b67e3cf3a..dde32decc69 100644 --- a/dom/src/geolocation/nsGeolocation.cpp +++ b/dom/src/geolocation/nsGeolocation.cpp @@ -15,7 +15,6 @@ #include "nsServiceManagerUtils.h" #include "nsContentUtils.h" #include "nsCxPusher.h" -#include "nsContentPermissionHelper.h" #include "nsIDocument.h" #include "nsIObserverService.h" #include "nsPIDOMWindow.h" @@ -386,11 +385,17 @@ nsGeolocationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal) } NS_IMETHODIMP -nsGeolocationRequest::GetTypes(nsIArray** aTypes) +nsGeolocationRequest::GetType(nsACString & aType) { - return CreatePermissionArray(NS_LITERAL_CSTRING("geolocation"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aType = "geolocation"; + return NS_OK; +} + +NS_IMETHODIMP +nsGeolocationRequest::GetAccess(nsACString & aAccess) +{ + aAccess = "unused"; + return NS_OK; } NS_IMETHODIMP @@ -1447,15 +1452,12 @@ Geolocation::RegisterRequestWithPrompt(nsGeolocationRequest* request) return false; } - nsTArray permArray; - permArray.AppendElement(PermissionRequest(NS_LITERAL_CSTRING("geolocation"), - NS_LITERAL_CSTRING("unused"))); - // Retain a reference so the object isn't deleted without IPDL's knowledge. // Corresponding release occurs in DeallocPContentPermissionRequest. request->AddRef(); child->SendPContentPermissionRequestConstructor(request, - permArray, + NS_LITERAL_CSTRING("geolocation"), + NS_LITERAL_CSTRING("unused"), IPC::Principal(mPrincipal)); request->Sendprompt(); diff --git a/dom/src/notification/DesktopNotification.cpp b/dom/src/notification/DesktopNotification.cpp index ca978afe499..15fe3be9c34 100644 --- a/dom/src/notification/DesktopNotification.cpp +++ b/dom/src/notification/DesktopNotification.cpp @@ -15,7 +15,6 @@ #include "PCOMContentPermissionRequestChild.h" #include "nsIScriptSecurityManager.h" #include "nsServiceManagerUtils.h" -#include "PermissionMessageUtils.h" namespace mozilla { namespace dom { @@ -178,12 +177,9 @@ DesktopNotification::Init() // Corresponding release occurs in DeallocPContentPermissionRequest. nsRefPtr copy = request; - nsTArray permArray; - permArray.AppendElement(PermissionRequest( - NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"))); child->SendPContentPermissionRequestConstructor(copy.forget().get(), - permArray, + NS_LITERAL_CSTRING("desktop-notification"), + NS_LITERAL_CSTRING("unused"), IPC::Principal(mPrincipal)); request->Sendprompt(); @@ -355,11 +351,17 @@ DesktopNotificationRequest::Allow() } NS_IMETHODIMP -DesktopNotificationRequest::GetTypes(nsIArray** aTypes) +DesktopNotificationRequest::GetType(nsACString & aType) { - return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aType = "desktop-notification"; + return NS_OK; +} + +NS_IMETHODIMP +DesktopNotificationRequest::GetAccess(nsACString & aAccess) +{ + aAccess = "unused"; + return NS_OK; } } // namespace dom diff --git a/dom/src/notification/Notification.cpp b/dom/src/notification/Notification.cpp index 4a4edc8a134..7f4de6d609a 100644 --- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -24,7 +24,6 @@ #include "nsDOMJSUtils.h" #include "nsIScriptSecurityManager.h" #include "mozilla/dom/PermissionMessageUtils.h" -#include "nsContentPermissionHelper.h" #ifdef MOZ_B2G #include "nsIDOMDesktopNotification.h" #endif @@ -268,11 +267,9 @@ NotificationPermissionRequest::Run() // Corresponding release occurs in DeallocPContentPermissionRequest. AddRef(); - nsTArray permArray; - permArray.AppendElement(PermissionRequest( - NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"))); - child->SendPContentPermissionRequestConstructor(this, permArray, + NS_NAMED_LITERAL_CSTRING(type, "desktop-notification"); + NS_NAMED_LITERAL_CSTRING(access, "unused"); + child->SendPContentPermissionRequestConstructor(this, type, access, IPC::Principal(mPrincipal)); Sendprompt(); @@ -345,11 +342,17 @@ NotificationPermissionRequest::CallCallback() } NS_IMETHODIMP -NotificationPermissionRequest::GetTypes(nsIArray** aTypes) +NotificationPermissionRequest::GetAccess(nsACString& aAccess) { - return CreatePermissionArray(NS_LITERAL_CSTRING("desktop-notification"), - NS_LITERAL_CSTRING("unused"), - aTypes); + aAccess.AssignLiteral("unused"); + return NS_OK; +} + +NS_IMETHODIMP +NotificationPermissionRequest::GetType(nsACString& aType) +{ + aType.AssignLiteral("desktop-notification"); + return NS_OK; } bool diff --git a/mobile/android/components/ContentPermissionPrompt.js b/mobile/android/components/ContentPermissionPrompt.js index ca8feb92729..09697296234 100644 --- a/mobile/android/components/ContentPermissionPrompt.js +++ b/mobile/android/components/ContentPermissionPrompt.js @@ -21,8 +21,8 @@ ContentPermissionPrompt.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]), - handleExistingPermission: function handleExistingPermission(request, type, isApp) { - let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type); + handleExistingPermission: function handleExistingPermission(request, isApp) { + let result = Services.perms.testExactPermissionFromPrincipal(request.principal, request.type); if (result == Ci.nsIPermissionManager.ALLOW_ACTION) { request.allow(); return true; @@ -32,7 +32,7 @@ ContentPermissionPrompt.prototype = { return true; } - if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[type])) { + if (isApp && (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && !!kEntities[request.type])) { request.cancel(); return true; } @@ -62,16 +62,8 @@ ContentPermissionPrompt.prototype = { prompt: function(request) { let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID; - // Only allow exactly one permission rquest here. - let types = request.types.QueryInterface(Ci.nsIArray); - if (types.length != 1) { - request.cancel(); - return; - } - let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); - // Returns true if the request was handled - if (this.handleExistingPermission(request, perm.type, isApp)) + if (this.handleExistingPermission(request, isApp)) return; let chromeWin = this.getChromeForRequest(request); @@ -80,17 +72,17 @@ ContentPermissionPrompt.prototype = { return; let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties"); - let entityName = kEntities[perm.type]; + let entityName = kEntities[request.type]; let buttons = [{ label: browserBundle.GetStringFromName(entityName + ".allow"), callback: function(aChecked) { // If the user checked "Don't ask again", make a permanent exception if (aChecked) { - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION); } else if (isApp || entityName == "desktopNotification") { // Otherwise allow the permission for the current session (if the request comes from an app or if it's a desktop-notification request) - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION); } request.allow(); @@ -101,7 +93,7 @@ ContentPermissionPrompt.prototype = { callback: function(aChecked) { // If the user checked "Don't ask again", make a permanent exception if (aChecked) - Services.perms.addFromPrincipal(request.principal, perm.type, Ci.nsIPermissionManager.DENY_ACTION); + Services.perms.addFromPrincipal(request.principal, request.type, Ci.nsIPermissionManager.DENY_ACTION); request.cancel(); } diff --git a/testing/specialpowers/content/MockPermissionPrompt.jsm b/testing/specialpowers/content/MockPermissionPrompt.jsm index 0416a622d0e..7c18e9efcf1 100644 --- a/testing/specialpowers/content/MockPermissionPrompt.jsm +++ b/testing/specialpowers/content/MockPermissionPrompt.jsm @@ -34,18 +34,9 @@ this.MockPermissionPrompt = { init: function() { this.reset(); if (!registrar.isCIDRegistered(newClassID)) { - try { - oldClassID = registrar.contractIDToCID(CONTRACT_ID); - oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory); - } catch (ex) { - oldClassID = ""; - oldFactory = null; - dump("TEST-INFO | can't get permission prompt registered component, " + - "assuming there is none"); - } - if (oldFactory != "" && oldFactory != null) { - registrar.unregisterFactory(oldClassID, oldFactory); - } + oldClassID = registrar.contractIDToCID(CONTRACT_ID); + oldFactory = Cm.getClassObject(Cc[CONTRACT_ID], Ci.nsIFactory); + registrar.unregisterFactory(oldClassID, oldFactory); registrar.registerFactory(newClassID, "", CONTRACT_ID, newFactory); } }, @@ -70,17 +61,14 @@ MockPermissionPromptInstance.prototype = { prompt: function(request) { - let perms = request.types.QueryInterface(Ci.nsIArray); - for (let idx = 0; idx < perms.length; idx++) { - let perm = perms.queryElementAt(idx, Ci.nsIContentPermissionType); - if (Services.perms.testExactPermissionFromPrincipal( - request.principal, perm.type) != Ci.nsIPermissionManager.ALLOW_ACTION) { - request.cancel(); - return; - } + this.promptResult = Services.perms.testExactPermissionFromPrincipal(request.principal, + request.type); + if (this.promptResult == Ci.nsIPermissionManager.ALLOW_ACTION) { + request.allow(); + } + else { + request.cancel(); } - - request.allow(); } }; diff --git a/webapprt/ContentPermission.js b/webapprt/ContentPermission.js index 463522304fc..c0cf06993b9 100644 --- a/webapprt/ContentPermission.js +++ b/webapprt/ContentPermission.js @@ -30,25 +30,17 @@ ContentPermission.prototype = { }, prompt: function(request) { - // Only allow exactly one permission rquest here. - let types = request.types.QueryInterface(Ci.nsIArray); - if (types.length != 1) { - request.cancel(); - return; - } - let perm = types.queryElementAt(0, Ci.nsIContentPermissionType); - // Reuse any remembered permission preferences let result = Services.perms.testExactPermissionFromPrincipal(request.principal, - perm.type); + request.type); // We used to use the name "geo" for the geolocation permission, now we're // using "geolocation". We need to check both to support existing // installations. if ((result == Ci.nsIPermissionManager.UNKNOWN_ACTION || result == Ci.nsIPermissionManager.PROMPT_ACTION) && - perm.type == "geolocation") { + request.type == "geolocation") { let geoResult = Services.perms.testExactPermission(request.principal.URI, "geo"); // We override the result only if the "geo" permission was allowed or @@ -64,7 +56,7 @@ ContentPermission.prototype = { return; } else if (result == Ci.nsIPermissionManager.DENY_ACTION || (result == Ci.nsIPermissionManager.UNKNOWN_ACTION && - UNKNOWN_FAIL.indexOf(perm.type) >= 0)) { + UNKNOWN_FAIL.indexOf(request.type) >= 0)) { request.cancel(); return; } @@ -79,16 +71,16 @@ ContentPermission.prototype = { let remember = {value: false}; let choice = Services.prompt.confirmEx( chromeWin, - bundle.formatStringFromName(perm.type + ".title", [name], 1), - bundle.GetStringFromName(perm.type + ".description"), + bundle.formatStringFromName(request.type + ".title", [name], 1), + bundle.GetStringFromName(request.type + ".description"), // Set both buttons to strings with the cancel button being default Ci.nsIPromptService.BUTTON_POS_1_DEFAULT | Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_0 | Ci.nsIPromptService.BUTTON_TITLE_IS_STRING * Ci.nsIPromptService.BUTTON_POS_1, - bundle.GetStringFromName(perm.type + ".allow"), - bundle.GetStringFromName(perm.type + ".deny"), + bundle.GetStringFromName(request.type + ".allow"), + bundle.GetStringFromName(request.type + ".deny"), null, - bundle.GetStringFromName(perm.type + ".remember"), + bundle.GetStringFromName(request.type + ".remember"), remember); let action = Ci.nsIPermissionManager.ALLOW_ACTION; @@ -98,10 +90,10 @@ ContentPermission.prototype = { if (remember.value) { // Persist the choice if the user wants to remember - Services.perms.addFromPrincipal(request.principal, perm.type, action); + Services.perms.addFromPrincipal(request.principal, request.type, action); } else { // Otherwise allow the permission for the current session - Services.perms.addFromPrincipal(request.principal, perm.type, action, + Services.perms.addFromPrincipal(request.principal, request.type, action, Ci.nsIPermissionManager.EXPIRE_SESSION); } From c354a1c2b1b79247f41ef31fef70df8812c38c2c Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 20:15:25 -0800 Subject: [PATCH 09/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/1ff621b5d97f Author: Timothy Guan-tin Chien Desc: Merge pull request #13410 from timdream/keyboard-rename-followup Bug 935350 - Rename 'keyboard' role in homescreen, r=rudyl ======== https://hg.mozilla.org/integration/gaia-central/rev/1f26eb964f43 Author: Timothy Guan-tin Chien Desc: Bug 935350 - Rename 'keyboard' role in homescreen, +shepherd --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 345ad299f72..1c4a0f664ca 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "6489f84d85645253962cb0197df693d63e9a42e6", + "revision": "1ff621b5d97f8ded18426d49712c508402d08362", "repo_path": "/integration/gaia-central" } From 2755582353717e1b095cc781b88f6ea7ce0dd384 Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 21:15:24 -0800 Subject: [PATCH 10/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/6debe3af1446 Author: Arthur Chen Desc: Merge pull request #13375 from crh0716/911701_1 Bug 911701 - Show data signal strength when connecting to EVDO r=alive ======== https://hg.mozilla.org/integration/gaia-central/rev/f8b6c92cacab Author: Arthur Chen Desc: Bug 911701 - Show data signal strength when connecting to EVDO --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 1c4a0f664ca..3ee49b9b29a 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "1ff621b5d97f8ded18426d49712c508402d08362", + "revision": "6debe3af1446cfa0e3057762e5e491d81599806f", "repo_path": "/integration/gaia-central" } From a5026c06b6e0ca5800891011df64e0f99102f023 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Sun, 27 Oct 2013 20:46:46 +0800 Subject: [PATCH 11/53] Bug 814634 - part1 - WebAPI - WebVoicemail API: support multiple sim cards. r=khuey, r=gene.lian --- dom/voicemail/nsIDOMMozVoicemailStatus.idl | 9 +++----- dom/webidl/MozVoicemail.webidl | 24 ++++++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/dom/voicemail/nsIDOMMozVoicemailStatus.idl b/dom/voicemail/nsIDOMMozVoicemailStatus.idl index ef391d92e9b..ff9239d65b6 100644 --- a/dom/voicemail/nsIDOMMozVoicemailStatus.idl +++ b/dom/voicemail/nsIDOMMozVoicemailStatus.idl @@ -6,13 +6,10 @@ #include "nsISupports.idl" -[scriptable, uuid(8c58859a-e006-466a-ad76-b188ba0918ab)] +[scriptable, uuid(efd352af-9eee-48dc-8e92-4d4fdbc89ecb)] interface nsIDOMMozVoicemailStatus : nsISupports { - /** - * There are voicemail messages waiting, but the count is unknown. - */ - const long MESSAGE_COUNT_UNKNOWN = -1; + readonly attribute unsigned long serviceId; /** * Whether or not there are messages waiting in the voicemail box @@ -22,7 +19,7 @@ interface nsIDOMMozVoicemailStatus : nsISupports /** * The total message count. Some voicemail indicators will only specify that * messages are waiting, but not the actual number. In that case, the value - * of messageCount will be MESSAGE_COUNT_UNKNOWN (-1). + * of messageCount will be -1, indicating the unknown message count. * * Logic for a voicemail notification might look something like: * if (status.hasMessages) { diff --git a/dom/webidl/MozVoicemail.webidl b/dom/webidl/MozVoicemail.webidl index 22c91fc54f1..468bae7daa1 100644 --- a/dom/webidl/MozVoicemail.webidl +++ b/dom/webidl/MozVoicemail.webidl @@ -11,26 +11,28 @@ interface MozVoicemailStatus; interface MozVoicemail : EventTarget { /** - * The current voicemail status, or null when the status is unknown + * The current voicemail status of a specified service, or null when the + * status is unknown. */ - [GetterThrows] - readonly attribute MozVoicemailStatus? status; + [Throws] + MozVoicemailStatus getStatus(optional unsigned long serviceId); /** - * The voicemail box dialing number, or null if one wasn't found + * The voicemail box dialing number of a specified service, or null if one + * wasn't found. */ - [GetterThrows] - readonly attribute DOMString? number; + [Throws] + DOMString getNumber(optional unsigned long serviceId); /** - * The display name of the voicemail box dialing number, or null if one - * wasn't found + * The display name of the voicemail box dialing number of a specified service, + * or null if one wasn't found. */ - [GetterThrows] - readonly attribute DOMString? displayName; + [Throws] + DOMString getDisplayName(optional unsigned long serviceId); /** - * The current voicemail status has changed + * The current voicemail status has changed. */ attribute EventHandler onstatuschanged; }; From 53c3560b1e9f4cc146e99b44a9e39bc104ba0741 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Sun, 27 Oct 2013 20:48:43 +0800 Subject: [PATCH 12/53] Bug 814634 - part2 - internal API --- dom/voicemail/nsIVoicemailProvider.idl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/voicemail/nsIVoicemailProvider.idl b/dom/voicemail/nsIVoicemailProvider.idl index 115e35cc80a..05f1aba5869 100644 --- a/dom/voicemail/nsIVoicemailProvider.idl +++ b/dom/voicemail/nsIVoicemailProvider.idl @@ -22,7 +22,7 @@ interface nsIVoicemailListener : nsISupports * XPCOM component (in the content process) that provides the voicemail * information. */ -[scriptable, uuid(38746f3c-f4e3-4804-b900-ba2463b923c8)] +[scriptable, uuid(1bbfff90-88f7-4d73-896e-9620a0000ab0)] interface nsIVoicemailProvider : nsISupports { readonly attribute unsigned long voicemailDefaultServiceId; @@ -35,7 +35,7 @@ interface nsIVoicemailProvider : nsISupports void registerVoicemailMsg(in nsIVoicemailListener listener); void unregisterVoicemailMsg(in nsIVoicemailListener listener); - readonly attribute nsIDOMMozVoicemailStatus voicemailStatus; - readonly attribute DOMString voicemailNumber; - readonly attribute DOMString voicemailDisplayName; + nsIDOMMozVoicemailStatus getVoicemailStatus(in unsigned long clientId); + DOMString getVoicemailNumber(in unsigned long clientId); + DOMString getVoicemailDisplayName(in unsigned long clientId); }; From 0b909df4825d4b66ffcf9b732afa211565e98f89 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Tue, 29 Oct 2013 09:58:12 +0800 Subject: [PATCH 13/53] Bug 814634 - part3 - DOM. r=khuey --- dom/voicemail/Voicemail.cpp | 58 +++++++++++++++++++++++++++++++++---- dom/voicemail/Voicemail.h | 15 ++++++++-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/dom/voicemail/Voicemail.cpp b/dom/voicemail/Voicemail.cpp index a4de3a68595..2b5c3bfec87 100644 --- a/dom/voicemail/Voicemail.cpp +++ b/dom/voicemail/Voicemail.cpp @@ -10,12 +10,14 @@ #include "nsIDOMMozVoicemailStatus.h" #include "nsIDOMMozVoicemailEvent.h" +#include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsDOMClassInfo.h" #include "nsServiceManagerUtils.h" #include "GeneratedEvents.h" #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1" +const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; using namespace mozilla::dom; @@ -67,18 +69,48 @@ Voicemail::WrapObject(JSContext* aCx, JS::Handle aScope) return MozVoicemailBinding::Wrap(aCx, aScope, this); } +bool +Voicemail::IsValidServiceId(uint32_t aServiceId) const +{ + uint32_t numClients = mozilla::Preferences::GetUint(kPrefRilNumRadioInterfaces, 1); + + return aServiceId < numClients; +} + +bool +Voicemail::PassedOrDefaultServiceId(const Optional& aServiceId, + uint32_t& aResult) const +{ + if (aServiceId.WasPassed()) { + if (!IsValidServiceId(aServiceId.Value())) { + return false; + } + aResult = aServiceId.Value(); + } else { + mProvider->GetVoicemailDefaultServiceId(&aResult); + } + + return true; +} + // MozVoicemail WebIDL already_AddRefed -Voicemail::GetStatus(ErrorResult& aRv) const +Voicemail::GetStatus(const Optional& aServiceId, + ErrorResult& aRv) const { if (!mProvider) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } + uint32_t id = 0; + if (!PassedOrDefaultServiceId(aServiceId, id)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return nullptr; + } nsCOMPtr status; - nsresult rv = mProvider->GetVoicemailStatus(getter_AddRefs(status)); + nsresult rv = mProvider->GetVoicemailStatus(id, getter_AddRefs(status)); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; @@ -88,7 +120,8 @@ Voicemail::GetStatus(ErrorResult& aRv) const } void -Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const +Voicemail::GetNumber(const Optional& aServiceId, nsString& aNumber, + ErrorResult& aRv) const { aNumber.SetIsVoid(true); @@ -97,11 +130,18 @@ Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const return; } - aRv = mProvider->GetVoicemailNumber(aNumber); + uint32_t id = 0; + if (!PassedOrDefaultServiceId(aServiceId, id)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return; + } + + aRv = mProvider->GetVoicemailNumber(id, aNumber); } void -Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const +Voicemail::GetDisplayName(const Optional& aServiceId, nsString& aDisplayName, + ErrorResult& aRv) const { aDisplayName.SetIsVoid(true); @@ -110,7 +150,13 @@ Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const return; } - aRv = mProvider->GetVoicemailDisplayName(aDisplayName); + uint32_t id = 0; + if (!PassedOrDefaultServiceId(aServiceId, id)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return; + } + + aRv = mProvider->GetVoicemailDisplayName(id, aDisplayName); } // nsIVoicemailListener diff --git a/dom/voicemail/Voicemail.h b/dom/voicemail/Voicemail.h index 5ee5efef4c6..5da306ea22c 100644 --- a/dom/voicemail/Voicemail.h +++ b/dom/voicemail/Voicemail.h @@ -52,19 +52,28 @@ public: WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; already_AddRefed - GetStatus(ErrorResult& aRv) const; + GetStatus(const Optional& aServiceId, ErrorResult& aRv) const; void - GetNumber(nsString& aNumber, ErrorResult& aRv) const; + GetNumber(const Optional& aServiceId, nsString& aNumber, + ErrorResult& aRv) const; void - GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const; + GetDisplayName(const Optional& aServiceId, nsString& aDisplayName, + ErrorResult& aRv) const; IMPL_EVENT_HANDLER(statuschanged) private: nsCOMPtr mProvider; nsRefPtr mListener; + + bool + IsValidServiceId(uint32_t aServiceId) const; + + bool + PassedOrDefaultServiceId(const Optional& aServiceId, + uint32_t& aResult) const; }; } // namespace dom From 5fabc4804f96883a17ba7e291daed0343fc46d5c Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Tue, 29 Oct 2013 17:40:44 +0800 Subject: [PATCH 14/53] Bug 814634 - part4 - RIL and tests. r=vicamo --- dom/system/gonk/RILContentHelper.js | 86 ++++++++++++------- .../test/marionette/test_voicemail_number.js | 9 +- .../test_voicemail_statuschanged.js | 15 ++-- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index aadaf07f803..9441a518de7 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -271,7 +271,9 @@ MobileCellInfo.prototype = { cdmaNetworkId: -1 }; -function VoicemailStatus() {} +function VoicemailStatus(clientId) { + this.serviceId = clientId; +} VoicemailStatus.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]), classID: VOICEMAILSTATUS_CID, @@ -284,8 +286,9 @@ VoicemailStatus.prototype = { // nsIDOMMozVoicemailStatus + serviceId: -1, hasMessages: false, - messageCount: Ci.nsIDOMMozVoicemailStatus.MESSAGE_COUNT_UNKNOWN, + messageCount: -1, // Count unknown. returnNumber: null, returnMessage: null }; @@ -451,6 +454,8 @@ function RILContentHelper() { debug("Number of clients: " + this.numClients); this.rilContexts = []; + this.voicemailInfos = []; + this.voicemailStatuses = []; for (let clientId = 0; clientId < this.numClients; clientId++) { this.rilContexts[clientId] = { cardState: RIL.GECKO_CARDSTATE_UNKNOWN, @@ -459,9 +464,10 @@ function RILContentHelper() { voiceConnectionInfo: new MobileConnectionInfo(), dataConnectionInfo: new MobileConnectionInfo() }; + + this.voicemailInfos[clientId] = new VoicemailInfo(); } - this.voicemailInfo = new VoicemailInfo(); this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId(); this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES); @@ -1361,7 +1367,8 @@ RILContentHelper.prototype = { _voicemailListeners: null, _iccListeners: null, - voicemailStatus: null, + voicemailInfos: null, + voicemailStatuses: null, voicemailDefaultServiceId: 0, getVoicemailDefaultServiceId: function getVoicemailDefaultServiceId() { @@ -1374,27 +1381,33 @@ RILContentHelper.prototype = { return id; }, - getVoicemailInfo: function getVoicemailInfo() { + getVoicemailInfo: function getVoicemailInfo(clientId) { // Get voicemail infomation by IPC only on first time. - this.getVoicemailInfo = function getVoicemailInfo() { - return this.voicemailInfo; + this.getVoicemailInfo = function getVoicemailInfo(clientId) { + return this.voicemailInfos[clientId]; }; - let voicemailInfo = - cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: 0})[0]; - if (voicemailInfo) { - this.updateInfo(voicemailInfo, this.voicemailInfo); + for (let cId = 0; cId < gNumRadioInterfaces; cId++) { + let voicemailInfo = + cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0]; + if (voicemailInfo) { + this.updateInfo(voicemailInfo, this.voicemailInfos[cId]); + } } - return this.voicemailInfo; + return this.voicemailInfos[clientId]; }, - get voicemailNumber() { - return this.getVoicemailInfo().number; + getVoicemailNumber: function getVoicemailNumber(clientId) { + return this.getVoicemailInfo(clientId).number; }, - get voicemailDisplayName() { - return this.getVoicemailInfo().displayName; + getVoicemailDisplayName: function getVoicemailDisplayName(clientId) { + return this.getVoicemailInfo(clientId).displayName; + }, + + getVoicemailStatus: function getVoicemailStatus(clientId) { + return this.voicemailStatuses[clientId]; }, registerListener: function registerListener(listenerType, clientId, listener) { @@ -1442,13 +1455,17 @@ RILContentHelper.prototype = { registerVoicemailMsg: function registerVoicemailMsg(listener) { debug("Registering for voicemail-related messages"); - //TODO: Bug 814634 - WebVoicemail API: support multiple sim cards. + // To follow the listener registration scheme, we add a dummy clientId 0. + // All voicemail events are routed to listener for client id 0. + // See |handleVoicemailNotification|. this.registerListener("_voicemailListeners", 0, listener); cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg"); }, unregisterVoicemailMsg: function unregisteVoicemailMsg(listener) { - //TODO: Bug 814634 - WebVoicemail API: support multiple sim cards. + // To follow the listener unregistration scheme, we add a dummy clientId 0. + // All voicemail events are routed to listener for client id 0. + // See |handleVoicemailNotification|. this.unregisterListener("_voicemailListeners", 0, listener); }, @@ -1619,7 +1636,7 @@ RILContentHelper.prototype = { this.handleVoicemailNotification(clientId, data); break; case "RIL:VoicemailInfoChanged": - this.updateInfo(data, this.voicemailInfo); + this.updateInfo(data, this.voicemailInfos[clientId]); break; case "RIL:CardLockResult": { let requestId = data.requestId; @@ -1835,41 +1852,44 @@ RILContentHelper.prototype = { this.fireRequestSuccess(message.requestId, result); }, - handleVoicemailNotification: function handleVoicemailNotification(clientId, message) { - // Bug 814634 - WebVoicemail API: support multiple sim cards + handleVoicemailNotification: function handleVoicemailNotification(clientId, + message) { let changed = false; - if (!this.voicemailStatus) { - this.voicemailStatus = new VoicemailStatus(); + if (!this.voicemailStatuses[clientId]) { + this.voicemailStatuses[clientId] = new VoicemailStatus(clientId); } - if (this.voicemailStatus.hasMessages != message.active) { + let voicemailStatus = this.voicemailStatuses[clientId]; + if (voicemailStatus.hasMessages != message.active) { changed = true; - this.voicemailStatus.hasMessages = message.active; + voicemailStatus.hasMessages = message.active; } - if (this.voicemailStatus.messageCount != message.msgCount) { + if (voicemailStatus.messageCount != message.msgCount) { changed = true; - this.voicemailStatus.messageCount = message.msgCount; + voicemailStatus.messageCount = message.msgCount; } else if (message.msgCount == -1) { // For MWI using DCS the message count is not available changed = true; } - if (this.voicemailStatus.returnNumber != message.returnNumber) { + if (voicemailStatus.returnNumber != message.returnNumber) { changed = true; - this.voicemailStatus.returnNumber = message.returnNumber; + voicemailStatus.returnNumber = message.returnNumber; } - if (this.voicemailStatus.returnMessage != message.returnMessage) { + if (voicemailStatus.returnMessage != message.returnMessage) { changed = true; - this.voicemailStatus.returnMessage = message.returnMessage; + voicemailStatus.returnMessage = message.returnMessage; } if (changed) { - this._deliverEvent(clientId, + // To follow the event delivering scheme, we add a dummy clientId 0. + // All voicemail events are routed to listener for client id 0. + this._deliverEvent(0, "_voicemailListeners", "notifyStatusChanged", - [this.voicemailStatus]); + [voicemailStatus]); } }, diff --git a/dom/voicemail/test/marionette/test_voicemail_number.js b/dom/voicemail/test/marionette/test_voicemail_number.js index bc5f1376d9e..3a8a56b7969 100644 --- a/dom/voicemail/test/marionette/test_voicemail_number.js +++ b/dom/voicemail/test/marionette/test_voicemail_number.js @@ -8,9 +8,14 @@ SpecialPowers.addPermission("voicemail", true, document); let voicemail = window.navigator.mozVoicemail; ok(voicemail instanceof MozVoicemail); +let serviceId = 0; + // These are the emulator's hard coded voicemail number and alphaId -is(voicemail.number, "+15552175049"); -is(voicemail.displayName, "Voicemail"); +is(voicemail.getNumber(serviceId), "+15552175049"); +is(voicemail.getDisplayName(serviceId), "Voicemail"); + +is(voicemail.getNumber(), "+15552175049"); +is(voicemail.getDisplayName(), "Voicemail"); SpecialPowers.removePermission("voicemail", document); finish(); diff --git a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js index 4816c182d52..a33a3f3c1c3 100644 --- a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js +++ b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js @@ -4,6 +4,8 @@ SpecialPowers.addPermission("voicemail", true, document); let voicemail = window.navigator.mozVoicemail; +let serviceId = 0; + ok(voicemail instanceof MozVoicemail); is(voicemail.status, null); @@ -42,10 +44,13 @@ function sendIndicatorPDU(pdu, listener, nextTest) { // See RadioInterfaceLayer.js / Bug #768441 function isVoicemailStatus(status) { - is(voicemail.status.hasMessages, status.hasMessages); - is(voicemail.status.messageCount, status.messageCount); - is(voicemail.status.returnNumber, status.returnNumber); - is(voicemail.status.returnMessage, status.returnMessage); + is(voicemail.getStatus(), status); + is(voicemail.getStatus(serviceId), status); + + is(voicemail.getStatus().hasMessages, status.hasMessages); + is(voicemail.getStatus().messageCount, status.messageCount); + is(voicemail.getStatus().returnNumber, status.returnNumber); + is(voicemail.getStatus().returnMessage, status.returnMessage); } const MWI_PDU_PREFIX = "0000"; @@ -80,7 +85,7 @@ function testLevel1Indicator() { // TODO: bug 905228 - MozVoicemailStatus is not defined. //ok(status instanceof MozVoicemailStatus); is(status.hasMessages, true); - is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN); + is(status.messageCount, -1); is(status.returnNumber, MWI_LEVEL1_SENDER); is(status.returnMessage, MWI_DEFAULT_BODY); isVoicemailStatus(status); From 5544a039aefb8bb9c3b12fd626047a2fc3581824 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Wed, 6 Nov 2013 13:48:17 +0800 Subject: [PATCH 15/53] Backed out changeset 9e63eda1ca2f (bug 814634) for missing r= in comment --- dom/system/gonk/RILContentHelper.js | 86 +++++++------------ .../test/marionette/test_voicemail_number.js | 9 +- .../test_voicemail_statuschanged.js | 15 ++-- 3 files changed, 40 insertions(+), 70 deletions(-) diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index 9441a518de7..aadaf07f803 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -271,9 +271,7 @@ MobileCellInfo.prototype = { cdmaNetworkId: -1 }; -function VoicemailStatus(clientId) { - this.serviceId = clientId; -} +function VoicemailStatus() {} VoicemailStatus.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]), classID: VOICEMAILSTATUS_CID, @@ -286,9 +284,8 @@ VoicemailStatus.prototype = { // nsIDOMMozVoicemailStatus - serviceId: -1, hasMessages: false, - messageCount: -1, // Count unknown. + messageCount: Ci.nsIDOMMozVoicemailStatus.MESSAGE_COUNT_UNKNOWN, returnNumber: null, returnMessage: null }; @@ -454,8 +451,6 @@ function RILContentHelper() { debug("Number of clients: " + this.numClients); this.rilContexts = []; - this.voicemailInfos = []; - this.voicemailStatuses = []; for (let clientId = 0; clientId < this.numClients; clientId++) { this.rilContexts[clientId] = { cardState: RIL.GECKO_CARDSTATE_UNKNOWN, @@ -464,10 +459,9 @@ function RILContentHelper() { voiceConnectionInfo: new MobileConnectionInfo(), dataConnectionInfo: new MobileConnectionInfo() }; - - this.voicemailInfos[clientId] = new VoicemailInfo(); } + this.voicemailInfo = new VoicemailInfo(); this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId(); this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES); @@ -1367,8 +1361,7 @@ RILContentHelper.prototype = { _voicemailListeners: null, _iccListeners: null, - voicemailInfos: null, - voicemailStatuses: null, + voicemailStatus: null, voicemailDefaultServiceId: 0, getVoicemailDefaultServiceId: function getVoicemailDefaultServiceId() { @@ -1381,33 +1374,27 @@ RILContentHelper.prototype = { return id; }, - getVoicemailInfo: function getVoicemailInfo(clientId) { + getVoicemailInfo: function getVoicemailInfo() { // Get voicemail infomation by IPC only on first time. - this.getVoicemailInfo = function getVoicemailInfo(clientId) { - return this.voicemailInfos[clientId]; + this.getVoicemailInfo = function getVoicemailInfo() { + return this.voicemailInfo; }; - for (let cId = 0; cId < gNumRadioInterfaces; cId++) { - let voicemailInfo = - cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0]; - if (voicemailInfo) { - this.updateInfo(voicemailInfo, this.voicemailInfos[cId]); - } + let voicemailInfo = + cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: 0})[0]; + if (voicemailInfo) { + this.updateInfo(voicemailInfo, this.voicemailInfo); } - return this.voicemailInfos[clientId]; + return this.voicemailInfo; }, - getVoicemailNumber: function getVoicemailNumber(clientId) { - return this.getVoicemailInfo(clientId).number; + get voicemailNumber() { + return this.getVoicemailInfo().number; }, - getVoicemailDisplayName: function getVoicemailDisplayName(clientId) { - return this.getVoicemailInfo(clientId).displayName; - }, - - getVoicemailStatus: function getVoicemailStatus(clientId) { - return this.voicemailStatuses[clientId]; + get voicemailDisplayName() { + return this.getVoicemailInfo().displayName; }, registerListener: function registerListener(listenerType, clientId, listener) { @@ -1455,17 +1442,13 @@ RILContentHelper.prototype = { registerVoicemailMsg: function registerVoicemailMsg(listener) { debug("Registering for voicemail-related messages"); - // To follow the listener registration scheme, we add a dummy clientId 0. - // All voicemail events are routed to listener for client id 0. - // See |handleVoicemailNotification|. + //TODO: Bug 814634 - WebVoicemail API: support multiple sim cards. this.registerListener("_voicemailListeners", 0, listener); cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg"); }, unregisterVoicemailMsg: function unregisteVoicemailMsg(listener) { - // To follow the listener unregistration scheme, we add a dummy clientId 0. - // All voicemail events are routed to listener for client id 0. - // See |handleVoicemailNotification|. + //TODO: Bug 814634 - WebVoicemail API: support multiple sim cards. this.unregisterListener("_voicemailListeners", 0, listener); }, @@ -1636,7 +1619,7 @@ RILContentHelper.prototype = { this.handleVoicemailNotification(clientId, data); break; case "RIL:VoicemailInfoChanged": - this.updateInfo(data, this.voicemailInfos[clientId]); + this.updateInfo(data, this.voicemailInfo); break; case "RIL:CardLockResult": { let requestId = data.requestId; @@ -1852,44 +1835,41 @@ RILContentHelper.prototype = { this.fireRequestSuccess(message.requestId, result); }, - handleVoicemailNotification: function handleVoicemailNotification(clientId, - message) { + handleVoicemailNotification: function handleVoicemailNotification(clientId, message) { + // Bug 814634 - WebVoicemail API: support multiple sim cards let changed = false; - if (!this.voicemailStatuses[clientId]) { - this.voicemailStatuses[clientId] = new VoicemailStatus(clientId); + if (!this.voicemailStatus) { + this.voicemailStatus = new VoicemailStatus(); } - let voicemailStatus = this.voicemailStatuses[clientId]; - if (voicemailStatus.hasMessages != message.active) { + if (this.voicemailStatus.hasMessages != message.active) { changed = true; - voicemailStatus.hasMessages = message.active; + this.voicemailStatus.hasMessages = message.active; } - if (voicemailStatus.messageCount != message.msgCount) { + if (this.voicemailStatus.messageCount != message.msgCount) { changed = true; - voicemailStatus.messageCount = message.msgCount; + this.voicemailStatus.messageCount = message.msgCount; } else if (message.msgCount == -1) { // For MWI using DCS the message count is not available changed = true; } - if (voicemailStatus.returnNumber != message.returnNumber) { + if (this.voicemailStatus.returnNumber != message.returnNumber) { changed = true; - voicemailStatus.returnNumber = message.returnNumber; + this.voicemailStatus.returnNumber = message.returnNumber; } - if (voicemailStatus.returnMessage != message.returnMessage) { + if (this.voicemailStatus.returnMessage != message.returnMessage) { changed = true; - voicemailStatus.returnMessage = message.returnMessage; + this.voicemailStatus.returnMessage = message.returnMessage; } if (changed) { - // To follow the event delivering scheme, we add a dummy clientId 0. - // All voicemail events are routed to listener for client id 0. - this._deliverEvent(0, + this._deliverEvent(clientId, "_voicemailListeners", "notifyStatusChanged", - [voicemailStatus]); + [this.voicemailStatus]); } }, diff --git a/dom/voicemail/test/marionette/test_voicemail_number.js b/dom/voicemail/test/marionette/test_voicemail_number.js index 3a8a56b7969..bc5f1376d9e 100644 --- a/dom/voicemail/test/marionette/test_voicemail_number.js +++ b/dom/voicemail/test/marionette/test_voicemail_number.js @@ -8,14 +8,9 @@ SpecialPowers.addPermission("voicemail", true, document); let voicemail = window.navigator.mozVoicemail; ok(voicemail instanceof MozVoicemail); -let serviceId = 0; - // These are the emulator's hard coded voicemail number and alphaId -is(voicemail.getNumber(serviceId), "+15552175049"); -is(voicemail.getDisplayName(serviceId), "Voicemail"); - -is(voicemail.getNumber(), "+15552175049"); -is(voicemail.getDisplayName(), "Voicemail"); +is(voicemail.number, "+15552175049"); +is(voicemail.displayName, "Voicemail"); SpecialPowers.removePermission("voicemail", document); finish(); diff --git a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js index a33a3f3c1c3..4816c182d52 100644 --- a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js +++ b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js @@ -4,8 +4,6 @@ SpecialPowers.addPermission("voicemail", true, document); let voicemail = window.navigator.mozVoicemail; -let serviceId = 0; - ok(voicemail instanceof MozVoicemail); is(voicemail.status, null); @@ -44,13 +42,10 @@ function sendIndicatorPDU(pdu, listener, nextTest) { // See RadioInterfaceLayer.js / Bug #768441 function isVoicemailStatus(status) { - is(voicemail.getStatus(), status); - is(voicemail.getStatus(serviceId), status); - - is(voicemail.getStatus().hasMessages, status.hasMessages); - is(voicemail.getStatus().messageCount, status.messageCount); - is(voicemail.getStatus().returnNumber, status.returnNumber); - is(voicemail.getStatus().returnMessage, status.returnMessage); + is(voicemail.status.hasMessages, status.hasMessages); + is(voicemail.status.messageCount, status.messageCount); + is(voicemail.status.returnNumber, status.returnNumber); + is(voicemail.status.returnMessage, status.returnMessage); } const MWI_PDU_PREFIX = "0000"; @@ -85,7 +80,7 @@ function testLevel1Indicator() { // TODO: bug 905228 - MozVoicemailStatus is not defined. //ok(status instanceof MozVoicemailStatus); is(status.hasMessages, true); - is(status.messageCount, -1); + is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN); is(status.returnNumber, MWI_LEVEL1_SENDER); is(status.returnMessage, MWI_DEFAULT_BODY); isVoicemailStatus(status); From 98c928ea6e262e68cf43973beba19e036218a261 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Wed, 6 Nov 2013 13:48:17 +0800 Subject: [PATCH 16/53] Backed out changeset 4b0f636041e5 (bug 814634) for missing r= in comment --- dom/voicemail/Voicemail.cpp | 58 ++++--------------------------------- dom/voicemail/Voicemail.h | 15 ++-------- 2 files changed, 9 insertions(+), 64 deletions(-) diff --git a/dom/voicemail/Voicemail.cpp b/dom/voicemail/Voicemail.cpp index 2b5c3bfec87..a4de3a68595 100644 --- a/dom/voicemail/Voicemail.cpp +++ b/dom/voicemail/Voicemail.cpp @@ -10,14 +10,12 @@ #include "nsIDOMMozVoicemailStatus.h" #include "nsIDOMMozVoicemailEvent.h" -#include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsDOMClassInfo.h" #include "nsServiceManagerUtils.h" #include "GeneratedEvents.h" #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1" -const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; using namespace mozilla::dom; @@ -69,48 +67,18 @@ Voicemail::WrapObject(JSContext* aCx, JS::Handle aScope) return MozVoicemailBinding::Wrap(aCx, aScope, this); } -bool -Voicemail::IsValidServiceId(uint32_t aServiceId) const -{ - uint32_t numClients = mozilla::Preferences::GetUint(kPrefRilNumRadioInterfaces, 1); - - return aServiceId < numClients; -} - -bool -Voicemail::PassedOrDefaultServiceId(const Optional& aServiceId, - uint32_t& aResult) const -{ - if (aServiceId.WasPassed()) { - if (!IsValidServiceId(aServiceId.Value())) { - return false; - } - aResult = aServiceId.Value(); - } else { - mProvider->GetVoicemailDefaultServiceId(&aResult); - } - - return true; -} - // MozVoicemail WebIDL already_AddRefed -Voicemail::GetStatus(const Optional& aServiceId, - ErrorResult& aRv) const +Voicemail::GetStatus(ErrorResult& aRv) const { if (!mProvider) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } - uint32_t id = 0; - if (!PassedOrDefaultServiceId(aServiceId, id)) { - aRv.Throw(NS_ERROR_INVALID_ARG); - return nullptr; - } nsCOMPtr status; - nsresult rv = mProvider->GetVoicemailStatus(id, getter_AddRefs(status)); + nsresult rv = mProvider->GetVoicemailStatus(getter_AddRefs(status)); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; @@ -120,8 +88,7 @@ Voicemail::GetStatus(const Optional& aServiceId, } void -Voicemail::GetNumber(const Optional& aServiceId, nsString& aNumber, - ErrorResult& aRv) const +Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const { aNumber.SetIsVoid(true); @@ -130,18 +97,11 @@ Voicemail::GetNumber(const Optional& aServiceId, nsString& aNumber, return; } - uint32_t id = 0; - if (!PassedOrDefaultServiceId(aServiceId, id)) { - aRv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - aRv = mProvider->GetVoicemailNumber(id, aNumber); + aRv = mProvider->GetVoicemailNumber(aNumber); } void -Voicemail::GetDisplayName(const Optional& aServiceId, nsString& aDisplayName, - ErrorResult& aRv) const +Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const { aDisplayName.SetIsVoid(true); @@ -150,13 +110,7 @@ Voicemail::GetDisplayName(const Optional& aServiceId, nsString& aDispl return; } - uint32_t id = 0; - if (!PassedOrDefaultServiceId(aServiceId, id)) { - aRv.Throw(NS_ERROR_INVALID_ARG); - return; - } - - aRv = mProvider->GetVoicemailDisplayName(id, aDisplayName); + aRv = mProvider->GetVoicemailDisplayName(aDisplayName); } // nsIVoicemailListener diff --git a/dom/voicemail/Voicemail.h b/dom/voicemail/Voicemail.h index 5da306ea22c..5ee5efef4c6 100644 --- a/dom/voicemail/Voicemail.h +++ b/dom/voicemail/Voicemail.h @@ -52,28 +52,19 @@ public: WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; already_AddRefed - GetStatus(const Optional& aServiceId, ErrorResult& aRv) const; + GetStatus(ErrorResult& aRv) const; void - GetNumber(const Optional& aServiceId, nsString& aNumber, - ErrorResult& aRv) const; + GetNumber(nsString& aNumber, ErrorResult& aRv) const; void - GetDisplayName(const Optional& aServiceId, nsString& aDisplayName, - ErrorResult& aRv) const; + GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const; IMPL_EVENT_HANDLER(statuschanged) private: nsCOMPtr mProvider; nsRefPtr mListener; - - bool - IsValidServiceId(uint32_t aServiceId) const; - - bool - PassedOrDefaultServiceId(const Optional& aServiceId, - uint32_t& aResult) const; }; } // namespace dom From cc134f033a9f6e2a9511e2d99340be0d848061ae Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Wed, 6 Nov 2013 13:48:17 +0800 Subject: [PATCH 17/53] Backed out changeset 5804ff8c66fb (bug 814634) for missing r= in comment --- dom/voicemail/nsIVoicemailProvider.idl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/voicemail/nsIVoicemailProvider.idl b/dom/voicemail/nsIVoicemailProvider.idl index 05f1aba5869..115e35cc80a 100644 --- a/dom/voicemail/nsIVoicemailProvider.idl +++ b/dom/voicemail/nsIVoicemailProvider.idl @@ -22,7 +22,7 @@ interface nsIVoicemailListener : nsISupports * XPCOM component (in the content process) that provides the voicemail * information. */ -[scriptable, uuid(1bbfff90-88f7-4d73-896e-9620a0000ab0)] +[scriptable, uuid(38746f3c-f4e3-4804-b900-ba2463b923c8)] interface nsIVoicemailProvider : nsISupports { readonly attribute unsigned long voicemailDefaultServiceId; @@ -35,7 +35,7 @@ interface nsIVoicemailProvider : nsISupports void registerVoicemailMsg(in nsIVoicemailListener listener); void unregisterVoicemailMsg(in nsIVoicemailListener listener); - nsIDOMMozVoicemailStatus getVoicemailStatus(in unsigned long clientId); - DOMString getVoicemailNumber(in unsigned long clientId); - DOMString getVoicemailDisplayName(in unsigned long clientId); + readonly attribute nsIDOMMozVoicemailStatus voicemailStatus; + readonly attribute DOMString voicemailNumber; + readonly attribute DOMString voicemailDisplayName; }; From ebcf902cd0184b8305e16c4d372e4951595d2377 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Wed, 6 Nov 2013 13:48:17 +0800 Subject: [PATCH 18/53] Backed out changeset 170e22ea9aa0 (bug 814634) for missing r= in comment --- dom/voicemail/nsIDOMMozVoicemailStatus.idl | 9 +++++--- dom/webidl/MozVoicemail.webidl | 24 ++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/dom/voicemail/nsIDOMMozVoicemailStatus.idl b/dom/voicemail/nsIDOMMozVoicemailStatus.idl index ff9239d65b6..ef391d92e9b 100644 --- a/dom/voicemail/nsIDOMMozVoicemailStatus.idl +++ b/dom/voicemail/nsIDOMMozVoicemailStatus.idl @@ -6,10 +6,13 @@ #include "nsISupports.idl" -[scriptable, uuid(efd352af-9eee-48dc-8e92-4d4fdbc89ecb)] +[scriptable, uuid(8c58859a-e006-466a-ad76-b188ba0918ab)] interface nsIDOMMozVoicemailStatus : nsISupports { - readonly attribute unsigned long serviceId; + /** + * There are voicemail messages waiting, but the count is unknown. + */ + const long MESSAGE_COUNT_UNKNOWN = -1; /** * Whether or not there are messages waiting in the voicemail box @@ -19,7 +22,7 @@ interface nsIDOMMozVoicemailStatus : nsISupports /** * The total message count. Some voicemail indicators will only specify that * messages are waiting, but not the actual number. In that case, the value - * of messageCount will be -1, indicating the unknown message count. + * of messageCount will be MESSAGE_COUNT_UNKNOWN (-1). * * Logic for a voicemail notification might look something like: * if (status.hasMessages) { diff --git a/dom/webidl/MozVoicemail.webidl b/dom/webidl/MozVoicemail.webidl index 468bae7daa1..22c91fc54f1 100644 --- a/dom/webidl/MozVoicemail.webidl +++ b/dom/webidl/MozVoicemail.webidl @@ -11,28 +11,26 @@ interface MozVoicemailStatus; interface MozVoicemail : EventTarget { /** - * The current voicemail status of a specified service, or null when the - * status is unknown. + * The current voicemail status, or null when the status is unknown */ - [Throws] - MozVoicemailStatus getStatus(optional unsigned long serviceId); + [GetterThrows] + readonly attribute MozVoicemailStatus? status; /** - * The voicemail box dialing number of a specified service, or null if one - * wasn't found. + * The voicemail box dialing number, or null if one wasn't found */ - [Throws] - DOMString getNumber(optional unsigned long serviceId); + [GetterThrows] + readonly attribute DOMString? number; /** - * The display name of the voicemail box dialing number of a specified service, - * or null if one wasn't found. + * The display name of the voicemail box dialing number, or null if one + * wasn't found */ - [Throws] - DOMString getDisplayName(optional unsigned long serviceId); + [GetterThrows] + readonly attribute DOMString? displayName; /** - * The current voicemail status has changed. + * The current voicemail status has changed */ attribute EventHandler onstatuschanged; }; From a8db10719fdfb6a1658cf043a16dd107bafebbfc Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Sun, 27 Oct 2013 20:46:46 +0800 Subject: [PATCH 19/53] Bug 814634 - part1 - WebAPI - WebVoicemail API: support multiple sim cards. r=khuey, r=gene.lian --- dom/voicemail/nsIDOMMozVoicemailStatus.idl | 9 +++----- dom/webidl/MozVoicemail.webidl | 24 ++++++++++++---------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/dom/voicemail/nsIDOMMozVoicemailStatus.idl b/dom/voicemail/nsIDOMMozVoicemailStatus.idl index ef391d92e9b..ff9239d65b6 100644 --- a/dom/voicemail/nsIDOMMozVoicemailStatus.idl +++ b/dom/voicemail/nsIDOMMozVoicemailStatus.idl @@ -6,13 +6,10 @@ #include "nsISupports.idl" -[scriptable, uuid(8c58859a-e006-466a-ad76-b188ba0918ab)] +[scriptable, uuid(efd352af-9eee-48dc-8e92-4d4fdbc89ecb)] interface nsIDOMMozVoicemailStatus : nsISupports { - /** - * There are voicemail messages waiting, but the count is unknown. - */ - const long MESSAGE_COUNT_UNKNOWN = -1; + readonly attribute unsigned long serviceId; /** * Whether or not there are messages waiting in the voicemail box @@ -22,7 +19,7 @@ interface nsIDOMMozVoicemailStatus : nsISupports /** * The total message count. Some voicemail indicators will only specify that * messages are waiting, but not the actual number. In that case, the value - * of messageCount will be MESSAGE_COUNT_UNKNOWN (-1). + * of messageCount will be -1, indicating the unknown message count. * * Logic for a voicemail notification might look something like: * if (status.hasMessages) { diff --git a/dom/webidl/MozVoicemail.webidl b/dom/webidl/MozVoicemail.webidl index 22c91fc54f1..468bae7daa1 100644 --- a/dom/webidl/MozVoicemail.webidl +++ b/dom/webidl/MozVoicemail.webidl @@ -11,26 +11,28 @@ interface MozVoicemailStatus; interface MozVoicemail : EventTarget { /** - * The current voicemail status, or null when the status is unknown + * The current voicemail status of a specified service, or null when the + * status is unknown. */ - [GetterThrows] - readonly attribute MozVoicemailStatus? status; + [Throws] + MozVoicemailStatus getStatus(optional unsigned long serviceId); /** - * The voicemail box dialing number, or null if one wasn't found + * The voicemail box dialing number of a specified service, or null if one + * wasn't found. */ - [GetterThrows] - readonly attribute DOMString? number; + [Throws] + DOMString getNumber(optional unsigned long serviceId); /** - * The display name of the voicemail box dialing number, or null if one - * wasn't found + * The display name of the voicemail box dialing number of a specified service, + * or null if one wasn't found. */ - [GetterThrows] - readonly attribute DOMString? displayName; + [Throws] + DOMString getDisplayName(optional unsigned long serviceId); /** - * The current voicemail status has changed + * The current voicemail status has changed. */ attribute EventHandler onstatuschanged; }; From 768d1cca3cbce5d5baebb8bece2d5c161932911e Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Sun, 27 Oct 2013 20:48:43 +0800 Subject: [PATCH 20/53] Bug 814634 - part2 - internal API. r=vicamo --- dom/voicemail/nsIVoicemailProvider.idl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/voicemail/nsIVoicemailProvider.idl b/dom/voicemail/nsIVoicemailProvider.idl index 115e35cc80a..05f1aba5869 100644 --- a/dom/voicemail/nsIVoicemailProvider.idl +++ b/dom/voicemail/nsIVoicemailProvider.idl @@ -22,7 +22,7 @@ interface nsIVoicemailListener : nsISupports * XPCOM component (in the content process) that provides the voicemail * information. */ -[scriptable, uuid(38746f3c-f4e3-4804-b900-ba2463b923c8)] +[scriptable, uuid(1bbfff90-88f7-4d73-896e-9620a0000ab0)] interface nsIVoicemailProvider : nsISupports { readonly attribute unsigned long voicemailDefaultServiceId; @@ -35,7 +35,7 @@ interface nsIVoicemailProvider : nsISupports void registerVoicemailMsg(in nsIVoicemailListener listener); void unregisterVoicemailMsg(in nsIVoicemailListener listener); - readonly attribute nsIDOMMozVoicemailStatus voicemailStatus; - readonly attribute DOMString voicemailNumber; - readonly attribute DOMString voicemailDisplayName; + nsIDOMMozVoicemailStatus getVoicemailStatus(in unsigned long clientId); + DOMString getVoicemailNumber(in unsigned long clientId); + DOMString getVoicemailDisplayName(in unsigned long clientId); }; From bfa34a8c3e123d7b7ce629bfba0d606af08ff938 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Tue, 29 Oct 2013 09:58:12 +0800 Subject: [PATCH 21/53] Bug 814634 - part3 - DOM. r=khuey --- dom/voicemail/Voicemail.cpp | 58 +++++++++++++++++++++++++++++++++---- dom/voicemail/Voicemail.h | 15 ++++++++-- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/dom/voicemail/Voicemail.cpp b/dom/voicemail/Voicemail.cpp index a4de3a68595..2b5c3bfec87 100644 --- a/dom/voicemail/Voicemail.cpp +++ b/dom/voicemail/Voicemail.cpp @@ -10,12 +10,14 @@ #include "nsIDOMMozVoicemailStatus.h" #include "nsIDOMMozVoicemailEvent.h" +#include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "nsDOMClassInfo.h" #include "nsServiceManagerUtils.h" #include "GeneratedEvents.h" #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1" +const char* kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; using namespace mozilla::dom; @@ -67,18 +69,48 @@ Voicemail::WrapObject(JSContext* aCx, JS::Handle aScope) return MozVoicemailBinding::Wrap(aCx, aScope, this); } +bool +Voicemail::IsValidServiceId(uint32_t aServiceId) const +{ + uint32_t numClients = mozilla::Preferences::GetUint(kPrefRilNumRadioInterfaces, 1); + + return aServiceId < numClients; +} + +bool +Voicemail::PassedOrDefaultServiceId(const Optional& aServiceId, + uint32_t& aResult) const +{ + if (aServiceId.WasPassed()) { + if (!IsValidServiceId(aServiceId.Value())) { + return false; + } + aResult = aServiceId.Value(); + } else { + mProvider->GetVoicemailDefaultServiceId(&aResult); + } + + return true; +} + // MozVoicemail WebIDL already_AddRefed -Voicemail::GetStatus(ErrorResult& aRv) const +Voicemail::GetStatus(const Optional& aServiceId, + ErrorResult& aRv) const { if (!mProvider) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } + uint32_t id = 0; + if (!PassedOrDefaultServiceId(aServiceId, id)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return nullptr; + } nsCOMPtr status; - nsresult rv = mProvider->GetVoicemailStatus(getter_AddRefs(status)); + nsresult rv = mProvider->GetVoicemailStatus(id, getter_AddRefs(status)); if (NS_FAILED(rv)) { aRv.Throw(rv); return nullptr; @@ -88,7 +120,8 @@ Voicemail::GetStatus(ErrorResult& aRv) const } void -Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const +Voicemail::GetNumber(const Optional& aServiceId, nsString& aNumber, + ErrorResult& aRv) const { aNumber.SetIsVoid(true); @@ -97,11 +130,18 @@ Voicemail::GetNumber(nsString& aNumber, ErrorResult& aRv) const return; } - aRv = mProvider->GetVoicemailNumber(aNumber); + uint32_t id = 0; + if (!PassedOrDefaultServiceId(aServiceId, id)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return; + } + + aRv = mProvider->GetVoicemailNumber(id, aNumber); } void -Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const +Voicemail::GetDisplayName(const Optional& aServiceId, nsString& aDisplayName, + ErrorResult& aRv) const { aDisplayName.SetIsVoid(true); @@ -110,7 +150,13 @@ Voicemail::GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const return; } - aRv = mProvider->GetVoicemailDisplayName(aDisplayName); + uint32_t id = 0; + if (!PassedOrDefaultServiceId(aServiceId, id)) { + aRv.Throw(NS_ERROR_INVALID_ARG); + return; + } + + aRv = mProvider->GetVoicemailDisplayName(id, aDisplayName); } // nsIVoicemailListener diff --git a/dom/voicemail/Voicemail.h b/dom/voicemail/Voicemail.h index 5ee5efef4c6..5da306ea22c 100644 --- a/dom/voicemail/Voicemail.h +++ b/dom/voicemail/Voicemail.h @@ -52,19 +52,28 @@ public: WrapObject(JSContext* aCx, JS::Handle aScope) MOZ_OVERRIDE; already_AddRefed - GetStatus(ErrorResult& aRv) const; + GetStatus(const Optional& aServiceId, ErrorResult& aRv) const; void - GetNumber(nsString& aNumber, ErrorResult& aRv) const; + GetNumber(const Optional& aServiceId, nsString& aNumber, + ErrorResult& aRv) const; void - GetDisplayName(nsString& aDisplayName, ErrorResult& aRv) const; + GetDisplayName(const Optional& aServiceId, nsString& aDisplayName, + ErrorResult& aRv) const; IMPL_EVENT_HANDLER(statuschanged) private: nsCOMPtr mProvider; nsRefPtr mListener; + + bool + IsValidServiceId(uint32_t aServiceId) const; + + bool + PassedOrDefaultServiceId(const Optional& aServiceId, + uint32_t& aResult) const; }; } // namespace dom From 048d298182edc32ef16a6986435a5e6817069c76 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Tsai Date: Tue, 29 Oct 2013 17:40:44 +0800 Subject: [PATCH 22/53] Bug 814634 - part4 - RIL and tests. r=vicamo --- dom/system/gonk/RILContentHelper.js | 86 ++++++++++++------- .../test/marionette/test_voicemail_number.js | 9 +- .../test_voicemail_statuschanged.js | 15 ++-- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index aadaf07f803..9441a518de7 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -271,7 +271,9 @@ MobileCellInfo.prototype = { cdmaNetworkId: -1 }; -function VoicemailStatus() {} +function VoicemailStatus(clientId) { + this.serviceId = clientId; +} VoicemailStatus.prototype = { QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozVoicemailStatus]), classID: VOICEMAILSTATUS_CID, @@ -284,8 +286,9 @@ VoicemailStatus.prototype = { // nsIDOMMozVoicemailStatus + serviceId: -1, hasMessages: false, - messageCount: Ci.nsIDOMMozVoicemailStatus.MESSAGE_COUNT_UNKNOWN, + messageCount: -1, // Count unknown. returnNumber: null, returnMessage: null }; @@ -451,6 +454,8 @@ function RILContentHelper() { debug("Number of clients: " + this.numClients); this.rilContexts = []; + this.voicemailInfos = []; + this.voicemailStatuses = []; for (let clientId = 0; clientId < this.numClients; clientId++) { this.rilContexts[clientId] = { cardState: RIL.GECKO_CARDSTATE_UNKNOWN, @@ -459,9 +464,10 @@ function RILContentHelper() { voiceConnectionInfo: new MobileConnectionInfo(), dataConnectionInfo: new MobileConnectionInfo() }; + + this.voicemailInfos[clientId] = new VoicemailInfo(); } - this.voicemailInfo = new VoicemailInfo(); this.voicemailDefaultServiceId = this.getVoicemailDefaultServiceId(); this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES); @@ -1361,7 +1367,8 @@ RILContentHelper.prototype = { _voicemailListeners: null, _iccListeners: null, - voicemailStatus: null, + voicemailInfos: null, + voicemailStatuses: null, voicemailDefaultServiceId: 0, getVoicemailDefaultServiceId: function getVoicemailDefaultServiceId() { @@ -1374,27 +1381,33 @@ RILContentHelper.prototype = { return id; }, - getVoicemailInfo: function getVoicemailInfo() { + getVoicemailInfo: function getVoicemailInfo(clientId) { // Get voicemail infomation by IPC only on first time. - this.getVoicemailInfo = function getVoicemailInfo() { - return this.voicemailInfo; + this.getVoicemailInfo = function getVoicemailInfo(clientId) { + return this.voicemailInfos[clientId]; }; - let voicemailInfo = - cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: 0})[0]; - if (voicemailInfo) { - this.updateInfo(voicemailInfo, this.voicemailInfo); + for (let cId = 0; cId < gNumRadioInterfaces; cId++) { + let voicemailInfo = + cpmm.sendSyncMessage("RIL:GetVoicemailInfo", {clientId: cId})[0]; + if (voicemailInfo) { + this.updateInfo(voicemailInfo, this.voicemailInfos[cId]); + } } - return this.voicemailInfo; + return this.voicemailInfos[clientId]; }, - get voicemailNumber() { - return this.getVoicemailInfo().number; + getVoicemailNumber: function getVoicemailNumber(clientId) { + return this.getVoicemailInfo(clientId).number; }, - get voicemailDisplayName() { - return this.getVoicemailInfo().displayName; + getVoicemailDisplayName: function getVoicemailDisplayName(clientId) { + return this.getVoicemailInfo(clientId).displayName; + }, + + getVoicemailStatus: function getVoicemailStatus(clientId) { + return this.voicemailStatuses[clientId]; }, registerListener: function registerListener(listenerType, clientId, listener) { @@ -1442,13 +1455,17 @@ RILContentHelper.prototype = { registerVoicemailMsg: function registerVoicemailMsg(listener) { debug("Registering for voicemail-related messages"); - //TODO: Bug 814634 - WebVoicemail API: support multiple sim cards. + // To follow the listener registration scheme, we add a dummy clientId 0. + // All voicemail events are routed to listener for client id 0. + // See |handleVoicemailNotification|. this.registerListener("_voicemailListeners", 0, listener); cpmm.sendAsyncMessage("RIL:RegisterVoicemailMsg"); }, unregisterVoicemailMsg: function unregisteVoicemailMsg(listener) { - //TODO: Bug 814634 - WebVoicemail API: support multiple sim cards. + // To follow the listener unregistration scheme, we add a dummy clientId 0. + // All voicemail events are routed to listener for client id 0. + // See |handleVoicemailNotification|. this.unregisterListener("_voicemailListeners", 0, listener); }, @@ -1619,7 +1636,7 @@ RILContentHelper.prototype = { this.handleVoicemailNotification(clientId, data); break; case "RIL:VoicemailInfoChanged": - this.updateInfo(data, this.voicemailInfo); + this.updateInfo(data, this.voicemailInfos[clientId]); break; case "RIL:CardLockResult": { let requestId = data.requestId; @@ -1835,41 +1852,44 @@ RILContentHelper.prototype = { this.fireRequestSuccess(message.requestId, result); }, - handleVoicemailNotification: function handleVoicemailNotification(clientId, message) { - // Bug 814634 - WebVoicemail API: support multiple sim cards + handleVoicemailNotification: function handleVoicemailNotification(clientId, + message) { let changed = false; - if (!this.voicemailStatus) { - this.voicemailStatus = new VoicemailStatus(); + if (!this.voicemailStatuses[clientId]) { + this.voicemailStatuses[clientId] = new VoicemailStatus(clientId); } - if (this.voicemailStatus.hasMessages != message.active) { + let voicemailStatus = this.voicemailStatuses[clientId]; + if (voicemailStatus.hasMessages != message.active) { changed = true; - this.voicemailStatus.hasMessages = message.active; + voicemailStatus.hasMessages = message.active; } - if (this.voicemailStatus.messageCount != message.msgCount) { + if (voicemailStatus.messageCount != message.msgCount) { changed = true; - this.voicemailStatus.messageCount = message.msgCount; + voicemailStatus.messageCount = message.msgCount; } else if (message.msgCount == -1) { // For MWI using DCS the message count is not available changed = true; } - if (this.voicemailStatus.returnNumber != message.returnNumber) { + if (voicemailStatus.returnNumber != message.returnNumber) { changed = true; - this.voicemailStatus.returnNumber = message.returnNumber; + voicemailStatus.returnNumber = message.returnNumber; } - if (this.voicemailStatus.returnMessage != message.returnMessage) { + if (voicemailStatus.returnMessage != message.returnMessage) { changed = true; - this.voicemailStatus.returnMessage = message.returnMessage; + voicemailStatus.returnMessage = message.returnMessage; } if (changed) { - this._deliverEvent(clientId, + // To follow the event delivering scheme, we add a dummy clientId 0. + // All voicemail events are routed to listener for client id 0. + this._deliverEvent(0, "_voicemailListeners", "notifyStatusChanged", - [this.voicemailStatus]); + [voicemailStatus]); } }, diff --git a/dom/voicemail/test/marionette/test_voicemail_number.js b/dom/voicemail/test/marionette/test_voicemail_number.js index bc5f1376d9e..3a8a56b7969 100644 --- a/dom/voicemail/test/marionette/test_voicemail_number.js +++ b/dom/voicemail/test/marionette/test_voicemail_number.js @@ -8,9 +8,14 @@ SpecialPowers.addPermission("voicemail", true, document); let voicemail = window.navigator.mozVoicemail; ok(voicemail instanceof MozVoicemail); +let serviceId = 0; + // These are the emulator's hard coded voicemail number and alphaId -is(voicemail.number, "+15552175049"); -is(voicemail.displayName, "Voicemail"); +is(voicemail.getNumber(serviceId), "+15552175049"); +is(voicemail.getDisplayName(serviceId), "Voicemail"); + +is(voicemail.getNumber(), "+15552175049"); +is(voicemail.getDisplayName(), "Voicemail"); SpecialPowers.removePermission("voicemail", document); finish(); diff --git a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js index 4816c182d52..a33a3f3c1c3 100644 --- a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js +++ b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js @@ -4,6 +4,8 @@ SpecialPowers.addPermission("voicemail", true, document); let voicemail = window.navigator.mozVoicemail; +let serviceId = 0; + ok(voicemail instanceof MozVoicemail); is(voicemail.status, null); @@ -42,10 +44,13 @@ function sendIndicatorPDU(pdu, listener, nextTest) { // See RadioInterfaceLayer.js / Bug #768441 function isVoicemailStatus(status) { - is(voicemail.status.hasMessages, status.hasMessages); - is(voicemail.status.messageCount, status.messageCount); - is(voicemail.status.returnNumber, status.returnNumber); - is(voicemail.status.returnMessage, status.returnMessage); + is(voicemail.getStatus(), status); + is(voicemail.getStatus(serviceId), status); + + is(voicemail.getStatus().hasMessages, status.hasMessages); + is(voicemail.getStatus().messageCount, status.messageCount); + is(voicemail.getStatus().returnNumber, status.returnNumber); + is(voicemail.getStatus().returnMessage, status.returnMessage); } const MWI_PDU_PREFIX = "0000"; @@ -80,7 +85,7 @@ function testLevel1Indicator() { // TODO: bug 905228 - MozVoicemailStatus is not defined. //ok(status instanceof MozVoicemailStatus); is(status.hasMessages, true); - is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN); + is(status.messageCount, -1); is(status.returnNumber, MWI_LEVEL1_SENDER); is(status.returnMessage, MWI_DEFAULT_BODY); isVoicemailStatus(status); From 63c4e672e84f079762a17fabca2e81316dfcc4b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabrice=20Desr=C3=A9?= Date: Tue, 5 Nov 2013 22:17:03 -0800 Subject: [PATCH 23/53] Bug 935340 - Remove unused IDL in b2g/components r=gwagner --- b2g/components/b2g.idl | 12 ------------ b2g/components/moz.build | 4 ---- b2g/installer/package-manifest.in | 2 -- 3 files changed, 18 deletions(-) delete mode 100644 b2g/components/b2g.idl diff --git a/b2g/components/b2g.idl b/b2g/components/b2g.idl deleted file mode 100644 index 6f24657b6a9..00000000000 --- a/b2g/components/b2g.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "domstubs.idl" - -[scriptable, uuid(3615a616-571d-4194-bf54-ccf546067b14)] -interface nsIB2GCameraContent : nsISupports -{ - /* temporary solution, waiting for getUserMedia */ - DOMString getCameraURI([optional] in jsval options); -}; diff --git a/b2g/components/moz.build b/b2g/components/moz.build index 6f7cd6b0e1d..a1c9ff93684 100644 --- a/b2g/components/moz.build +++ b/b2g/components/moz.build @@ -6,10 +6,6 @@ TEST_DIRS += ['test'] -XPIDL_SOURCES += [ - 'b2g.idl', -] - MODULE = 'B2GComponents' EXTRA_COMPONENTS += [ diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 39bd1ee846f..d6deb9132dd 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -749,8 +749,6 @@ bin/components/@DLL_PREFIX@nkgnomevfs@DLL_SUFFIX@ @BINPATH@/chrome/chrome@JAREXT@ @BINPATH@/chrome/chrome.manifest @BINPATH@/components/B2GComponents.manifest -@BINPATH@/components/B2GComponents.xpt -@BINPATH@/components/CameraContent.js @BINPATH@/@DLL_PREFIX@omxplugin@DLL_SUFFIX@ #ifdef ENABLE_MARIONETTE @BINPATH@/chrome/marionette@JAREXT@ From 596403d7c9a02ee5ec811f4119ef6e4d438ef413 Mon Sep 17 00:00:00 2001 From: Chuck Lee Date: Mon, 16 Sep 2013 10:12:35 +0800 Subject: [PATCH 24/53] Bug 859215 - 0001. IDL change. r=vicamo --- dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl | 5 ++++- dom/mobilemessage/interfaces/nsISmsService.idl | 5 ++++- dom/system/gonk/nsIRadioInterfaceLayer.idl | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl b/dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl index c84e6553fe6..fee6bf805e9 100644 --- a/dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl +++ b/dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl @@ -11,7 +11,7 @@ interface nsIDOMDOMCursor; interface nsIDOMDOMRequest; interface nsIDOMBlob; -[scriptable, builtinclass, uuid(0e4ff35e-ab84-434a-96b4-46807798cc7e)] +[scriptable, builtinclass, uuid(cfcc7067-083f-4e09-91aa-75067a721b70)] interface nsIDOMMozMobileMessageManager : nsIDOMEventTarget { nsIDOMDOMRequest getSegmentInfoForText(in DOMString text); @@ -65,6 +65,9 @@ interface nsIDOMMozMobileMessageManager : nsIDOMEventTarget nsIDOMDOMRequest retrieveMMS(in long id); + [optional_argc] + nsIDOMDOMRequest getSmscAddress([optional] in unsigned long serviceId); + [implicit_jscontext] attribute jsval onreceived; [implicit_jscontext] attribute jsval onretrieving; [implicit_jscontext] attribute jsval onsending; diff --git a/dom/mobilemessage/interfaces/nsISmsService.idl b/dom/mobilemessage/interfaces/nsISmsService.idl index 464538803fc..089b215de64 100644 --- a/dom/mobilemessage/interfaces/nsISmsService.idl +++ b/dom/mobilemessage/interfaces/nsISmsService.idl @@ -13,7 +13,7 @@ interface nsIMobileMessageCallback; #define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1" %} -[scriptable, builtinclass, uuid(6ac68d50-3d60-11e3-a8ff-ab5ddef5f2ba)] +[scriptable, builtinclass, uuid(0a28f55b-95fe-4b32-994f-b08fe8edf77a)] interface nsISmsService : nsISupports { readonly attribute unsigned long smsDefaultServiceId; @@ -32,4 +32,7 @@ interface nsISmsService : nsISupports boolean isSilentNumber(in DOMString number); void addSilentNumber(in DOMString number); void removeSilentNumber(in DOMString number); + + void getSmscAddress(in unsigned long serviceId, + in nsIMobileMessageCallback request); }; diff --git a/dom/system/gonk/nsIRadioInterfaceLayer.idl b/dom/system/gonk/nsIRadioInterfaceLayer.idl index 3338eee2ccc..ac3a9a46b16 100644 --- a/dom/system/gonk/nsIRadioInterfaceLayer.idl +++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl @@ -97,7 +97,7 @@ interface nsIRilSendWorkerMessageCallback : nsISupports boolean handleResponse(in jsval response); }; -[scriptable, uuid(61a8ca67-6113-4cd0-b443-e045f09863ed)] +[scriptable, uuid(5b14cf79-2846-4226-b07f-9b9977b525fe)] interface nsIRadioInterface : nsISupports { readonly attribute nsIRilContext rilContext; @@ -128,6 +128,8 @@ interface nsIRadioInterface : nsISupports void sendWorkerMessage(in DOMString type, [optional] in jsval message, [optional] in nsIRilSendWorkerMessageCallback callback); + + void getSmscAddress(in nsIMobileMessageCallback request); }; [scriptable, uuid(70d3a18c-4063-11e3-89de-0f9ec19fd803)] From 20fee65b25455be2d286751673f7288dc911e7e9 Mon Sep 17 00:00:00 2001 From: Chuck Lee Date: Mon, 16 Sep 2013 10:12:38 +0800 Subject: [PATCH 25/53] Bug 859215 - 0002. IPDL change to support get SMSC address. r=vicamo --- .../interfaces/nsIMobileMessageCallback.idl | 8 ++++- .../src/MobileMessageCallback.cpp | 22 +++++++++++++ dom/mobilemessage/src/ipc/PSms.ipdl | 6 ++++ dom/mobilemessage/src/ipc/PSmsRequest.ipdl | 12 +++++++ dom/mobilemessage/src/ipc/SmsChild.cpp | 6 ++++ dom/mobilemessage/src/ipc/SmsIPCService.cpp | 7 +++++ dom/mobilemessage/src/ipc/SmsParent.cpp | 31 +++++++++++++++++++ dom/mobilemessage/src/ipc/SmsParent.h | 3 ++ 8 files changed, 94 insertions(+), 1 deletion(-) mode change 100755 => 100644 dom/mobilemessage/src/ipc/SmsParent.cpp diff --git a/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl b/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl index 872e8f36d20..c57f3f15b77 100644 --- a/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl +++ b/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl @@ -14,7 +14,7 @@ dictionary SmsThreadListItem unsigned long long unreadCount; }; -[scriptable, uuid(58780660-4080-11e3-8397-a7bb1b58cf12)] +[scriptable, uuid(0ee2ada1-fa98-40f1-adb3-0d7fd6df3f48)] interface nsIMobileMessageCallback : nsISupports { /** @@ -54,4 +54,10 @@ interface nsIMobileMessageCallback : nsISupports void notifySegmentInfoForTextGot(in nsIDOMMozSmsSegmentInfo info); void notifyGetSegmentInfoForTextFailed(in long error); + + /** + * SMSC Address get/set result + */ + void notifyGetSmscAddress(in DOMString aSmscAddress); + void notifyGetSmscAddressFailed(in long error); }; diff --git a/dom/mobilemessage/src/MobileMessageCallback.cpp b/dom/mobilemessage/src/MobileMessageCallback.cpp index 29f2ad44127..2987426d207 100644 --- a/dom/mobilemessage/src/MobileMessageCallback.cpp +++ b/dom/mobilemessage/src/MobileMessageCallback.cpp @@ -210,6 +210,28 @@ MobileMessageCallback::NotifyGetSegmentInfoForTextFailed(int32_t aError) return NotifyError(aError, true); } +NS_IMETHODIMP +MobileMessageCallback::NotifyGetSmscAddress(const nsAString& aSmscAddress) +{ + AutoJSContext cx; + JSString* smsc = JS_NewUCStringCopyN(cx, + static_cast(aSmscAddress.BeginReading()), + aSmscAddress.Length()); + + if (!smsc) { + return NotifyError(nsIMobileMessageCallback::INTERNAL_ERROR); + } + + JS::Rooted val(cx, STRING_TO_JSVAL(smsc)); + return NotifySuccess(val); +} + +NS_IMETHODIMP +MobileMessageCallback::NotifyGetSmscAddressFailed(int32_t aError) +{ + return NotifyError(aError); +} + } // namesapce mobilemessage } // namespace dom } // namespace mozilla diff --git a/dom/mobilemessage/src/ipc/PSms.ipdl b/dom/mobilemessage/src/ipc/PSms.ipdl index a2366b8cfce..50371cc22ec 100644 --- a/dom/mobilemessage/src/ipc/PSms.ipdl +++ b/dom/mobilemessage/src/ipc/PSms.ipdl @@ -74,6 +74,11 @@ struct CreateThreadCursorRequest { }; +struct GetSmscAddressRequest +{ + uint32_t serviceId; +}; + union IPCSmsRequest { SendMessageRequest; @@ -82,6 +87,7 @@ union IPCSmsRequest DeleteMessageRequest; MarkMessageReadRequest; GetSegmentInfoForTextRequest; + GetSmscAddressRequest; }; union IPCMobileMessageCursor diff --git a/dom/mobilemessage/src/ipc/PSmsRequest.ipdl b/dom/mobilemessage/src/ipc/PSmsRequest.ipdl index dfa6c70e24a..1aab10c62c0 100644 --- a/dom/mobilemessage/src/ipc/PSmsRequest.ipdl +++ b/dom/mobilemessage/src/ipc/PSmsRequest.ipdl @@ -73,6 +73,16 @@ struct ReplyGetSegmentInfoForTextFail int32_t error; }; +struct ReplyGetSmscAddress +{ + nsString smscAddress; +}; + +struct ReplyGetSmscAddressFail +{ + int32_t error; +}; + union MessageReply { ReplyMessageSend; @@ -85,6 +95,8 @@ union MessageReply ReplyMarkeMessageReadFail; ReplyGetSegmentInfoForText; ReplyGetSegmentInfoForTextFail; + ReplyGetSmscAddress; + ReplyGetSmscAddressFail; }; } // namespace mobilemessage diff --git a/dom/mobilemessage/src/ipc/SmsChild.cpp b/dom/mobilemessage/src/ipc/SmsChild.cpp index 11fa7e440fb..0cc9eb682d8 100644 --- a/dom/mobilemessage/src/ipc/SmsChild.cpp +++ b/dom/mobilemessage/src/ipc/SmsChild.cpp @@ -216,6 +216,12 @@ SmsRequestChild::Recv__delete__(const MessageReply& aReply) mReplyRequest->NotifyGetSegmentInfoForTextFailed( aReply.get_ReplyGetSegmentInfoForTextFail().error()); break; + case MessageReply::TReplyGetSmscAddress: + mReplyRequest->NotifyGetSmscAddress(aReply.get_ReplyGetSmscAddress().smscAddress()); + break; + case MessageReply::TReplyGetSmscAddressFail: + mReplyRequest->NotifyGetSmscAddressFailed(aReply.get_ReplyGetSmscAddressFail().error()); + break; default: MOZ_CRASH("Received invalid response parameters!"); } diff --git a/dom/mobilemessage/src/ipc/SmsIPCService.cpp b/dom/mobilemessage/src/ipc/SmsIPCService.cpp index 1af4464bc75..4fb9850eb47 100644 --- a/dom/mobilemessage/src/ipc/SmsIPCService.cpp +++ b/dom/mobilemessage/src/ipc/SmsIPCService.cpp @@ -166,6 +166,13 @@ SmsIPCService::GetSegmentInfoForText(const nsAString& aText, aRequest); } +NS_IMETHODIMP +SmsIPCService::GetSmscAddress(uint32_t aServiceId, + nsIMobileMessageCallback* aRequest) +{ + return SendRequest(GetSmscAddressRequest(aServiceId), aRequest); +} + NS_IMETHODIMP SmsIPCService::Send(uint32_t aServiceId, const nsAString& aNumber, diff --git a/dom/mobilemessage/src/ipc/SmsParent.cpp b/dom/mobilemessage/src/ipc/SmsParent.cpp old mode 100755 new mode 100644 index 9b465f167bd..3295e582981 --- a/dom/mobilemessage/src/ipc/SmsParent.cpp +++ b/dom/mobilemessage/src/ipc/SmsParent.cpp @@ -367,6 +367,8 @@ SmsParent::RecvPSmsRequestConstructor(PSmsRequestParent* aActor, return actor->DoRequest(aRequest.get_MarkMessageReadRequest()); case IPCSmsRequest::TGetSegmentInfoForTextRequest: return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest()); + case IPCSmsRequest::TGetSmscAddressRequest: + return actor->DoRequest(aRequest.get_GetSmscAddressRequest()); default: MOZ_CRASH("Unknown type!"); } @@ -513,6 +515,23 @@ SmsRequestParent::DoRequest(const GetMessageRequest& aRequest) return true; } +bool +SmsRequestParent::DoRequest(const GetSmscAddressRequest& aRequest) +{ + nsresult rv = NS_ERROR_FAILURE; + + nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); + if (smsService) { + rv = smsService->GetSmscAddress(aRequest.serviceId(), this); + } + + if (NS_FAILED(rv)) { + return NS_SUCCEEDED(NotifyGetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR)); + } + + return true; +} + bool SmsRequestParent::DoRequest(const DeleteMessageRequest& aRequest) { @@ -684,6 +703,18 @@ SmsRequestParent::NotifyGetSegmentInfoForTextFailed(int32_t aError) return SendReply(ReplyGetSegmentInfoForTextFail(aError)); } +NS_IMETHODIMP +SmsRequestParent::NotifyGetSmscAddress(const nsAString& aSmscAddress) +{ + return SendReply(ReplyGetSmscAddress(nsString(aSmscAddress))); +} + +NS_IMETHODIMP +SmsRequestParent::NotifyGetSmscAddressFailed(int32_t aError) +{ + return SendReply(ReplyGetSmscAddressFail(aError)); +} + /******************************************************************************* * MobileMessageCursorParent ******************************************************************************/ diff --git a/dom/mobilemessage/src/ipc/SmsParent.h b/dom/mobilemessage/src/ipc/SmsParent.h index 22908f1d776..b5cef03a0cc 100644 --- a/dom/mobilemessage/src/ipc/SmsParent.h +++ b/dom/mobilemessage/src/ipc/SmsParent.h @@ -120,6 +120,9 @@ protected: bool DoRequest(const GetSegmentInfoForTextRequest& aRequest); + bool + DoRequest(const GetSmscAddressRequest& aRequest); + nsresult SendReply(const MessageReply& aReply); }; From da65bd5c423159af2ec90f3e4d9de11c59e68825 Mon Sep 17 00:00:00 2001 From: Chuck Lee Date: Mon, 16 Sep 2013 10:12:40 +0800 Subject: [PATCH 26/53] Bug 859215 - 0003. Get SMSC address in RIL. r=vicamo --- dom/system/gonk/RadioInterfaceLayer.js | 12 ++++++++++ dom/system/gonk/ril_worker.js | 33 +++++++++++++++++++------- 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 27f2afca807..25db90bad98 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -2925,6 +2925,18 @@ RadioInterface.prototype = { request.notifySegmentInfoForTextGot(result); }, + getSmscAddress: function getSmscAddress(request) { + this.workerMessenger.send("getSmscAddress", + null, + (function(response) { + if (!response.errorMsg) { + request.notifyGetSmscAddress(response.smscAddress); + } else { + request.notifyGetSmscAddressFailed(response.errorMsg); + } + }).bind(this)); + }, + sendSMS: function sendSMS(number, message, silent, request) { let strict7BitEncoding; try { diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js index 4d3333e8574..c06d7eda50f 100644 --- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -1793,19 +1793,30 @@ let RIL = { /** * Get the Short Message Service Center address. */ - getSMSCAddress: function getSMSCAddress() { - Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS); + getSmscAddress: function getSmscAddress(options) { + if (!this.SMSC) { + Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS, options); + return; + } + + if (!options || options.rilMessageType !== "getSmscAddress") { + return; + } + + options.smscAddress = this.SMSC; + options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; + this.sendChromeMessage(options); }, /** * Set the Short Message Service Center address. * - * @param SMSC + * @param smscAddress * Short Message Service Center address in PDU format. */ - setSMSCAddress: function setSMSCAddress(options) { - Buf.newParcel(REQUEST_SET_SMSC_ADDRESS); - Buf.writeString(options.SMSC); + setSmscAddress: function setSmscAddress(options) { + Buf.newParcel(REQUEST_SET_SMSC_ADDRESS, options); + Buf.writeString(options.smscAddress); Buf.sendParcel(); }, @@ -3330,7 +3341,7 @@ let RIL = { let rs = this.voiceRegistrationState; let stateChanged = this._processCREG(rs, state); if (stateChanged && rs.connected) { - RIL.getSMSCAddress(); + RIL.getSmscAddress(); } let cell = rs.cell; @@ -5914,11 +5925,15 @@ RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = function REQUEST_EXIT_EMERGENCY_CALL this.sendChromeMessage(options); }; RIL[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS(length, options) { - if (options.rilRequestError) { + this.SMSC = options.rilRequestError ? null : Buf.readString(); + + if (!options || options.rilMessageType !== "getSmscAddress") { return; } - this.SMSC = Buf.readString(); + options.smscAddress = this.SMSC; + options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; + this.sendChromeMessage(options); }; RIL[REQUEST_SET_SMSC_ADDRESS] = null; RIL[REQUEST_REPORT_SMS_MEMORY_STATUS] = null; From 8de4766cade0e05485973de926bf94759cd6549e Mon Sep 17 00:00:00 2001 From: Chuck Lee Date: Mon, 16 Sep 2013 10:12:43 +0800 Subject: [PATCH 27/53] Bug 859215 - 0004. Get SMSC address in mobilemessage. r=vicamo --- .../src/MobileMessageManager.cpp | 22 +++++++++++++++++++ dom/mobilemessage/src/android/SmsService.cpp | 8 +++++++ dom/mobilemessage/src/fallback/SmsService.cpp | 8 +++++++ dom/mobilemessage/src/gonk/SmsService.cpp | 13 +++++++++++ 4 files changed, 51 insertions(+) diff --git a/dom/mobilemessage/src/MobileMessageManager.cpp b/dom/mobilemessage/src/MobileMessageManager.cpp index 1f22afc82bf..0464e70fe33 100644 --- a/dom/mobilemessage/src/MobileMessageManager.cpp +++ b/dom/mobilemessage/src/MobileMessageManager.cpp @@ -525,5 +525,27 @@ MobileMessageManager::Observe(nsISupports* aSubject, const char* aTopic, return NS_OK; } +NS_IMETHODIMP +MobileMessageManager::GetSmscAddress(uint32_t aServiceId, uint8_t aArgc, + nsIDOMDOMRequest** aRequest) +{ + nsCOMPtr smsService = do_GetService(SMS_SERVICE_CONTRACTID); + NS_ENSURE_TRUE(smsService, NS_ERROR_FAILURE); + + nsresult rv; + if (aArgc != 1) { + rv = smsService->GetSmsDefaultServiceId(&aServiceId); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsRefPtr request = new DOMRequest(GetOwner()); + nsCOMPtr msgCallback = new MobileMessageCallback(request); + rv = smsService->GetSmscAddress(aServiceId, msgCallback); + NS_ENSURE_SUCCESS(rv, rv); + + request.forget(aRequest); + return NS_OK; +} + } // namespace dom } // namespace mozilla diff --git a/dom/mobilemessage/src/android/SmsService.cpp b/dom/mobilemessage/src/android/SmsService.cpp index 2a92f714cd6..30c61a15774 100644 --- a/dom/mobilemessage/src/android/SmsService.cpp +++ b/dom/mobilemessage/src/android/SmsService.cpp @@ -80,6 +80,14 @@ SmsService::RemoveSilentNumber(const nsAString& aNumber) return NS_ERROR_NOT_IMPLEMENTED; } +NS_IMETHODIMP +SmsService::GetSmscAddress(uint32_t aServiceId, + nsIMobileMessageCallback *aRequest) +{ + // TODO: bug 878016 - Android backend: implement getSMSCAddress/setSMSCAddress + return NS_OK; +} + } // namespace mobilemessage } // namespace dom } // namespace mozilla diff --git a/dom/mobilemessage/src/fallback/SmsService.cpp b/dom/mobilemessage/src/fallback/SmsService.cpp index f547d282283..218d2e7074b 100644 --- a/dom/mobilemessage/src/fallback/SmsService.cpp +++ b/dom/mobilemessage/src/fallback/SmsService.cpp @@ -68,6 +68,14 @@ SmsService::RemoveSilentNumber(const nsAString& aNumber) return NS_ERROR_FAILURE; } +NS_IMETHODIMP +SmsService::GetSmscAddress(uint32_t aServiceId, + nsIMobileMessageCallback *aRequest) +{ + NS_ERROR("We should not be here!"); + return NS_OK; +} + } // namespace mobilemessage } // namespace dom } // namespace mozilla diff --git a/dom/mobilemessage/src/gonk/SmsService.cpp b/dom/mobilemessage/src/gonk/SmsService.cpp index 3471b1ef607..fd56c5b234d 100644 --- a/dom/mobilemessage/src/gonk/SmsService.cpp +++ b/dom/mobilemessage/src/gonk/SmsService.cpp @@ -149,6 +149,19 @@ SmsService::RemoveSilentNumber(const nsAString& aNumber) return NS_OK; } +NS_IMETHODIMP +SmsService::GetSmscAddress(uint32_t aServiceId, + nsIMobileMessageCallback *aRequest) +{ + nsCOMPtr radioInterface; + if (mRil) { + mRil->GetRadioInterface(aServiceId, getter_AddRefs(radioInterface)); + } + NS_ENSURE_TRUE(radioInterface, NS_ERROR_FAILURE); + + return radioInterface->GetSmscAddress(aRequest); +} + } // namespace mobilemessage } // namespace dom } // namespace mozilla From 350c38679d1356a64690272fd714bb48b0dc3fee Mon Sep 17 00:00:00 2001 From: Chuck Lee Date: Mon, 16 Sep 2013 10:12:45 +0800 Subject: [PATCH 28/53] Bug 859215 - 0005. Marionette test for read SMSC address. r=vicamo. --- .../tests/marionette/manifest.ini | 1 + .../tests/marionette/test_smsc_address.js | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 dom/mobilemessage/tests/marionette/test_smsc_address.js diff --git a/dom/mobilemessage/tests/marionette/manifest.ini b/dom/mobilemessage/tests/marionette/manifest.ini index d6e0b5bc5d9..b61c693de1a 100644 --- a/dom/mobilemessage/tests/marionette/manifest.ini +++ b/dom/mobilemessage/tests/marionette/manifest.ini @@ -36,4 +36,5 @@ qemu = true [test_invalid_address.js] [test_mmsmessage_attachments.js] [test_getthreads.js] +[test_smsc_address.js] [test_dsds_default_service_id.js] diff --git a/dom/mobilemessage/tests/marionette/test_smsc_address.js b/dom/mobilemessage/tests/marionette/test_smsc_address.js new file mode 100644 index 00000000000..0fe6e3acb55 --- /dev/null +++ b/dom/mobilemessage/tests/marionette/test_smsc_address.js @@ -0,0 +1,78 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +MARIONETTE_TIMEOUT = 60000; + +SpecialPowers.addPermission("sms", true, document); + +// Expected SMSC addresses of emulator +const SMSC = "\"+123456789\",145"; + +let manager = window.navigator.mozMobileMessage; + +let tasks = { + // List of test fuctions. Each of them should call |tasks.next()| when + // completed or |tasks.finish()| to jump to the last one. + _tasks: [], + _nextTaskIndex: 0, + + push: function push(func) { + this._tasks.push(func); + }, + + next: function next() { + let index = this._nextTaskIndex++; + let task = this._tasks[index]; + try { + task(); + } catch (ex) { + ok(false, "test task[" + index + "] throws: " + ex); + // Run last task as clean up if possible. + if (index != this._tasks.length - 1) { + this.finish(); + } + } + }, + + finish: function finish() { + this._tasks[this._tasks.length - 1](); + }, + + run: function run() { + this.next(); + } +}; + +tasks.push(function init() { + log("Initialize test object."); + ok(manager instanceof MozMobileMessageManager, + "manager is instance of " + manager.constructor); + tasks.next(); +}); + +tasks.push(function readSmscAddress() { + log("read SMSC address"); + + let req = manager.getSmscAddress(); + ok(req, "DOMRequest object for getting smsc address"); + + req.onsuccess = function(e) { + is(e.target.result, SMSC, "SMSC address"); + tasks.next(); + }; + + req.onerror = function(error) { + ok(false, "readSmscAddress(): Received 'onerror'"); + tasks.finish(); + }; +}); + +// WARNING: All tasks should be pushed before this!!! +tasks.push(function cleanUp() { + manager.onreceived = null; + SpecialPowers.removePermission("sms", document); + finish(); +}); + +// Start the test +tasks.run(); From 033c22b2b7d7f5712b6c1904942fb1837f7e24b4 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 5 Nov 2013 12:59:33 -0800 Subject: [PATCH 29/53] Bug 918053 - TA__discoverSources should use Debugger.Source; r=past --- toolkit/devtools/server/actors/script.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index aba0daedc94..f11ceb4870b 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -1561,19 +1561,18 @@ ThreadActor.prototype = { /** * Get the script and source lists from the debugger. - * - * TODO bug 637572: we should be dealing with sources directly, not inferring - * them through scripts. */ _discoverSources: function TA__discoverSources() { // Only get one script per url. - let scriptsByUrl = {}; + const sourcesToScripts = new Map(); for (let s of this.dbg.findScripts()) { - scriptsByUrl[s.url] = s; + if (s.source) { + sourcesToScripts.set(s.source, s); + } } - return all([this.sources.sourcesForScript(scriptsByUrl[s]) - for (s of Object.keys(scriptsByUrl))]); + return all([this.sources.sourcesForScript(script) + for (script of sourcesToScripts.values())]); }, onSources: function TA_onSources(aRequest) { From b015efce4942a8e50690a5b4f4f53ce1e85ff578 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Tue, 5 Nov 2013 13:51:58 -0800 Subject: [PATCH 30/53] Bug 935220: Uplift Add-on SDK to Firefox. r=me https://github.com/mozilla/addon-sdk/compare/firefox27...50697e6182cb4f79f9605b7cd1d1f5084cfaf03f --HG-- rename : addon-sdk/source/data/index.html => addon-sdk/source/test/addons/addon-page/data/index.html rename : addon-sdk/source/test/favicon-helpers.js => addon-sdk/source/test/addons/places/favicon-helpers.js rename : addon-sdk/source/test/places-helper.js => addon-sdk/source/test/addons/places/places-helper.js rename : addon-sdk/source/data/test-trusted-document.html => addon-sdk/source/test/addons/symbiont/data/test-trusted-document.html rename : addon-sdk/source/data/index.html => addon-sdk/source/test/fixtures/index.html rename : addon-sdk/source/data/mofo_logo.SVG => addon-sdk/source/test/fixtures/mofo_logo.SVG rename : addon-sdk/source/data/moz_favicon.ico => addon-sdk/source/test/fixtures/moz_favicon.ico rename : addon-sdk/source/data/pagemod-css-include-file.css => addon-sdk/source/test/fixtures/pagemod-css-include-file.css rename : addon-sdk/source/data/test-content-symbiont.js => addon-sdk/source/test/fixtures/test-content-symbiont.js rename : addon-sdk/source/data/test-context-menu.js => addon-sdk/source/test/fixtures/test-context-menu.js rename : addon-sdk/source/data/test-iframe-postmessage.html => addon-sdk/source/test/fixtures/test-iframe-postmessage.html rename : addon-sdk/source/data/test-iframe.html => addon-sdk/source/test/fixtures/test-iframe.html rename : addon-sdk/source/data/test-iframe.js => addon-sdk/source/test/fixtures/test-iframe.js rename : addon-sdk/source/data/test-message-manager.js => addon-sdk/source/test/fixtures/test-message-manager.js rename : addon-sdk/source/data/test-net-url.txt => addon-sdk/source/test/fixtures/test-net-url.txt rename : addon-sdk/source/data/test-page-mod.html => addon-sdk/source/test/fixtures/test-page-mod.html rename : addon-sdk/source/data/test-page-worker.html => addon-sdk/source/test/fixtures/test-page-worker.html rename : addon-sdk/source/data/test-page-worker.js => addon-sdk/source/test/fixtures/test-page-worker.js rename : addon-sdk/source/data/test-sidebar-addon-global.html => addon-sdk/source/test/fixtures/test-sidebar-addon-global.html rename : addon-sdk/source/data/test-trusted-document.html => addon-sdk/source/test/fixtures/test-trusted-document.html rename : addon-sdk/source/data/test.html => addon-sdk/source/test/fixtures/test.html rename : addon-sdk/source/data/testLocalXhr.json => addon-sdk/source/test/fixtures/testLocalXhr.json --- addon-sdk/Makefile.in | 1 - .../doc/module-source/sdk/places/favicon.md | 2 +- .../source/doc/module-source/sdk/tabs.md | 23 +- addon-sdk/source/doc/module-source/sdk/ui.md | 214 ------- .../doc/module-source/sdk/ui/sidebar.md | 378 +++++++++++ .../media/screenshots/sidebar-menu.png | Bin 0 -> 14961 bytes .../media/screenshots/sidebar.png | Bin 0 -> 120085 bytes .../examples/library-detector/package.json | 2 +- addon-sdk/source/lib/sdk/content/symbiont.js | 3 +- addon-sdk/source/lib/sdk/io/buffer.js | 341 ++++++---- addon-sdk/source/lib/sdk/io/fs.js | 7 +- addon-sdk/source/lib/sdk/io/stream.js | 2 +- addon-sdk/source/lib/sdk/system/events.js | 16 +- addon-sdk/source/lib/sdk/ui/sidebar.js | 34 +- .../source/lib/sdk/ui/sidebar/contract.js | 4 +- addon-sdk/source/lib/sdk/ui/sidebar/view.js | 13 +- addon-sdk/source/lib/sdk/window/helpers.js | 21 +- addon-sdk/source/lib/sdk/window/utils.js | 3 +- addon-sdk/source/lib/toolkit/loader.js | 50 +- .../source/python-lib/cuddlefish/__init__.py | 8 +- .../source/python-lib/cuddlefish/manifest.py | 8 +- addon-sdk/source/python-lib/cuddlefish/rdf.py | 2 +- .../source/python-lib/cuddlefish/templates.py | 2 +- .../bug-715340-files/pkg-1-pack/package.json | 2 +- .../pkg-2-unpack/package.json | 2 +- .../bug-715340-files/pkg-3-pack/package.json | 2 +- .../bug-906359-files/fullName/package.json | 9 + .../tests/bug-906359-files/none/package.json | 9 + .../tests/bug-906359-files/title/package.json | 9 + .../packages/no-prefs/package.json | 2 +- .../packages/simple-prefs/package.json | 2 +- .../python-lib/cuddlefish/tests/test_init.py | 2 +- .../cuddlefish/tests/test_linker.py | 7 +- .../python-lib/cuddlefish/tests/test_rdf.py | 9 + .../python-lib/cuddlefish/tests/test_xpi.py | 5 +- .../addons/addon-page}/data/index.html | 0 .../addon-page/main.js} | 2 +- .../test/addons/addon-page/package.json | 3 + .../{ => addons/places}/favicon-helpers.js | 0 addon-sdk/source/test/addons/places/main.js | 24 + .../source/test/addons/places/package.json | 3 + .../test/{ => addons/places}/places-helper.js | 0 .../places/tests}/test-places-bookmarks.js | 4 +- .../places/tests}/test-places-events.js | 3 +- .../places/tests}/test-places-favicon.js | 6 +- .../places/tests}/test-places-history.js | 4 +- .../places/tests}/test-places-host.js | 4 +- .../places/tests}/test-places-utils.js | 2 - .../source/test/addons/self/data/data.md | 1 + addon-sdk/source/test/addons/self/main.js | 20 + .../source/test/addons/self/package.json | 3 + .../symbiont}/data/test-trusted-document.html | 0 addon-sdk/source/test/addons/symbiont/main.js | 39 ++ .../source/test/addons/symbiont/package.json | 3 + .../source/test/buffers/test-read-types.js | 368 +++++++++++ .../source/test/buffers/test-write-types.js | 602 ++++++++++++++++++ addon-sdk/source/test/fixtures.js | 6 + addon-sdk/source/test/fixtures/index.html | 13 + .../test/fixtures/loader/json/invalid.json | 3 + .../test/fixtures/loader/json/manifest.json | 14 + .../fixtures/loader/json/nodotjson.json.js | 4 + .../test/fixtures/loader/json/test.json | 3 + .../test/fixtures/loader/json/test.json.js | 3 + .../{data => test/fixtures}/mofo_logo.SVG | 0 .../{data => test/fixtures}/moz_favicon.ico | Bin .../fixtures}/pagemod-css-include-file.css | 0 .../fixtures}/test-content-symbiont.js | 0 .../fixtures}/test-context-menu.js | 0 .../fixtures}/test-iframe-postmessage.html | 0 .../{data => test/fixtures}/test-iframe.html | 0 .../{data => test/fixtures}/test-iframe.js | 0 .../fixtures}/test-message-manager.js | 0 .../{data => test/fixtures}/test-net-url.txt | 0 .../fixtures}/test-page-mod.html | 0 .../fixtures}/test-page-worker.html | 0 .../fixtures}/test-page-worker.js | 0 .../fixtures}/test-sidebar-addon-global.html | 0 .../test/fixtures/test-trusted-document.html | 20 + .../source/{data => test/fixtures}/test.html | 0 .../{data => test/fixtures}/testLocalXhr.json | 0 addon-sdk/source/test/test-addon-installer.js | 1 + addon-sdk/source/test/test-buffer.js | 584 +++++++++++++++-- addon-sdk/source/test/test-content-loader.js | 3 +- addon-sdk/source/test/test-content-script.js | 2 +- .../source/test/test-content-symbiont.js | 34 +- addon-sdk/source/test/test-context-menu.js | 15 +- addon-sdk/source/test/test-loader.js | 57 +- addon-sdk/source/test/test-net-url.js | 2 +- addon-sdk/source/test/test-page-mod.js | 12 +- addon-sdk/source/test/test-page-worker.js | 7 +- addon-sdk/source/test/test-panel.js | 3 +- addon-sdk/source/test/test-promise.js | 15 + addon-sdk/source/test/test-self.js | 3 - addon-sdk/source/test/test-system-events.js | 30 +- addon-sdk/source/test/test-ui-button.js | 2 +- addon-sdk/source/test/test-ui-sidebar.js | 214 ++++++- addon-sdk/source/test/test-widget.js | 13 +- addon-sdk/source/test/test-window-utils.js | 27 +- addon-sdk/source/test/test-xhr.js | 3 +- 99 files changed, 2824 insertions(+), 554 deletions(-) delete mode 100644 addon-sdk/source/doc/module-source/sdk/ui.md create mode 100644 addon-sdk/source/doc/module-source/sdk/ui/sidebar.md create mode 100644 addon-sdk/source/doc/static-files/media/screenshots/sidebar-menu.png create mode 100644 addon-sdk/source/doc/static-files/media/screenshots/sidebar.png create mode 100644 addon-sdk/source/python-lib/cuddlefish/tests/bug-906359-files/fullName/package.json create mode 100644 addon-sdk/source/python-lib/cuddlefish/tests/bug-906359-files/none/package.json create mode 100644 addon-sdk/source/python-lib/cuddlefish/tests/bug-906359-files/title/package.json rename addon-sdk/source/{ => test/addons/addon-page}/data/index.html (100%) rename addon-sdk/source/test/{test-addon-page.js => addons/addon-page/main.js} (98%) create mode 100644 addon-sdk/source/test/addons/addon-page/package.json rename addon-sdk/source/test/{ => addons/places}/favicon-helpers.js (100%) create mode 100644 addon-sdk/source/test/addons/places/main.js create mode 100644 addon-sdk/source/test/addons/places/package.json rename addon-sdk/source/test/{ => addons/places}/places-helper.js (100%) rename addon-sdk/source/test/{ => addons/places/tests}/test-places-bookmarks.js (99%) rename addon-sdk/source/test/{ => addons/places/tests}/test-places-events.js (99%) rename addon-sdk/source/test/{ => addons/places/tests}/test-places-favicon.js (96%) rename addon-sdk/source/test/{ => addons/places/tests}/test-places-history.js (99%) rename addon-sdk/source/test/{ => addons/places/tests}/test-places-host.js (99%) rename addon-sdk/source/test/{ => addons/places/tests}/test-places-utils.js (98%) create mode 100644 addon-sdk/source/test/addons/self/data/data.md create mode 100644 addon-sdk/source/test/addons/self/main.js create mode 100644 addon-sdk/source/test/addons/self/package.json rename addon-sdk/source/{ => test/addons/symbiont}/data/test-trusted-document.html (100%) create mode 100644 addon-sdk/source/test/addons/symbiont/main.js create mode 100644 addon-sdk/source/test/addons/symbiont/package.json create mode 100644 addon-sdk/source/test/buffers/test-read-types.js create mode 100644 addon-sdk/source/test/buffers/test-write-types.js create mode 100644 addon-sdk/source/test/fixtures.js create mode 100644 addon-sdk/source/test/fixtures/index.html create mode 100644 addon-sdk/source/test/fixtures/loader/json/invalid.json create mode 100644 addon-sdk/source/test/fixtures/loader/json/manifest.json create mode 100644 addon-sdk/source/test/fixtures/loader/json/nodotjson.json.js create mode 100644 addon-sdk/source/test/fixtures/loader/json/test.json create mode 100644 addon-sdk/source/test/fixtures/loader/json/test.json.js rename addon-sdk/source/{data => test/fixtures}/mofo_logo.SVG (100%) rename addon-sdk/source/{data => test/fixtures}/moz_favicon.ico (100%) rename addon-sdk/source/{data => test/fixtures}/pagemod-css-include-file.css (100%) rename addon-sdk/source/{data => test/fixtures}/test-content-symbiont.js (100%) rename addon-sdk/source/{data => test/fixtures}/test-context-menu.js (100%) rename addon-sdk/source/{data => test/fixtures}/test-iframe-postmessage.html (100%) rename addon-sdk/source/{data => test/fixtures}/test-iframe.html (100%) rename addon-sdk/source/{data => test/fixtures}/test-iframe.js (100%) rename addon-sdk/source/{data => test/fixtures}/test-message-manager.js (100%) rename addon-sdk/source/{data => test/fixtures}/test-net-url.txt (100%) rename addon-sdk/source/{data => test/fixtures}/test-page-mod.html (100%) rename addon-sdk/source/{data => test/fixtures}/test-page-worker.html (100%) rename addon-sdk/source/{data => test/fixtures}/test-page-worker.js (100%) rename addon-sdk/source/{data => test/fixtures}/test-sidebar-addon-global.html (100%) create mode 100644 addon-sdk/source/test/fixtures/test-trusted-document.html rename addon-sdk/source/{data => test/fixtures}/test.html (100%) rename addon-sdk/source/{data => test/fixtures}/testLocalXhr.json (100%) diff --git a/addon-sdk/Makefile.in b/addon-sdk/Makefile.in index 477243041d2..c4b3ee11d30 100644 --- a/addon-sdk/Makefile.in +++ b/addon-sdk/Makefile.in @@ -13,7 +13,6 @@ include $(topsrcdir)/config/rules.mk TEST_FILES = \ source/app-extension \ source/bin \ - source/data \ source/python-lib \ source/test \ source/package.json \ diff --git a/addon-sdk/source/doc/module-source/sdk/places/favicon.md b/addon-sdk/source/doc/module-source/sdk/places/favicon.md index aeb7a4212c7..800c29ff924 100644 --- a/addon-sdk/source/doc/module-source/sdk/places/favicon.md +++ b/addon-sdk/source/doc/module-source/sdk/places/favicon.md @@ -35,7 +35,7 @@ such, will only return favicon URLs for visited sites. console.log(url); // http://mozorg.cdn.mozilla.net/media/img/favicon.ico }); -@param object {string, tab} +@param object {string|tab} A value that represents the URL of the page to get the favicon URL from. Can be a URL `String` or a [`Tab`](modules/sdk/tabs.html#Tab). diff --git a/addon-sdk/source/doc/module-source/sdk/tabs.md b/addon-sdk/source/doc/module-source/sdk/tabs.md index d60b4b9584a..8dec20a9d0c 100644 --- a/addon-sdk/source/doc/module-source/sdk/tabs.md +++ b/addon-sdk/source/doc/module-source/sdk/tabs.md @@ -126,6 +126,10 @@ content (see the }); }); +Note that `tab.attach` is tab-centric: if the user navigates to a new +page in the same tab, then the worker and content scripts will be +reattached to the new page. + ## Private Windows ## If your add-on has not opted into private browsing, then you won't see any @@ -346,7 +350,10 @@ Returns thumbnail data URI of the page currently loaded in this tab. @method - Create a page mod and attach it to the document in the tab. + Create a [Worker](modules/sdk/content/worker.html) and attach it to + every document loaded in the tab. Note that this is tab-centric: if + the user navigates to a new page in the same tab, then the worker and + content scripts will be reattached to the new page. **Example** @@ -360,20 +367,22 @@ Returns thumbnail data URI of the page currently loaded in this tab. }); @param options {object} - Options for the page mod, with the following keys: + Options for the worker, with the following keys: @prop [contentScriptFile] {string,array} The local file URLs of content scripts to load. Content scripts specified by this option are loaded *before* those specified by the `contentScript` option. Optional. @prop [contentScript] {string,array} - The texts of content scripts to load. Content scripts specified by this - option are loaded *after* those specified by the `contentScriptFile` option. + A string or an array of strings of code to be evaluated in the context. + Content scripts specified by this option are loaded *after* + those specified by the `contentScriptFile` option. Optional. @prop [onMessage] {function} - A function called when the page mod receives a message from content scripts. - Listeners are passed a single argument, the message posted from the - content script. Optional. + A function called when the content worker receives a message from + content scripts. Listeners are passed a single argument, the + message posted from the content script. + Optional. @returns {Worker} The [Worker](modules/sdk/content/worker.html#Worker) object can be used to diff --git a/addon-sdk/source/doc/module-source/sdk/ui.md b/addon-sdk/source/doc/module-source/sdk/ui.md deleted file mode 100644 index 7ecd5f0b6af..00000000000 --- a/addon-sdk/source/doc/module-source/sdk/ui.md +++ /dev/null @@ -1,214 +0,0 @@ - - - - -This module exports a two constructor functions `Button` which constructs a -new toolbar button, and `Sidebar` which constructs a sidebar (with a button). - -Sidebars are displayed on the left side of your browser. Its content is specified as -local HTML, so the appearance and behaviour of the sidebar -is limited only by what you can do using HTML, CSS and JavaScript. - -The screenshot below shows a sidebar whose content is built from tweets: - - - -Sidebars are useful for presenting temporary interfaces to users in a way that is -easier for users to ignore and dismiss than a modal dialog -and easier for users to keep around than a Panel, since sidebars are -displayed at the side of the browser until the user decides to close it. - -A sidebar's content is loaded anew as soon as it is opened, and unloads -when the user closes the sidebar. - -Your add-on can receive notifications when a sidebar is shown or hidden by -listening to its `show` and `hide` events. - -Opening a sidebar in a window will close an already opened sidebar in that window. - -## Sidebar Content ## - -The sidebar's content is specified as HTML, which is loaded from the URL -supplied in the `url` option to the sidebar's constructor. - -You can load remote HTML into the sidebar: - - var sidebar = require("sdk/ui").Sidebar({ - id: 'a-new-sidebar', - title: 'A New Sidebar', - icon: './icon.png', - url: './index.html' - }); - - sidebar.show(); - -This will load HTML that's been packaged with your add-on, and this is -most probably how you will create sidebars. To do this, save -the `index.html` HTML file in your add-on's `data` directory. - -## Sidebar Positioning ## - -By default the sidebars appears on the left side of the currently active browser window. - - -## Updating Sidebar Content ## - -You can update the sidebar's content simply by setting the sidebar's `url` -property. Note this will change the sidebar's url for all windows. - -## Scripting Sidebar Content ## - -You can't directly access your sidebar's content from your main add-on code. -To access the sidebar's content, you need to add a ` + + diff --git a/addon-sdk/source/data/test.html b/addon-sdk/source/test/fixtures/test.html similarity index 100% rename from addon-sdk/source/data/test.html rename to addon-sdk/source/test/fixtures/test.html diff --git a/addon-sdk/source/data/testLocalXhr.json b/addon-sdk/source/test/fixtures/testLocalXhr.json similarity index 100% rename from addon-sdk/source/data/testLocalXhr.json rename to addon-sdk/source/test/fixtures/testLocalXhr.json diff --git a/addon-sdk/source/test/test-addon-installer.js b/addon-sdk/source/test/test-addon-installer.js index 2af4c29b93b..0c2061badd4 100644 --- a/addon-sdk/source/test/test-addon-installer.js +++ b/addon-sdk/source/test/test-addon-installer.js @@ -10,6 +10,7 @@ const observers = require("sdk/deprecated/observer-service"); const { setTimeout } = require("sdk/timers"); const tmp = require("sdk/test/tmp-file"); const system = require("sdk/system"); +const fixtures = require("./fixtures"); const testFolderURL = module.uri.split('test-addon-installer.js')[0]; const ADDON_URL = testFolderURL + "fixtures/addon-install-unit-test@mozilla.com.xpi"; diff --git a/addon-sdk/source/test/test-buffer.js b/addon-sdk/source/test/test-buffer.js index 37d530bf7e4..1e3379e00cb 100644 --- a/addon-sdk/source/test/test-buffer.js +++ b/addon-sdk/source/test/test-buffer.js @@ -2,31 +2,486 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * Many of these tests taken from Joyent's Node + * https://github.com/joyent/node/blob/master/test/simple/test-buffer.js + */ + +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + const { Buffer, TextEncoder, TextDecoder } = require('sdk/io/buffer'); +const { safeMerge } = require('sdk/util/object'); + +const ENCODINGS = ['utf-8', 'utf-16le', 'utf-16be']; + +exports.testBufferMain = function (assert) { + let b = Buffer('abcdef'); + + // try to create 0-length buffers + new Buffer(''); + new Buffer(0); + // test encodings supported by node; + // this is different than what node supports, details + // in buffer.js + ENCODINGS.forEach(enc => { + new Buffer('', enc); + assert.pass('Creating a buffer with ' + enc + ' does not throw'); + }); + + ENCODINGS.forEach(function(encoding) { + // Does not work with utf8 + if (encoding === 'utf-8') return; + var b = new Buffer(10); + b.write('あいうえお', encoding); + assert.equal(b.toString(encoding), 'あいうえお', + 'encode and decodes buffer with ' + encoding); + }); + + // invalid encoding for Buffer.toString + assert.throws(() => { + b.toString('invalid'); + }, TypeError, 'invalid encoding for Buffer.toString'); + + // try to toString() a 0-length slice of a buffer, both within and without the + // valid buffer range + assert.equal(new Buffer('abc').toString('utf8', 0, 0), '', + 'toString 0-length buffer, valid range'); + assert.equal(new Buffer('abc').toString('utf8', -100, -100), '', + 'toString 0-length buffer, invalid range'); + assert.equal(new Buffer('abc').toString('utf8', 100, 100), '', + 'toString 0-length buffer, invalid range'); + + // try toString() with a object as a encoding + assert.equal(new Buffer('abc').toString({toString: function() { + return 'utf8'; + }}), 'abc', 'toString with object as an encoding'); + + // test for buffer overrun + var buf = new Buffer([0, 0, 0, 0, 0]); // length: 5 + var sub = buf.slice(0, 4); // length: 4 + var written = sub.write('12345', 'utf8'); + assert.equal(written, 4, 'correct bytes written in slice'); + assert.equal(buf[4], 0, 'correct origin buffer value'); + + // Check for fractional length args, junk length args, etc. + // https://github.com/joyent/node/issues/1758 + Buffer(3.3).toString(); // throws bad argument error in commit 43cb4ec + assert.equal(Buffer(-1).length, 0); + assert.equal(Buffer(NaN).length, 0); + assert.equal(Buffer(3.3).length, 3); + assert.equal(Buffer({length: 3.3}).length, 3); + assert.equal(Buffer({length: 'BAM'}).length, 0); + + // Make sure that strings are not coerced to numbers. + assert.equal(Buffer('99').length, 2); + assert.equal(Buffer('13.37').length, 5); +}; exports.testIsEncoding = function (assert) { - Object.keys(ENCODINGS).forEach(encoding => { + ENCODINGS.map(encoding => { assert.ok(Buffer.isEncoding(encoding), 'Buffer.isEncoding ' + encoding + ' truthy'); }); - ['not-encoding', undefined, null, 100, {}].forEach(encoding => { + ['not-encoding', undefined, null, 100, {}].map(encoding => { assert.ok(!Buffer.isEncoding(encoding), 'Buffer.isEncoding ' + encoding + ' falsy'); }); }; +exports.testBufferCopy = function (assert) { + // counter to ensure unique value is always copied + var cntr = 0; + var b = Buffer(1024); // safe constructor + + assert.strictEqual(1024, b.length); + b[0] = -1; + assert.strictEqual(b[0], 255); + + var shimArray = []; + for (var i = 0; i < 1024; i++) { + b[i] = i % 256; + shimArray[i] = i % 256; + } + + compareBuffers(assert, b, shimArray, 'array notation'); + + var c = new Buffer(512); + assert.strictEqual(512, c.length); + // copy 512 bytes, from 0 to 512. + b.fill(++cntr); + c.fill(++cntr); + var copied = b.copy(c, 0, 0, 512); + assert.strictEqual(512, copied, + 'copied ' + copied + ' bytes from b into c'); + + compareBuffers(assert, b, c, 'copied to other buffer'); + + // copy c into b, without specifying sourceEnd + b.fill(++cntr); + c.fill(++cntr); + var copied = c.copy(b, 0, 0); + assert.strictEqual(c.length, copied, + 'copied ' + copied + ' bytes from c into b w/o sourceEnd'); + compareBuffers(assert, b, c, + 'copied to other buffer without specifying sourceEnd'); + + // copy c into b, without specifying sourceStart + b.fill(++cntr); + c.fill(++cntr); + var copied = c.copy(b, 0); + assert.strictEqual(c.length, copied, + 'copied ' + copied + ' bytes from c into b w/o sourceStart'); + compareBuffers(assert, b, c, + 'copied to other buffer without specifying sourceStart'); + + // copy longer buffer b to shorter c without targetStart + b.fill(++cntr); + c.fill(++cntr); + + var copied = b.copy(c); + assert.strictEqual(c.length, copied, + 'copied ' + copied + ' bytes from b into c w/o targetStart'); + compareBuffers(assert, b, c, + 'copy long buffer to shorter buffer without targetStart'); + + // copy starting near end of b to c + b.fill(++cntr); + c.fill(++cntr); + var copied = b.copy(c, 0, b.length - Math.floor(c.length / 2)); + assert.strictEqual(Math.floor(c.length / 2), copied, + 'copied ' + copied + ' bytes from end of b into beg. of c'); + + let successStatus = true; + for (var i = 0; i < Math.floor(c.length / 2); i++) { + if (b[b.length - Math.floor(c.length / 2) + i] !== c[i]) + successStatus = false; + } + + for (var i = Math.floor(c.length /2) + 1; i < c.length; i++) { + if (c[c.length-1] !== c[i]) + successStatus = false; + } + assert.ok(successStatus, + 'Copied bytes from end of large buffer into beginning of small buffer'); + + // try to copy 513 bytes, and check we don't overrun c + b.fill(++cntr); + c.fill(++cntr); + var copied = b.copy(c, 0, 0, 513); + assert.strictEqual(c.length, copied, + 'copied ' + copied + ' bytes from b trying to overrun c'); + compareBuffers(assert, b, c, + 'copying to buffer that would overflow'); + + // copy 768 bytes from b into b + b.fill(++cntr); + b.fill(++cntr, 256); + var copied = b.copy(b, 0, 256, 1024); + assert.strictEqual(768, copied, + 'copied ' + copied + ' bytes from b into b'); + + compareBuffers(assert, b, shimArray.map(()=>cntr), + 'copy partial buffer to itself'); + + // copy string longer than buffer length (failure will segfault) + var bb = new Buffer(10); + bb.fill('hello crazy world'); + + // copy throws at negative sourceStart + assert.throws(function() { + Buffer(5).copy(Buffer(5), 0, -1); + }, RangeError, 'buffer copy throws at negative sourceStart'); + + // check sourceEnd resets to targetEnd if former is greater than the latter + b.fill(++cntr); + c.fill(++cntr); + var copied = b.copy(c, 0, 0, 1025); + assert.strictEqual(copied, c.length, + 'copied ' + copied + ' bytes from b into c'); + compareBuffers(assert, b, c, 'copying should reset sourceEnd if targetEnd if sourceEnd > targetEnd'); + + // throw with negative sourceEnd + assert.throws(function() { + b.copy(c, 0, 0, -1); + }, RangeError, 'buffer copy throws at negative sourceEnd'); + + // when sourceStart is greater than sourceEnd, zero copied + assert.equal(b.copy(c, 0, 100, 10), 0); + + // when targetStart > targetLength, zero copied + assert.equal(b.copy(c, 512, 0, 10), 0); + + // try to copy 0 bytes worth of data into an empty buffer + b.copy(new Buffer(0), 0, 0, 0); + + // try to copy 0 bytes past the end of the target buffer + b.copy(new Buffer(0), 1, 1, 1); + b.copy(new Buffer(1), 1, 1, 1); + + // try to copy 0 bytes from past the end of the source buffer + b.copy(new Buffer(1), 0, 2048, 2048); +}; + +exports.testBufferWrite = function (assert) { + let b = Buffer(1024); + b.fill(0); + + assert.throws(() => { + b.write('test string', 0, 5, 'invalid'); + }, TypeError, 'invalid encoding with buffer write throws'); + // try to write a 0-length string beyond the end of b + assert.throws(function() { + b.write('', 2048); + }, RangeError, 'writing a 0-length string beyond buffer throws'); + // throw when writing to negative offset + assert.throws(function() { + b.write('a', -1); + }, RangeError, 'writing negative offset on buffer throws'); + + // throw when writing past bounds from the pool + assert.throws(function() { + b.write('a', 2048); + }, RangeError, 'writing past buffer bounds from pool throws'); + + // testing for smart defaults and ability to pass string values as offset + + // previous write API was the following: + // write(string, encoding, offset, length) + // this is planned on being removed in node v0.13, + // we will not support it + var writeTest = new Buffer('abcdes'); + writeTest.write('n', 'utf8'); +// writeTest.write('o', 'utf8', '1'); + writeTest.write('d', '2', 'utf8'); + writeTest.write('e', 3, 'utf8'); +// writeTest.write('j', 'utf8', 4); + assert.equal(writeTest.toString(), 'nbdees', + 'buffer write API alternative syntax works'); +}; + +exports.testBufferWriteEncoding = function (assert) { + + // Node #1210 Test UTF-8 string includes null character + var buf = new Buffer('\0'); + assert.equal(buf.length, 1); + buf = new Buffer('\0\0'); + assert.equal(buf.length, 2); + + buf = new Buffer(2); + var written = buf.write(''); // 0byte + assert.equal(written, 0); + written = buf.write('\0'); // 1byte (v8 adds null terminator) + assert.equal(written, 1); + written = buf.write('a\0'); // 1byte * 2 + assert.equal(written, 2); + // TODO, these tests write 0, possibly due to character encoding +/* + written = buf.write('あ'); // 3bytes + assert.equal(written, 0); + written = buf.write('\0あ'); // 1byte + 3bytes + assert.equal(written, 1); +*/ + written = buf.write('\0\0あ'); // 1byte * 2 + 3bytes + buf = new Buffer(10); + written = buf.write('あいう'); // 3bytes * 3 (v8 adds null terminator) + assert.equal(written, 9); + written = buf.write('あいう\0'); // 3bytes * 3 + 1byte + assert.equal(written, 10); +}; + +exports.testBufferWriteWithMaxLength = function (assert) { + // Node #243 Test write() with maxLength + var buf = new Buffer(4); + buf.fill(0xFF); + var written = buf.write('abcd', 1, 2, 'utf8'); + assert.equal(written, 2); + assert.equal(buf[0], 0xFF); + assert.equal(buf[1], 0x61); + assert.equal(buf[2], 0x62); + assert.equal(buf[3], 0xFF); + + buf.fill(0xFF); + written = buf.write('abcd', 1, 4); + assert.equal(written, 3); + assert.equal(buf[0], 0xFF); + assert.equal(buf[1], 0x61); + assert.equal(buf[2], 0x62); + assert.equal(buf[3], 0x63); + + buf.fill(0xFF); + // Ignore legacy API + /* + written = buf.write('abcd', 'utf8', 1, 2); // legacy style + console.log(buf); + assert.equal(written, 2); + assert.equal(buf[0], 0xFF); + assert.equal(buf[1], 0x61); + assert.equal(buf[2], 0x62); + assert.equal(buf[3], 0xFF); + */ +}; + +exports.testBufferSlice = function (assert) { + var asciiString = 'hello world'; + var offset = 100; + var b = Buffer(1024); + b.fill(0); + + for (var i = 0; i < asciiString.length; i++) { + b[i] = asciiString.charCodeAt(i); + } + var asciiSlice = b.toString('utf8', 0, asciiString.length); + assert.equal(asciiString, asciiSlice); + + var written = b.write(asciiString, offset, 'utf8'); + assert.equal(asciiString.length, written); + asciiSlice = b.toString('utf8', offset, offset + asciiString.length); + assert.equal(asciiString, asciiSlice); + + var sliceA = b.slice(offset, offset + asciiString.length); + var sliceB = b.slice(offset, offset + asciiString.length); + compareBuffers(assert, sliceA, sliceB, + 'slicing is idempotent'); + + let sliceTest = true; + for (var j = 0; j < 100; j++) { + var slice = b.slice(100, 150); + if (50 !== slice.length) + sliceTest = false; + for (var i = 0; i < 50; i++) { + if (b[100 + i] !== slice[i]) + sliceTest = false; + } + } + assert.ok(sliceTest, 'massive slice runs do not affect buffer'); + + // Single argument slice + let testBuf = new Buffer('abcde'); + assert.equal('bcde', testBuf.slice(1).toString(), 'single argument slice'); + + // slice(0,0).length === 0 + assert.equal(0, Buffer('hello').slice(0, 0).length, 'slice(0,0) === 0'); + + var buf = new Buffer('0123456789'); + assert.equal(buf.slice(-10, 10), '0123456789', 'buffer slice range correct'); + assert.equal(buf.slice(-20, 10), '0123456789', 'buffer slice range correct'); + assert.equal(buf.slice(-20, -10), '', 'buffer slice range correct'); + assert.equal(buf.slice(0, -1), '012345678', 'buffer slice range correct'); + assert.equal(buf.slice(2, -2), '234567', 'buffer slice range correct'); + assert.equal(buf.slice(0, 65536), '0123456789', 'buffer slice range correct'); + assert.equal(buf.slice(65536, 0), '', 'buffer slice range correct'); + + let sliceTest = true; + for (var i = 0, s = buf.toString(); i < buf.length; ++i) { + if (buf.slice(-i) != s.slice(-i)) sliceTest = false; + if (buf.slice(0, -i) != s.slice(0, -i)) sliceTest = false; + } + assert.ok(sliceTest, 'buffer.slice should be consistent'); + + // Make sure modifying a sliced buffer, affects original and vice versa + b.fill(0); + let sliced = b.slice(0, 10); + let babyslice = sliced.slice(0, 5); + + for (let i = 0; i < sliced.length; i++) + sliced[i] = 'jetpack'.charAt(i); + + compareBuffers(assert, b, sliced, + 'modifying sliced buffer affects original'); + + compareBuffers(assert, b, babyslice, + 'modifying sliced buffer affects child-sliced buffer'); + + for (let i = 0; i < sliced.length; i++) + b[i] = 'odinmonkey'.charAt(i); + + compareBuffers(assert, b, sliced, + 'modifying original buffer affects sliced'); + + compareBuffers(assert, b, babyslice, + 'modifying original buffer affects grandchild sliced buffer'); +}; + +exports.testSlicingParents = function (assert) { + let root = Buffer(5); + let child = root.slice(0, 4); + let grandchild = child.slice(0, 3); + + assert.equal(root.parent, undefined, 'a new buffer should not have a parent'); + + // make sure a zero length slice doesn't set the .parent attribute + assert.equal(root.slice(0,0).parent, undefined, + '0-length slice should not have a parent'); + + assert.equal(child.parent, root, + 'a valid slice\'s parent should be the original buffer (child)'); + + assert.equal(grandchild.parent, root, + 'a valid slice\'s parent should be the original buffer (grandchild)'); +}; + exports.testIsBuffer = function (assert) { let buffer = new Buffer('content', 'utf8'); assert.ok(Buffer.isBuffer(buffer), 'isBuffer truthy on buffers'); assert.ok(!Buffer.isBuffer({}), 'isBuffer falsy on objects'); assert.ok(!Buffer.isBuffer(new Uint8Array()), 'isBuffer falsy on Uint8Array'); + assert.ok(Buffer.isBuffer(buffer.slice(0)), 'Buffer#slice should be a new buffer'); +}; + +exports.testBufferConcat = function (assert) { + let zero = []; + let one = [ new Buffer('asdf') ]; + let long = []; + for (let i = 0; i < 10; i++) long.push(new Buffer('asdf')); + + let flatZero = Buffer.concat(zero); + let flatOne = Buffer.concat(one); + let flatLong = Buffer.concat(long); + let flatLongLen = Buffer.concat(long, 40); + + assert.equal(flatZero.length, 0); + assert.equal(flatOne.toString(), 'asdf'); + assert.equal(flatOne, one[0]); + assert.ok(flatLong.toString(), (new Array(10+1).join('asdf'))); + assert.equal(flatLongLen.toString(), (new Array(10+1).join('asdf'))); }; exports.testBufferByteLength = function (assert) { let str = '\u00bd + \u00bc = \u00be'; assert.equal(Buffer.byteLength(str), 12, 'correct byteLength of string'); + + assert.equal(14, Buffer.byteLength('Il était tué')); + assert.equal(14, Buffer.byteLength('Il était tué', 'utf8')); + // We do not currently support these encodings + /* + ['ucs2', 'ucs-2', 'utf16le', 'utf-16le'].forEach(function(encoding) { + assert.equal(24, Buffer.byteLength('Il était tué', encoding)); + }); + assert.equal(12, Buffer.byteLength('Il était tué', 'ascii')); + assert.equal(12, Buffer.byteLength('Il était tué', 'binary')); + */ }; exports.testTextEncoderDecoder = function (assert) { @@ -34,57 +489,78 @@ exports.testTextEncoderDecoder = function (assert) { assert.ok(TextDecoder, 'TextDecoder exists'); }; -// List of supported encodings taken from: -// http://mxr.mozilla.org/mozilla-central/source/dom/encoding/labelsencodings.properties -const ENCODINGS = { "unicode-1-1-utf-8": 1, "utf-8": 1, "utf8": 1, - "866": 1, "cp866": 1, "csibm866": 1, "ibm866": 1, "csisolatin2": 1, - "iso-8859-2": 1, "iso-ir-101": 1, "iso8859-2": 1, "iso88592": 1, - "iso_8859-2": 1, "iso_8859-2:1987": 1, "l2": 1, "latin2": 1, "csisolatin3": 1, - "iso-8859-3": 1, "iso-ir-109": 1, "iso8859-3": 1, "iso88593": 1, - "iso_8859-3": 1, "iso_8859-3:1988": 1, "l3": 1, "latin3": 1, "csisolatin4": 1, - "iso-8859-4": 1, "iso-ir-110": 1, "iso8859-4": 1, "iso88594": 1, - "iso_8859-4": 1, "iso_8859-4:1988": 1, "l4": 1, "latin4": 1, - "csisolatincyrillic": 1, "cyrillic": 1, "iso-8859-5": 1, "iso-ir-144": 1, - "iso8859-5": 1, "iso88595": 1, "iso_8859-5": 1, "iso_8859-5:1988": 1, - "arabic": 1, "asmo-708": 1, "csiso88596e": 1, "csiso88596i": 1, - "csisolatinarabic": 1, "ecma-114": 1, "iso-8859-6": 1, "iso-8859-6-e": 1, - "iso-8859-6-i": 1, "iso-ir-127": 1, "iso8859-6": 1, "iso88596": 1, - "iso_8859-6": 1, "iso_8859-6:1987": 1, "csisolatingreek": 1, "ecma-118": 1, - "elot_928": 1, "greek": 1, "greek8": 1, "iso-8859-7": 1, "iso-ir-126": 1, - "iso8859-7": 1, "iso88597": 1, "iso_8859-7": 1, "iso_8859-7:1987": 1, - "sun_eu_greek": 1, "csiso88598e": 1, "csisolatinhebrew": 1, "hebrew": 1, - "iso-8859-8": 1, "iso-8859-8-e": 1, "iso-ir-138": 1, "iso8859-8": 1, - "iso88598": 1, "iso_8859-8": 1, "iso_8859-8:1988": 1, "visual": 1, - "csiso88598i": 1, "iso-8859-8-i": 1, "logical": 1, "csisolatin6": 1, - "iso-8859-10": 1, "iso-ir-157": 1, "iso8859-10": 1, "iso885910": 1, - "l6": 1, "latin6": 1, "iso-8859-13": 1, "iso8859-13": 1, "iso885913": 1, - "iso-8859-14": 1, "iso8859-14": 1, "iso885914": 1, "csisolatin9": 1, - "iso-8859-15": 1, "iso8859-15": 1, "iso885915": 1, "iso_8859-15": 1, - "l9": 1, "iso-8859-16": 1, "cskoi8r": 1, "koi": 1, "koi8": 1, "koi8-r": 1, - "koi8_r": 1, "koi8-u": 1, "csmacintosh": 1, "mac": 1, "macintosh": 1, - "x-mac-roman": 1, "dos-874": 1, "iso-8859-11": 1, "iso8859-11": 1, - "iso885911": 1, "tis-620": 1, "windows-874": 1, "cp1250": 1, - "windows-1250": 1, "x-cp1250": 1, "cp1251": 1, "windows-1251": 1, - "x-cp1251": 1, "ansi_x3.4-1968": 1, "ascii": 1, "cp1252": 1, "cp819": 1, - "csisolatin1": 1, "ibm819": 1, "iso-8859-1": 1, "iso-ir-100": 1, - "iso8859-1": 1, "iso88591": 1, "iso_8859-1": 1, "iso_8859-1:1987": 1, - "l1": 1, "latin1": 1, "us-ascii": 1, "windows-1252": 1, "x-cp1252": 1, - "cp1253": 1, "windows-1253": 1, "x-cp1253": 1, "cp1254": 1, "csisolatin5": 1, - "iso-8859-9": 1, "iso-ir-148": 1, "iso8859-9": 1, "iso88599": 1, - "iso_8859-9": 1, "iso_8859-9:1989": 1, "l5": 1, "latin5": 1, - "windows-1254": 1, "x-cp1254": 1, "cp1255": 1, "windows-1255": 1, - "x-cp1255": 1, "cp1256": 1, "windows-1256": 1, "x-cp1256": 1, "cp1257": 1, - "windows-1257": 1, "x-cp1257": 1, "cp1258": 1, "windows-1258": 1, - "x-cp1258": 1, "x-mac-cyrillic": 1, "x-mac-ukrainian": 1, "chinese": 1, - "csgb2312": 1, "csiso58gb231280": 1, "gb2312": 1, "gb_2312": 1, - "gb_2312-80": 1, "gbk": 1, "iso-ir-58": 1, "x-gbk": 1, "gb18030": 1, - "hz-gb-2312": 1, "big5": 1, "big5-hkscs": 1, "cn-big5": 1, "csbig5": 1, - "x-x-big5": 1, "cseucpkdfmtjapanese": 1, "euc-jp": 1, "x-euc-jp": 1, - "csiso2022jp": 1, "iso-2022-jp": 1, "csshiftjis": 1, "ms_kanji": 1, - "shift-jis": 1, "shift_jis": 1, "sjis": 1, "windows-31j": 1, "x-sjis": 1, - "cseuckr": 1, "csksc56011987": 1, "euc-kr": 1, "iso-ir-149": 1, "korean": 1, - "ks_c_5601-1987": 1, "ks_c_5601-1989": 1, "ksc5601": 1, "ksc_5601": 1, - "windows-949": 1, "csiso2022kr": 1, "iso-2022-kr": 1, "utf-16": 1, - "utf-16le": 1, "utf-16be": 1, "x-user-defined": 1 }; +exports.testOverflowedBuffers = function (assert) { + assert.throws(function() { + new Buffer(0xFFFFFFFF); + }, RangeError, 'correctly throws buffer overflow'); + assert.throws(function() { + new Buffer(0xFFFFFFFFF); + }, RangeError, 'correctly throws buffer overflow'); + + assert.throws(function() { + var buf = new Buffer(8); + buf.readFloatLE(0xffffffff); + }, RangeError, 'correctly throws buffer overflow with readFloatLE'); + + assert.throws(function() { + var buf = new Buffer(8); + buf.writeFloatLE(0.0, 0xffffffff); + }, RangeError, 'correctly throws buffer overflow with writeFloatLE'); + + //ensure negative values can't get past offset + assert.throws(function() { + var buf = new Buffer(8); + buf.readFloatLE(-1); + }, RangeError, 'correctly throws with readFloatLE negative values'); + + assert.throws(function() { + var buf = new Buffer(8); + buf.writeFloatLE(0.0, -1); + }, RangeError, 'correctly throws with writeFloatLE with negative values'); + + assert.throws(function() { + var buf = new Buffer(8); + buf.readFloatLE(-1); + }, RangeError, 'correctly throws with readFloatLE with negative values'); +}; + +exports.testReadWriteDataTypeErrors = function (assert) { + var buf = new Buffer(0); + assert.throws(function() { buf.readUInt8(0); }, RangeError, + 'readUInt8(0) throws'); + assert.throws(function() { buf.readInt8(0); }, RangeError, + 'readInt8(0) throws'); + + [16, 32].forEach(function(bits) { + var buf = new Buffer(bits / 8 - 1); + assert.throws(function() { buf['readUInt' + bits + 'BE'](0); }, + RangeError, + 'readUInt' + bits + 'BE'); + + assert.throws(function() { buf['readUInt' + bits + 'LE'](0); }, + RangeError, + 'readUInt' + bits + 'LE'); + + assert.throws(function() { buf['readInt' + bits + 'BE'](0); }, + RangeError, + 'readInt' + bits + 'BE()'); + + assert.throws(function() { buf['readInt' + bits + 'LE'](0); }, + RangeError, + 'readInt' + bits + 'LE()'); + }); +}; + +safeMerge(exports, require('./buffers/test-write-types')); +safeMerge(exports, require('./buffers/test-read-types')); + +function compareBuffers (assert, buf1, buf2, message) { + let status = true; + for (let i = 0; i < Math.min(buf1.length, buf2.length); i++) { + if (buf1[i] !== buf2[i]) + status = false; + } + assert.ok(status, 'buffer successfully copied: ' + message); +} require('sdk/test').run(exports); diff --git a/addon-sdk/source/test/test-content-loader.js b/addon-sdk/source/test/test-content-loader.js index 664631aae95..5690369fee2 100644 --- a/addon-sdk/source/test/test-content-loader.js +++ b/addon-sdk/source/test/test-content-loader.js @@ -5,6 +5,7 @@ "use strict"; const { Loader } = require('sdk/content/loader'); const self = require("sdk/self"); +const fixtures = require("./fixtures"); exports['test:contentURL'] = function(assert) { let loader = Loader(), @@ -172,7 +173,7 @@ exports['test:contentScript'] = function(assert) { }; exports['test:contentScriptFile'] = function(assert) { - let loader = Loader(), value, uri = self.data.url("test-content-loader.js"); + let loader = Loader(), value, uri = fixtures.url("test-content-loader.js"); assert.equal( null, loader.contentScriptFile, diff --git a/addon-sdk/source/test/test-content-script.js b/addon-sdk/source/test/test-content-script.js index 50a734478ad..ec47e343804 100644 --- a/addon-sdk/source/test/test-content-script.js +++ b/addon-sdk/source/test/test-content-script.js @@ -7,7 +7,7 @@ const { create: makeFrame } = require("sdk/frame/utils"); const { window } = require("sdk/addon/window"); const { Loader } = require('sdk/test/loader'); const { URL } = require("sdk/url"); -const testURI = require("sdk/self").data.url("test.html"); +const testURI = require("./fixtures").url("test.html"); const testHost = URL(testURI).scheme + '://' + URL(testURI).host; /* diff --git a/addon-sdk/source/test/test-content-symbiont.js b/addon-sdk/source/test/test-content-symbiont.js index 93601919495..9128773200b 100644 --- a/addon-sdk/source/test/test-content-symbiont.js +++ b/addon-sdk/source/test/test-content-symbiont.js @@ -6,6 +6,7 @@ const { Cc, Ci } = require('chrome'); const { Symbiont } = require('sdk/content/symbiont'); const self = require('sdk/self'); +const fixtures = require("./fixtures"); const { close } = require('sdk/window/helpers'); const app = require("sdk/system/xul-app"); @@ -27,7 +28,7 @@ function makeWindow() { exports['test:constructing symbiont && validating API'] = function(assert) { let contentScript = ["1;", "2;"]; - let contentScriptFile = self.data.url("test-content-symbiont.js"); + let contentScriptFile = fixtures.url("test-content-symbiont.js"); // We can avoid passing a `frame` argument. Symbiont will create one // by using HiddenFrame module @@ -75,6 +76,8 @@ exports["test:communication with worker global scope"] = function(assert, done) let window = makeWindow(); let contentSymbiont; + console.log(window) + function onMessage1(message) { assert.equal(message, 1, "Program gets message via onMessage."); contentSymbiont.removeListener('message', onMessage1); @@ -154,33 +157,4 @@ exports["test:document element present on 'start'"] = function(assert, done) { }); }; -exports["test:direct communication with trusted document"] = function(assert, done) { - let worker = Symbiont({ - contentURL: require("sdk/self").data.url("test-trusted-document.html") - }); - - worker.port.on('document-to-addon', function (arg) { - assert.equal(arg, "ok", "Received an event from the document"); - worker.destroy(); - done(); - }); - worker.port.emit('addon-to-document', 'ok'); -}; - -exports["test:`addon` is not available when a content script is set"] = function(assert, done) { - let worker = Symbiont({ - contentURL: require("sdk/self").data.url("test-trusted-document.html"), - contentScript: "new " + function ContentScriptScope() { - self.port.emit("cs-to-addon", "addon" in unsafeWindow); - } - }); - - worker.port.on('cs-to-addon', function (hasAddon) { - assert.equal(hasAddon, false, - "`addon` is not available"); - worker.destroy(); - done(); - }); -}; - require("test").run(exports); diff --git a/addon-sdk/source/test/test-context-menu.js b/addon-sdk/source/test/test-context-menu.js index 8fd9aad97b1..80b6df4f0ff 100644 --- a/addon-sdk/source/test/test-context-menu.js +++ b/addon-sdk/source/test/test-context-menu.js @@ -21,6 +21,7 @@ const OVERFLOW_MENU_CLASS = "addon-content-menu-overflow-menu"; const OVERFLOW_POPUP_CLASS = "addon-content-menu-overflow-popup"; const TEST_DOC_URL = module.uri.replace(/\.js$/, ".html"); +const data = require("./fixtures"); // Tests that when present the separator is placed before the separator from // the old context-menu module @@ -894,7 +895,7 @@ exports.testContentScriptFile = function (assert, done) { // But accept files from data folder let item = new loader.cm.Item({ label: "item", - contentScriptFile: require("sdk/self").data.url("test-context-menu.js") + contentScriptFile: data.url("test-context-menu.js") }); test.showMenu(null, function (popup) { @@ -2669,7 +2670,7 @@ exports.testItemImage = function (assert, done) { let test = new TestHelper(assert, done); let loader = test.newLoader(); - let imageURL = require("sdk/self").data.url("moz_favicon.ico"); + let imageURL = data.url("moz_favicon.ico"); let item = new loader.cm.Item({ label: "item", image: imageURL }); let menu = new loader.cm.Menu({ label: "menu", image: imageURL, items: [ loader.cm.Item({ label: "subitem" }) @@ -2680,7 +2681,7 @@ exports.testItemImage = function (assert, done) { test.showMenu(null, function (popup) { test.checkMenu([item, menu], [], []); - let imageURL2 = require("sdk/self").data.url("dummy.ico"); + let imageURL2 = data.url("dummy.ico"); item.image = imageURL2; menu.image = imageURL2; assert.equal(item.image, imageURL2, "Should have set the image correctly"); @@ -2701,7 +2702,7 @@ exports.testItemImage = function (assert, done) { exports.testItemImageValidURL = function (assert, done) { let test = new TestHelper(assert, done); let loader = test.newLoader(); - + assert.throws(function(){ new loader.cm.Item({ label: "item 1", @@ -2725,8 +2726,8 @@ exports.testItemImageValidURL = function (assert, done) { }) }, /Image URL validation failed/ ); - - let imageURL = require("sdk/self").data.url("moz_favicon.ico"); + + let imageURL = data.url("moz_favicon.ico"); let item4 = new loader.cm.Item({ label: "item 4", image: imageURL }); let item5 = new loader.cm.Item({ label: "item 5", image: null }); let item6 = new loader.cm.Item({ label: "item 6", image: undefined }); @@ -3228,7 +3229,7 @@ TestHelper.prototype = { }, // Asserts that the context menu looks OK given the arguments. presentItems - // are items that have been added to the menu. absentItems are items that + // are items that have been added to the menu. absentItems are items that // shouldn't match the current context. removedItems are items that have been // removed from the menu. checkMenu: function (presentItems, absentItems, removedItems) { diff --git a/addon-sdk/source/test/test-loader.js b/addon-sdk/source/test/test-loader.js index 589a0dc023b..c2632d30599 100644 --- a/addon-sdk/source/test/test-loader.js +++ b/addon-sdk/source/test/test-loader.js @@ -36,7 +36,7 @@ exports['test syntax errors'] = function(assert) { assert.equal(error.name, "SyntaxError", "throws syntax error"); assert.equal(error.fileName.split("/").pop(), "error.js", "Error contains filename"); - assert.equal(error.lineNumber, 11, "error is on line 11") + assert.equal(error.lineNumber, 11, "error is on line 11"); let stack = parseStack(error.stack); assert.equal(stack.pop().fileName, uri + "error.js", @@ -147,7 +147,41 @@ exports['test early errors in module'] = function(assert) { } finally { unload(loader); } -} +}; + +exports['test require json'] = function (assert) { + let data = require('./fixtures/loader/json/manifest.json'); + assert.equal(data.name, 'Jetpack Loader Test', 'loads json with strings'); + assert.equal(data.version, '1.0.1', 'loads json with strings'); + assert.equal(data.dependencies.async, '*', 'loads json with objects'); + assert.equal(data.dependencies.underscore, '*', 'loads json with objects'); + assert.equal(data.contributors.length, 4, 'loads json with arrays'); + assert.ok(Array.isArray(data.contributors), 'loads json with arrays'); + data.version = '2.0.0'; + let newdata = require('./fixtures/loader/json/manifest.json'); + assert.equal(newdata.version, '2.0.0', + 'JSON objects returned should be cached and the same instance'); + + try { + require('./fixtures/loader/json/invalid.json'); + assert.fail('Error not thrown when loading invalid json'); + } catch (err) { + assert.ok(err, 'error thrown when loading invalid json'); + assert.ok(/JSON\.parse/.test(err.message), + 'should thrown an error from JSON.parse, not attempt to load .json.js'); + } + + // Try again to ensure an empty module isn't loaded from cache + try { + require('./fixtures/loader/json/invalid.json'); + assert.fail('Error not thrown when loading invalid json a second time'); + } catch (err) { + assert.ok(err, + 'error thrown when loading invalid json a second time'); + assert.ok(/JSON\.parse/.test(err.message), + 'should thrown an error from JSON.parse a second time, not attempt to load .json.js'); + } +}; exports['test setting metadata for newly created sandboxes'] = function(assert) { let addonID = 'random-addon-id'; @@ -165,6 +199,23 @@ exports['test setting metadata for newly created sandboxes'] = function(assert) } let program = main(loader, 'main'); -} +}; + +exports['test require .json, .json.js'] = function (assert) { + let testjson = require('./fixtures/loader/json/test.json'); + assert.equal(testjson.filename, 'test.json', + 'require("./x.json") should load x.json, not x.json.js'); + + let nodotjson = require('./fixtures/loader/json/nodotjson.json'); + assert.equal(nodotjson.filename, 'nodotjson.json.js', + 'require("./x.json") should load x.json.js when x.json does not exist'); + nodotjson.data.prop = 'hydralisk'; + + // require('nodotjson.json') and require('nodotjson.json.js') + // should resolve to the same file + let nodotjsonjs = require('./fixtures/loader/json/nodotjson.json.js'); + assert.equal(nodotjsonjs.data.prop, 'hydralisk', + 'js modules are cached whether access via .json.js or .json'); +}; require('test').run(exports); diff --git a/addon-sdk/source/test/test-net-url.js b/addon-sdk/source/test/test-net-url.js index 986ea5ebf18..6ce2a328bc7 100644 --- a/addon-sdk/source/test/test-net-url.js +++ b/addon-sdk/source/test/test-net-url.js @@ -5,7 +5,7 @@ "use strict"; const { readURI, readURISync } = require("sdk/net/url"); -const { data } = require("sdk/self"); +const data = require("./fixtures"); const utf8text = "Hello, ゼロ!"; const latin1text = "Hello, ゼロ!"; diff --git a/addon-sdk/source/test/test-page-mod.js b/addon-sdk/source/test/test-page-mod.js index 26be1608797..b17ffe8034b 100644 --- a/addon-sdk/source/test/test-page-mod.js +++ b/addon-sdk/source/test/test-page-mod.js @@ -13,15 +13,18 @@ const { open, getFrames, getMostRecentBrowserWindow } = require('sdk/window/util const windowUtils = require('sdk/deprecated/window-utils'); const { getTabContentWindow, getActiveTab, setTabURL, openTab, closeTab } = require('sdk/tabs/utils'); const xulApp = require("sdk/system/xul-app"); -const { data, isPrivateBrowsingSupported } = require('sdk/self'); +const { isPrivateBrowsingSupported } = require('sdk/self'); const { isPrivate } = require('sdk/private-browsing'); const { openWebpage } = require('./private-browsing/helper'); const { isTabPBSupported, isWindowPBSupported, isGlobalPBSupported } = require('sdk/private-browsing/utils'); const promise = require("sdk/core/promise"); const { pb } = require('./private-browsing/helper'); const { URL } = require("sdk/url"); -const testPageURI = require("sdk/self").data.url("test.html"); + const { waitUntil } = require("sdk/test/utils"); +const data = require("./fixtures"); + +const testPageURI = data.url("test.html"); // The following adds Debugger constructor to the global namespace. const { addDebuggerToGlobal } = @@ -311,7 +314,7 @@ exports.testHistory = function(assert, done) { // We need a valid url in order to have a working History API. // (i.e do not work on data: or about: pages) // Test bug 679054. - let url = require("sdk/self").data.url("test-page-mod.html"); + let url = data.url("test-page-mod.html"); let callbackDone = null; testPageMod(assert, done, url, [{ include: url, @@ -691,8 +694,7 @@ exports.testPageModCss = function(assert, done) { 'data:text/html;charset=utf-8,
css test
', [{ include: ["*", "data:*"], contentStyle: "div { height: 100px; }", - contentStyleFile: - require("sdk/self").data.url("pagemod-css-include-file.css") + contentStyleFile: data.url("pagemod-css-include-file.css") }], function(win, done) { let div = win.document.querySelector("div"); diff --git a/addon-sdk/source/test/test-page-worker.js b/addon-sdk/source/test/test-page-worker.js index e55299f6936..dbdca227d0a 100644 --- a/addon-sdk/source/test/test-page-worker.js +++ b/addon-sdk/source/test/test-page-worker.js @@ -8,7 +8,8 @@ const { Loader } = require('sdk/test/loader'); const Pages = require("sdk/page-worker"); const Page = Pages.Page; const { URL } = require("sdk/url"); -const testURI = require("sdk/self").data.url("test.html"); +const fixtures = require("./fixtures"); +const testURI = fixtures.url("test.html"); const ERR_DESTROYED = "Couldn't find the worker to receive this message. " + @@ -264,8 +265,8 @@ exports.testLoadContentPage = function(assert, done) { return done(); assert[msg].apply(assert, message); }, - contentURL: require("sdk/self").data.url("test-page-worker.html"), - contentScriptFile: require("sdk/self").data.url("test-page-worker.js"), + contentURL: fixtures.url("test-page-worker.html"), + contentScriptFile: fixtures.url("test-page-worker.js"), contentScriptWhen: "ready" }); } diff --git a/addon-sdk/source/test/test-panel.js b/addon-sdk/source/test/test-panel.js index 2bc5bd5dfde..8cc20192d2d 100644 --- a/addon-sdk/source/test/test-panel.js +++ b/addon-sdk/source/test/test-panel.js @@ -22,8 +22,9 @@ const { getMostRecentBrowserWindow } = require('sdk/window/utils'); const { getWindow } = require('sdk/panel/window'); const { pb } = require('./private-browsing/helper'); const { URL } = require('sdk/url'); +const fixtures = require('./fixtures') -const SVG_URL = self.data.url('mofo_logo.SVG'); +const SVG_URL = fixtures.url('mofo_logo.SVG'); const Isolate = fn => '(' + fn + ')()'; function ignorePassingDOMNodeWarning(type, message) { diff --git a/addon-sdk/source/test/test-promise.js b/addon-sdk/source/test/test-promise.js index c64096918e5..d04aea037a6 100644 --- a/addon-sdk/source/test/test-promise.js +++ b/addon-sdk/source/test/test-promise.js @@ -276,6 +276,21 @@ exports['test promised error handleing'] = function(assert, done) { }) } +exports['test errors in promise resolution handlers are propagated'] = function(assert, done) { + var expected = Error('Boom'); + var { promise, resolve } = defer(); + + promise.then(function() { + throw expected; + }).then(function() { + return undefined; + }).then(null, function(actual) { + assert.equal(actual, expected, 'rejected as expected'); + }).then(done, assert.fail); + + resolve({}); +} + exports['test return promise form promised'] = function(assert, done) { var f = promised(function() { return resolve(17) diff --git a/addon-sdk/source/test/test-self.js b/addon-sdk/source/test/test-self.js index 1e3b6dbe60f..47b00fe7765 100644 --- a/addon-sdk/source/test/test-self.js +++ b/addon-sdk/source/test/test-self.js @@ -10,9 +10,6 @@ const self = require("sdk/self"); const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {}); exports.testSelf = function(assert) { - var source = self.data.load("test-content-symbiont.js"); - assert.ok(source.match(/test-content-symbiont/), "self.data.load() works"); - // Likewise, we can't assert anything about the full URL, because that // depends on self.id . We can only assert that it ends in the right // thing. diff --git a/addon-sdk/source/test/test-system-events.js b/addon-sdk/source/test/test-system-events.js index 0491d16f89c..64aa5493f9d 100644 --- a/addon-sdk/source/test/test-system-events.js +++ b/addon-sdk/source/test/test-system-events.js @@ -17,7 +17,7 @@ exports["test basic"] = function(assert) { let type = Date.now().toString(32); let timesCalled = 0; - function handler(subject, data) { timesCalled++; }; + function handler({subject, data}) { timesCalled++; }; events.on(type, handler); events.emit(type, { data: "yo yo" }); @@ -36,6 +36,32 @@ exports["test basic"] = function(assert) { assert.equal(timesCalled, 2, "handlers added via once are triggered once"); } +exports["test simple argument passing"] = function (assert) { + let type = Date.now().toString(32); + + let lastArg; + function handler({data}) { lastArg = data; } + events.on(type, handler); + + [true, false, 100, 0, 'a string', ''].forEach(arg => { + events.emit(type, arg); + assert.strictEqual(lastArg, arg + '', + 'event emitted for ' + arg + ' has correct data value'); + + events.emit(type, { data: arg }); + assert.strictEqual(lastArg, arg + '', + 'event emitted for ' + arg + ' has correct data value when a property on an object'); + }); + + [null, undefined, {}].forEach(arg => { + events.emit(type, arg); + assert.strictEqual(lastArg, null, + 'emitting ' + arg + ' gets null data'); + }); + + events.off(type, handler); +}; + exports["test error reporting"] = function(assert) { let { loader, messages } = LoaderWithHookedConsole2(module); @@ -220,7 +246,7 @@ exports["test emit to nsIObserverService observers"] = function(assert) { assert.equal(lastData, "data again", "event.data is notification data"); nsIObserverService.removeObserver(nsIObserver, "*"); - + events.emit(topic, { data: "last data" }); assert.equal(timesCalled, 3, "removed observers no longer invoked"); } diff --git a/addon-sdk/source/test/test-ui-button.js b/addon-sdk/source/test/test-ui-button.js index 3f05eeb7744..f481fae2906 100644 --- a/addon-sdk/source/test/test-ui-button.js +++ b/addon-sdk/source/test/test-ui-button.js @@ -11,7 +11,7 @@ module.metadata = { const { Cu } = require('chrome'); const { Loader } = require('sdk/test/loader'); -const { data } = require('sdk/self'); +const data = require('./fixtures'); const { open, focus, close } = require('sdk/window/helpers'); const { setTimeout } = require('sdk/timers'); const { getMostRecentBrowserWindow } = require('sdk/window/utils'); diff --git a/addon-sdk/source/test/test-ui-sidebar.js b/addon-sdk/source/test/test-ui-sidebar.js index 1177a6c45d2..1efec36609e 100644 --- a/addon-sdk/source/test/test-ui-sidebar.js +++ b/addon-sdk/source/test/test-ui-sidebar.js @@ -15,9 +15,9 @@ const { show, hide } = require('sdk/ui/sidebar/actions'); const { isShowing } = require('sdk/ui/sidebar/utils'); const { getMostRecentBrowserWindow } = require('sdk/window/utils'); const { open, close, focus, promise: windowPromise } = require('sdk/window/helpers'); -const { setTimeout } = require('sdk/timers'); +const { setTimeout, setImmediate } = require('sdk/timers'); const { isPrivate } = require('sdk/private-browsing'); -const { data } = require('sdk/self'); +const data = require('./fixtures'); const { URL } = require('sdk/url'); const { once, off, emit } = require('sdk/event/core'); const { defer, all } = require('sdk/core/promise'); @@ -251,6 +251,32 @@ exports.testAddonGlobalComplex = function(assert, done) { show(sidebar); } +exports.testAddonReady = function(assert, done) { + const { Sidebar } = require('sdk/ui/sidebar'); + let testName = 'testAddonReady'; + let sidebar = Sidebar({ + id: testName, + title: testName, + url: data.url('test-sidebar-addon-global.html'), + onReady: function(worker) { + assert.pass('sidebar was attached'); + assert.ok(!!worker, 'attach event has worker'); + + worker.port.on('X', function(msg) { + assert.equal(msg, '123', 'the final message is correct'); + + sidebar.destroy(); + + done(); + }); + + worker.port.emit('X', '12'); + } + }); + + show(sidebar); +} + exports.testShowingOneSidebarAfterAnother = function(assert, done) { const { Sidebar } = require('sdk/ui/sidebar'); let testName = 'testShowingOneSidebarAfterAnother'; @@ -356,7 +382,7 @@ exports.testRemoteContent = function(assert) { sidebar.destroy(); } catch(e) { - assert.ok(/The option "url" must be a valid URI./.test(e), 'remote content is not acceptable'); + assert.ok(/The option "url" must be a valid local URI\./.test(e), 'remote content is not acceptable'); } } @@ -373,7 +399,7 @@ exports.testInvalidURL = function(assert) { sidebar.destroy(); } catch(e) { - assert.ok(/The option "url" must be a valid URI./.test(e), 'invalid URIs are not acceptable'); + assert.ok(/The option "url" must be a valid local URI\./.test(e), 'invalid URIs are not acceptable'); } } @@ -389,7 +415,7 @@ exports.testInvalidURLType = function(assert) { sidebar.destroy(); } catch(e) { - assert.ok(/The option "url" must be a valid URI./.test(e), 'invalid URIs are not acceptable'); + assert.ok(/The option "url" must be a valid local URI\./.test(e), 'invalid URIs are not acceptable'); } } @@ -461,19 +487,24 @@ exports.testInvalidNullID = function(assert) { } } -exports.testInvalidUndefinedID = function(assert) { +exports.testUndefinedID = function(assert) { const { Sidebar } = require('sdk/ui/sidebar'); - let testName = 'testInvalidBlankID'; + let testName = 'testInvalidUndefinedID'; + try { let sidebar = Sidebar({ title: testName, - url: 'data:text/html;charset=utf-8,'+testName + url: 'data:text/html;charset=utf-8,' + testName }); - assert.fail('a bad sidebar was created..'); + + assert.ok(sidebar.id, 'an undefined id was accepted, id was creawted: ' + sidebar.id); + assert.ok(getMostRecentBrowserWindow().document.getElementById(makeID(sidebar.id)), 'the sidebar element was found'); + sidebar.destroy(); } catch(e) { - assert.ok(/The option "id" must be a valid alphanumeric id/.test(e), 'invalid ids are not acceptable'); + assert.fail('undefined ids are acceptable'); + assert.fail(e.message); } } @@ -892,6 +923,64 @@ exports.testGCdShowingSidebarsOnUnload = function(assert, done) { sidebar.show(); } +exports.testDetachEventOnWindowClose = function(assert, done) { + const loader = Loader(module); + const { Sidebar } = loader.require('sdk/ui/sidebar'); + const window = getMostRecentBrowserWindow(); + + let testName = 'testDetachEventOnWindowClose'; + let url = 'data:text/html;charset=utf-8,' + testName; + + + windowPromise(window.OpenBrowserWindow(), 'load').then(focus).then(function(window) { + let sidebar = Sidebar({ + id: testName, + title: testName, + url: url, + onAttach: function() { + assert.pass('the attach event is fired'); + window.close(); + }, + onDetach: function() { + assert.pass('the detach event is fired when the window showing it closes'); + loader.unload(); + done(); + } + }); + + sidebar.show(); + }).then(null, assert.fail); +} + +exports.testHideEventOnWindowClose = function(assert, done) { + const loader = Loader(module); + const { Sidebar } = loader.require('sdk/ui/sidebar'); + const window = getMostRecentBrowserWindow(); + + let testName = 'testDetachEventOnWindowClose'; + let url = 'data:text/html;charset=utf-8,' + testName; + + + windowPromise(window.OpenBrowserWindow(), 'load').then(focus).then(function(window) { + let sidebar = Sidebar({ + id: testName, + title: testName, + url: url, + onAttach: function() { + assert.pass('the attach event is fired'); + window.close(); + }, + onHide: function() { + assert.pass('the hide event is fired when the window showing it closes'); + loader.unload(); + done(); + } + }); + + sidebar.show(); + }).then(null, assert.fail); +} + exports.testGCdHiddenSidebarsOnUnload = function(assert, done) { const loader = Loader(module); const { Sidebar } = loader.require('sdk/ui/sidebar'); @@ -1078,6 +1167,35 @@ exports.testTwoSidebarsWithSameTitleAndURL = function(assert) { sidebar2.destroy(); } +exports.testChangingURLBackToOriginalValue = function(assert) { + const { Sidebar } = require('sdk/ui/sidebar'); + let testName = 'testChangingURLBackToOriginalValue'; + + let title = testName; + let url = 'data:text/html;charset=utf-8,' + testName; + let count = 0; + + let sidebar = Sidebar({ + id: testName, + title: title, + url: url + }); + + sidebar.url = url + 2; + assert.equal(sidebar.url, url + 2, 'the sidebar.url is correct'); + sidebar.url = url; + assert.equal(sidebar.url, url, 'the sidebar.url is correct'); + + sidebar.title = 'foo'; + assert.equal(sidebar.title, 'foo', 'the sidebar.title is correct'); + sidebar.title = title; + assert.equal(sidebar.title, title, 'the sidebar.title is correct'); + + sidebar.destroy(); + + assert.pass('Changing values back to originals works'); +} + exports.testShowToOpenXToClose = function(assert, done) { const { Sidebar } = require('sdk/ui/sidebar'); let testName = 'testShowToOpenXToClose'; @@ -1181,14 +1299,17 @@ exports.testEventListeners = function(assert, done) { let constructorOnShow = defer(); let constructorOnHide = defer(); let constructorOnAttach = defer(); + let constructorOnReady = defer(); let onShow = defer(); let onHide = defer(); let onAttach = defer(); + let onReady = defer(); let onceShow = defer(); let onceHide = defer(); let onceAttach = defer(); + let onceReady = defer(); function testThis() { assert(this, sidebar, '`this` is correct'); @@ -1208,6 +1329,11 @@ exports.testEventListeners = function(assert, done) { eventListenerOrder.push('onAttach'); constructorOnAttach.resolve(); }, + onReady: function() { + assert.equal(this, sidebar, '`this` is correct in onReady'); + eventListenerOrder.push('onReady'); + constructorOnReady.resolve(); + }, onHide: function() { assert.equal(this, sidebar, '`this` is correct in onHide'); eventListenerOrder.push('onHide'); @@ -1225,6 +1351,11 @@ exports.testEventListeners = function(assert, done) { eventListenerOrder.push('once attach'); onceAttach.resolve(); }); + sidebar.once('ready', function() { + assert.equal(this, sidebar, '`this` is correct in once ready'); + eventListenerOrder.push('once ready'); + onceReady.resolve(); + }); sidebar.once('hide', function() { assert.equal(this, sidebar, '`this` is correct in once hide'); eventListenerOrder.push('once hide'); @@ -1243,6 +1374,11 @@ exports.testEventListeners = function(assert, done) { eventListenerOrder.push('on attach'); onAttach.resolve(); }); + sidebar.on('ready', function() { + assert.equal(this, sidebar, '`this` is correct in on ready'); + eventListenerOrder.push('on ready'); + onReady.resolve(); + }); sidebar.on('hide', function() { assert.equal(this, sidebar, '`this` is correct in on hide'); eventListenerOrder.push('on hide'); @@ -1251,17 +1387,23 @@ exports.testEventListeners = function(assert, done) { all(constructorOnShow.promise, constructorOnAttach.promise, + constructorOnReady.promise, constructorOnHide.promise, onceShow.promise, onceAttach.promise, + onceReady.promise, onceHide.promise, onShow.promise, onAttach.promise, + onReady.promise, onHide.promise).then(function() { assert.equal(eventListenerOrder.join(), [ 'onAttach', 'once attach', 'on attach', + 'onReady', + 'once ready', + 'on ready', 'onShow', 'once show', 'on show', @@ -1275,6 +1417,58 @@ exports.testEventListeners = function(assert, done) { sidebar.show(); } +// For more information see Bug 920780 +exports.testAttachDoesNotEmitWhenShown = function(assert, done) { + const { Sidebar } = require('sdk/ui/sidebar'); + let testName = 'testSidebarLeakCheckUnloadAfterAttach'; + let count = 0; + + let sidebar = Sidebar({ + id: testName, + title: testName, + url: 'data:text/html;charset=utf-8,'+testName, + onAttach: function() { + if (count > 2) { + assert.fail('sidebar was attached again..'); + } + else { + assert.pass('sidebar was attached ' + count + ' time(s)'); + } + + if (++count == 1) { + setTimeout(function() { + let shown = false; + let endShownTest = false; + sidebar.once('show', function() { + assert.pass('shown was emitted'); + shown = !endShownTest && true; + }); + + sidebar.show().then(function() { + assert.pass('calling hide'); + sidebar.hide(); + }).then(function() { + endShownTest = true; + + setTimeout(function() { + sidebar.show().then(function() { + assert.ok(!shown, 'show did not emit'); + + sidebar.hide().then(function() { + sidebar.destroy(); + done(); + }).then(null, assert.fail); + }) + }) + }).then(null, assert.fail); + }); + } + } + }); + + sidebar.show(); +} + // If the module doesn't support the app we're being run in, require() will // throw. In that case, remove all tests above from exports, and add one dummy // test that passes. diff --git a/addon-sdk/source/test/test-widget.js b/addon-sdk/source/test/test-widget.js index 4d0a00da54a..9d54d39296c 100644 --- a/addon-sdk/source/test/test-widget.js +++ b/addon-sdk/source/test/test-widget.js @@ -18,6 +18,7 @@ const self = require("sdk/self"); const windowUtils = require("sdk/deprecated/window-utils"); const { getMostRecentBrowserWindow } = require('sdk/window/utils'); const { close } = require("sdk/window/helpers"); +const fixtures = require("./fixtures"); let jetpackID = "testID"; try { @@ -243,7 +244,7 @@ exports.testConstructor = function(assert, done) { tests.push(function testImageURLWidget() testSingleWidget({ id: "image", label: "image url widget", - contentURL: require("sdk/self").data.url("test.html"), + contentURL: fixtures.url("test.html"), contentScript: "self.postMessage({title: document.title, " + "tag: document.body.firstElementChild.tagName, " + "content: document.body.firstElementChild.innerHTML});", @@ -261,7 +262,7 @@ exports.testConstructor = function(assert, done) { tests.push(function testWebURIWidget() testSingleWidget({ id: "web", label: "web uri widget", - contentURL: require("sdk/self").data.url("test.html"), + contentURL: fixtures.url("test.html"), contentScript: "self.postMessage({title: document.title, " + "tag: document.body.firstElementChild.tagName, " + "content: document.body.firstElementChild.innerHTML});", @@ -324,7 +325,7 @@ exports.testConstructor = function(assert, done) { tests.push(function testOnclickEventImage() testSingleWidget({ id: "click", label: "click test widget - image", - contentURL: require("sdk/self").data.url("moz_favicon.ico"), + contentURL: fixtures.url("moz_favicon.ico"), contentScript: "var evt = new MouseEvent('click'); " + "document.body.firstElementChild.dispatchEvent(evt);", contentScriptWhen: "end", @@ -339,7 +340,7 @@ exports.testConstructor = function(assert, done) { tests.push(function testOnmouseoverEventImage() testSingleWidget({ id: "mouseover", label: "mouseover test widget - image", - contentURL: require("sdk/self").data.url("moz_favicon.ico"), + contentURL: fixtures.url("moz_favicon.ico"), contentScript: "var evt = new MouseEvent('mouseover');" + "document.body.firstElementChild.dispatchEvent(evt);", contentScriptWhen: "end", @@ -354,7 +355,7 @@ exports.testConstructor = function(assert, done) { tests.push(function testOnmouseoutEventImage() testSingleWidget({ id: "mouseout", label: "mouseout test widget - image", - contentURL: require("sdk/self").data.url("moz_favicon.ico"), + contentURL: fixtures.url("moz_favicon.ico"), contentScript: "var evt = new MouseEvent('mouseout'); " + "document.body.firstElementChild.dispatchEvent(evt);", contentScriptWhen: "end", @@ -1034,7 +1035,7 @@ exports.testPostMessageOnLocationChange = function(assert, done) { exports.testSVGWidget = function(assert, done) { // use of capital SVG here is intended, that was failing.. - let SVG_URL = self.data.url("mofo_logo.SVG"); + let SVG_URL = fixtures.url("mofo_logo.SVG"); let widget = require("sdk/widget").Widget({ id: "mozilla-svg-logo", diff --git a/addon-sdk/source/test/test-window-utils.js b/addon-sdk/source/test/test-window-utils.js index c76d264b6ab..2d6f61368d1 100644 --- a/addon-sdk/source/test/test-window-utils.js +++ b/addon-sdk/source/test/test-window-utils.js @@ -13,7 +13,7 @@ const windowUtils = require("sdk/deprecated/window-utils"); const timer = require("sdk/timers"); const { Cc, Ci } = require("chrome"); const { Loader } = require("sdk/test/loader"); -const { open, getFrames, getWindowTitle, onFocus } = require('sdk/window/utils'); +const { open, getFrames, getWindowTitle, onFocus, windows } = require('sdk/window/utils'); const { close } = require('sdk/window/helpers'); const { fromIterator: toArray } = require('sdk/util/array'); @@ -297,4 +297,29 @@ exports.testWindowIterator = function(assert, done) { }, false); }; +exports.testIgnoreClosingWindow = function(assert, done) { + assert.equal(windows().length, 1, "Only one window open"); + + // make a new window + let window = makeEmptyWindow(); + + assert.equal(windows().length, 2, "Two windows open"); + + window.addEventListener("load", function onload() { + window.addEventListener("load", onload, false); + + assert.equal(windows().length, 2, "Two windows open"); + + // Wait for the window unload before ending test + let checked = false; + + close(window).then(function() { + assert.ok(checked, 'the test is finished'); + }).then(done, assert.fail) + + assert.equal(windows().length, 1, "Only one window open"); + checked = true; + }, false); +}; + require("test").run(exports); diff --git a/addon-sdk/source/test/test-xhr.js b/addon-sdk/source/test/test-xhr.js index 25407be684d..e138e7fd04e 100644 --- a/addon-sdk/source/test/test-xhr.js +++ b/addon-sdk/source/test/test-xhr.js @@ -5,8 +5,9 @@ const { XMLHttpRequest } = require('sdk/net/xhr'); const { LoaderWithHookedConsole } = require('sdk/test/loader'); -const { data } = require('sdk/self'); const { set: setPref } = require("sdk/preferences/service"); +const data = require("./fixtures"); + const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings"; exports.testAPIExtension = function(assert) { From c59873227f2f55713e6e724f2cbffaeabc8944b6 Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Thu, 31 Oct 2013 10:59:35 +1100 Subject: [PATCH 31/53] Bug 906839 - enable by default social.allowMultipleWorkers - update tests to work pref'd on and fix a missing update to the worker state, r=markh. --- browser/app/profile/firefox.js | 2 + .../test/social/browser_social_chatwindow.js | 72 +++++++++---------- .../base/content/test/social/social_worker.js | 4 +- browser/modules/Social.jsm | 4 +- toolkit/components/social/FrameWorker.jsm | 6 +- .../test/browser/browser_SocialProvider.js | 2 +- 6 files changed, 46 insertions(+), 44 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 274fdd4349d..acfd3b33928 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1300,6 +1300,8 @@ pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"nam pref("social.sidebar.open", true); pref("social.sidebar.unload_timeout_ms", 10000); +pref("social.allowMultipleWorkers", true); + pref("dom.identity.enabled", false); // Turn on the CSP 1.0 parser for Content Security Policy headers diff --git a/browser/base/content/test/social/browser_social_chatwindow.js b/browser/base/content/test/social/browser_social_chatwindow.js index c764393f0b3..a4809f0653a 100644 --- a/browser/base/content/test/social/browser_social_chatwindow.js +++ b/browser/base/content/test/social/browser_social_chatwindow.js @@ -51,18 +51,6 @@ function waitPrefChange(cb) { }, false); } -function setWorkerMode(multiple, cb) { - waitPrefChange(function() { - if (multiple) - Services.prefs.setBoolPref("social.allowMultipleWorkers", true); - else - Services.prefs.clearUserPref("social.allowMultipleWorkers"); - waitPrefChange(cb); - Social.enabled = true; - }); - Social.enabled = false; -} - function test() { requestLongerTimeout(2); // only debug builds seem to need more time... waitForExplicitFinish(); @@ -75,8 +63,15 @@ function test() { ok(chats.children.length == 0, "no chatty children left behind"); cb(); }; + // always run chat tests with multiple workers. + Services.prefs.setBoolPref("social.allowMultipleWorkers", true); runSocialTestWithProvider(manifests, function (finishcb) { + ok(Social.enabled, "Social is enabled"); + ok(Social.providers[0].getWorkerPort(), "provider 0 has port"); + ok(Social.providers[1].getWorkerPort(), "provider 1 has port"); + ok(Social.providers[2].getWorkerPort(), "provider 2 has port"); runSocialTests(tests, undefined, postSubTest, function() { + Services.prefs.clearUserPref("social.allowMultipleWorkers"); window.moveTo(oldleft, window.screenY) window.resizeTo(oldwidth, window.outerHeight); finishcb(); @@ -517,30 +512,31 @@ var tests = { }); }, testMultipleProviderChat: function(next) { - // while pref'd off, we need to set the worker mode to multiple providers - setWorkerMode(true, function() { - // test incomming chats from all providers - openChat(Social.providers[0], function() { - openChat(Social.providers[1], function() { - openChat(Social.providers[2], function() { - let chats = document.getElementById("pinnedchats"); - waitForCondition(function() chats.children.length == Social.providers.length, - function() { - ok(true, "one chat window per provider opened"); - // test logout of a single provider - let provider = Social.providers[0]; - let port = provider.getWorkerPort(); - port.postMessage({topic: "test-logout"}); - waitForCondition(function() chats.children.length == Social.providers.length - 1, - function() { - port.close(); - chats.removeAll(); - ok(!chats.selectedChat, "chats are all closed"); - setWorkerMode(false, next); - }, - "chat window didn't close"); - }, "chat windows did not open"); - }); + // test incomming chats from all providers + openChat(Social.providers[0], function() { + openChat(Social.providers[1], function() { + openChat(Social.providers[2], function() { + let chats = document.getElementById("pinnedchats"); + waitForCondition(function() chats.children.length == Social.providers.length, + function() { + ok(true, "one chat window per provider opened"); + // test logout of a single provider + let provider = Social.providers[2]; + let port = provider.getWorkerPort(); + port.postMessage({topic: "test-logout"}); + waitForCondition(function() chats.children.length == Social.providers.length - 1, + function() { + chats.removeAll(); + waitForCondition(function() chats.children.length == 0, + function() { + ok(!chats.selectedChat, "multiprovider chats are all closed"); + port.close(); + next(); + }, + "chat windows didn't close"); + }, + "chat window didn't close"); + }, "chat windows did not open"); }); }); }); @@ -578,6 +574,10 @@ var tests = { break; } } + // make sure a user profile is set for this provider as chat windows are + // only closed on *change* of the profile data rather than merely setting + // profile data. + port.postMessage({topic: "test-set-profile"}); port.postMessage({topic: "test-init"}); } } diff --git a/browser/base/content/test/social/social_worker.js b/browser/base/content/test/social/social_worker.js index 256c13e2a4a..1bea0d0ccc6 100644 --- a/browser/base/content/test/social/social_worker.js +++ b/browser/base/content/test/social/social_worker.js @@ -84,6 +84,8 @@ onconnect = function(e) { // For multiprovider tests, we support acting like different providers // based on the domain we load from. apiPort = port; + // purposely fall through and set the profile on initialization + case "test-set-profile": let profile; if (location.href.indexOf("https://test1.example.com") == 0) { profile = { @@ -99,7 +101,7 @@ onconnect = function(e) { profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa" }; } - port.postMessage({topic: "social.user-profile", data: profile}); + apiPort.postMessage({topic: "social.user-profile", data: profile}); break; case "test-ambient-notification": apiPort.postMessage({topic: "social.ambient-notification", data: event.data.data}); diff --git a/browser/modules/Social.jsm b/browser/modules/Social.jsm index ee2d1c430d5..45a476c841f 100644 --- a/browser/modules/Social.jsm +++ b/browser/modules/Social.jsm @@ -95,8 +95,7 @@ this.Social = { _disabledForSafeMode: false, get allowMultipleWorkers() { - return Services.prefs.prefHasUserValue("social.allowMultipleWorkers") && - Services.prefs.getBoolPref("social.allowMultipleWorkers"); + return Services.prefs.getBoolPref("social.allowMultipleWorkers"); }, get _currentProviderPref() { @@ -141,6 +140,7 @@ this.Social = { let enabled = !!provider; if (enabled != SocialService.enabled) { SocialService.enabled = enabled; + this._updateWorkerState(enabled); } let origin = this._provider && this._provider.origin; diff --git a/toolkit/components/social/FrameWorker.jsm b/toolkit/components/social/FrameWorker.jsm index 014dc51fea8..82cafca019b 100644 --- a/toolkit/components/social/FrameWorker.jsm +++ b/toolkit/components/social/FrameWorker.jsm @@ -199,15 +199,13 @@ function makeRemoteBrowser() { let browser = iframe.contentDocument.createElementNS(XUL_NS, "browser"); browser.setAttribute("type", "content"); browser.setAttribute("disableglobalhistory", "true"); - let remote; // for now we use the same preference that enabled multiple workers - the // idea is that there is no point in having people help test multiple // "old" frameworkers - so anyone who wants multiple workers is forced to // help us test remote frameworkers too. - if (Services.prefs.prefHasUserValue("social.allowMultipleWorkers") && - Services.prefs.getBoolPref("social.allowMultipleWorkers")) { + if (Services.prefs.getBoolPref("social.allowMultipleWorkers")) browser.setAttribute("remote", "true"); - } + iframe.contentDocument.documentElement.appendChild(browser); deferred.resolve(browser); }, true); diff --git a/toolkit/components/social/test/browser/browser_SocialProvider.js b/toolkit/components/social/test/browser/browser_SocialProvider.js index 81582f12061..5cd5931a197 100644 --- a/toolkit/components/social/test/browser/browser_SocialProvider.js +++ b/toolkit/components/social/test/browser/browser_SocialProvider.js @@ -62,7 +62,7 @@ let tests = { }; SocialService.addProvider(manifest, function (provider2) { ok(provider.enabled, "provider is initially enabled"); - ok(!provider2.enabled, "provider2 is not initially enabled"); + is(provider2.enabled, Services.prefs.getBoolPref("social.allowMultipleWorkers"), "provider2 is enabled status is correct"); provider2.enabled = true; let port = provider.getWorkerPort(); let port2 = provider2.getWorkerPort(); From 4cf5f1217bb200438cf16cd6ef8e891c6632ecea Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Thu, 31 Oct 2013 10:59:36 +1100 Subject: [PATCH 32/53] Bug 906839 - test fixes. r=markh --- browser/base/content/test/social/browser_social_flyout.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/browser/base/content/test/social/browser_social_flyout.js b/browser/base/content/test/social/browser_social_flyout.js index 1bf2307db9b..871919b8b73 100644 --- a/browser/base/content/test/social/browser_social_flyout.js +++ b/browser/base/content/test/social/browser_social_flyout.js @@ -113,15 +113,17 @@ var tests = { port.postMessage({topic: "test-flyout-open"}); break; case "got-flyout-visibility": + if (e.data.result != "shown") + return; let iframe = panel.firstChild; iframe.contentDocument.addEventListener("SocialTest-DoneCloseSelf", function _doneHandler() { iframe.contentDocument.removeEventListener("SocialTest-DoneCloseSelf", _doneHandler, false); + port.close(); is(panel.state, "closed", "flyout should have closed itself"); Services.prefs.setBoolPref(ALLOW_SCRIPTS_TO_CLOSE_PREF, oldAllowScriptsToClose); next(); }, false); is(panel.state, "open", "flyout should be open"); - port.close(); // so we don't get the -visibility message as it hides... SocialFlyout.dispatchPanelEvent("socialTest-CloseSelf"); break; } From c7a06676688d61ec9ccc45a1efd39d227af915d7 Mon Sep 17 00:00:00 2001 From: Mark Hammond Date: Thu, 31 Oct 2013 10:59:36 +1100 Subject: [PATCH 33/53] Bug 906839 - disable one social test due to bug 919878. r=gavin --- .../components/social/test/browser/browser_frameworker.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toolkit/components/social/test/browser/browser_frameworker.js b/toolkit/components/social/test/browser/browser_frameworker.js index a7d1707e615..2ade7c9fd68 100644 --- a/toolkit/components/social/test/browser/browser_frameworker.js +++ b/toolkit/components/social/test/browser/browser_frameworker.js @@ -49,6 +49,11 @@ let tests = { }, // when the client closes early but the worker tries to send anyway... + // XXX - disabled due to bug 919878 - we close the frameworker before the + // remote browser has completed initializing, leading to failures. Given + // this can realistically only happen in this synthesized test environment, + // disabling just this test seems OK for now. +/*** testEarlyClose: function(cbnext) { let run = function() { onconnect = function(e) { @@ -62,6 +67,7 @@ let tests = { worker.terminate(); cbnext(); }, +***/ // Check we do get a social.port-closing message as the port is closed. testPortClosingMessage: function(cbnext) { From 6602b7c8c3cc52459b866db4c4145c565c97d4be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Qu=C3=A8ze?= Date: Tue, 5 Nov 2013 13:06:23 +0100 Subject: [PATCH 34/53] Bug 906839 - disable frameworker tests on ASAN builds, r=markh. --- toolkit/components/social/test/browser/Makefile.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/toolkit/components/social/test/browser/Makefile.in b/toolkit/components/social/test/browser/Makefile.in index 8bb59b9b04a..9527505632f 100644 --- a/toolkit/components/social/test/browser/Makefile.in +++ b/toolkit/components/social/test/browser/Makefile.in @@ -10,8 +10,6 @@ MOCHITEST_BROWSER_FILES = \ data.json \ echo.sjs \ worker_xhr.js \ - browser_frameworker.js \ - browser_frameworker_sandbox.js \ worker_relative.js \ relative_import.js \ browser_workerAPI.js \ @@ -23,4 +21,12 @@ MOCHITEST_BROWSER_FILES = \ eventsource.resource^headers^ \ $(NULL) +ifndef MOZ_ASAN +# These tests are currently unreliable on ASAN builds with remote frameworkers. +MOCHITEST_BROWSER_FILES += \ + browser_frameworker.js \ + browser_frameworker_sandbox.js \ + $(NULL) +endif + endif From 792ace36fa3222f927cfd2a4a0e8fa0606f4cfe2 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Tue, 5 Nov 2013 16:43:53 -0500 Subject: [PATCH 35/53] Bug 934774 - Intermittent exception is killing mochitests (primarily browser_pluginnotification.js) because we're dispatching an event to a document which is already dead. Check it's aliveness before dispatching, r=johns --HG-- extra : rebase_source : b12ee9219793da46ebec5b1a770f3a1d80ea4c66 --- content/base/src/nsObjectLoadingContent.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index a4c425b590e..f4bb4931695 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -227,6 +227,7 @@ public: , mDocument(aTarget->GetCurrentDoc()) , mEvent(aEvent) { + MOZ_ASSERT(aTarget && mDocument); } nsSimplePluginEvent(nsIDocument* aTarget, const nsAString& aEvent) @@ -234,6 +235,7 @@ public: , mDocument(aTarget) , mEvent(aEvent) { + MOZ_ASSERT(aTarget); } ~nsSimplePluginEvent() {} @@ -249,10 +251,12 @@ private: NS_IMETHODIMP nsSimplePluginEvent::Run() { - LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mTarget.get(), - mEvent.get())); - nsContentUtils::DispatchTrustedEvent(mDocument, mTarget, - mEvent, true, true); + if (mDocument->IsActive()) { + LOG(("OBJLC [%p]: nsSimplePluginEvent firing event \"%s\"", mTarget.get(), + NS_ConvertUTF16toUTF8(mEvent).get())); + nsContentUtils::DispatchTrustedEvent(mDocument, mTarget, + mEvent, true, true); + } return NS_OK; } @@ -710,9 +714,12 @@ nsObjectLoadingContent::UnbindFromTree(bool aDeep, bool aNullParent) /// would keep the docshell around, but trash the frameloader UnloadObject(); } - nsCOMPtr ev = new nsSimplePluginEvent(thisContent->GetCurrentDoc(), - NS_LITERAL_STRING("PluginRemoved")); - NS_DispatchToCurrentThread(ev); + nsIDocument* doc = thisContent->GetCurrentDoc(); + if (doc && doc->IsActive()) { + nsCOMPtr ev = new nsSimplePluginEvent(doc, + NS_LITERAL_STRING("PluginRemoved")); + NS_DispatchToCurrentThread(ev); + } } nsObjectLoadingContent::nsObjectLoadingContent() From 646382fbac55e9009ff3dd88486821b0d5ce38d1 Mon Sep 17 00:00:00 2001 From: Benjamin Smedberg Date: Tue, 5 Nov 2013 16:43:53 -0500 Subject: [PATCH 36/53] Bug 934503 - Activated hidden plugins should not show the hidden plugin notification icon, r=jaws --HG-- extra : rebase_source : bdae17aa44e5fbe60d724b3ad98f679da9c851f1 --- browser/base/content/browser-plugins.js | 15 +++++++--- .../general/browser_pluginnotification.js | 29 ++++++++++++++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/browser/base/content/browser-plugins.js b/browser/base/content/browser-plugins.js index 97f0d772110..cb801ced6b1 100644 --- a/browser/base/content/browser-plugins.js +++ b/browser/base/content/browser-plugins.js @@ -903,14 +903,21 @@ var gPluginHandler = { let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); for (let plugin of cwu.plugins) { - let fallbackType = plugin.pluginFallbackType; - if (fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY) { - continue; - } let info = this._getPluginInfo(plugin); if (!actions.has(info.permissionString)) { continue; } + let fallbackType = info.fallbackType; + if (fallbackType == Ci.nsIObjectLoadingContent.PLUGIN_ACTIVE) { + actions.delete(info.permissionString); + if (actions.size == 0) { + break; + } + continue; + } + if (fallbackType != Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY) { + continue; + } let overlay = this.getPluginUI(plugin, "main"); if (!overlay) { continue; diff --git a/browser/base/content/test/general/browser_pluginnotification.js b/browser/base/content/test/general/browser_pluginnotification.js index 6ab0a561ed9..079ac754211 100644 --- a/browser/base/content/test/general/browser_pluginnotification.js +++ b/browser/base/content/test/general/browser_pluginnotification.js @@ -844,5 +844,32 @@ function test25() { ok(notification, "Test 25: There should be a plugin notification even if the plugin was immediately removed"); ok(notification.dismissed, "Test 25: The notification should be dismissed by default"); - finishTest(); + prepareTest(() => executeSoon(test26), gTestRoot + "plugin_small.html"); +} + +function test26() { + let notification = PopupNotifications.getNotification("click-to-play-plugins"); + ok(notification, "Test 26: There should be a plugin notification"); + + waitForCondition(() => gBrowser.ownerDocument. + getElementById("plugins-notification-icon").classList. + contains("plugin-hidden"), + () => { + // Don't use setTestPluginEnabledState here because we already saved the + // prior value + getTestPlugin().enabledState = Ci.nsIPluginTag.STATE_ENABLED; + prepareTest(test27, gTestRoot + "plugin_small.html"); + }, + "Test 26, expected the plugin notification icon to be highlighted"); +} + +function test27() { + let notification = PopupNotifications.getNotification("click-to-play-plugins"); + ok(notification, "Test 27: There should be a plugin notification"); + + waitForCondition(() => !gBrowser.ownerDocument. + getElementById("plugins-notification-icon").classList. + contains("plugin-hidden"), + finishTest, + "Test 27, expected the plugin notification icon to not be highlighted"); } From 35ba8812bc48f73be494be136503d3f73f04eb8d Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Tue, 5 Nov 2013 17:01:37 -0500 Subject: [PATCH 37/53] Bug 934233 - Use nsLayoutUtils::FindContentFor instead of nsDOMWindowUtils::FindElementWithViewId. r=jimm --- widget/windows/winrt/APZController.cpp | 48 +++++++------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/widget/windows/winrt/APZController.cpp b/widget/windows/winrt/APZController.cpp index 8853471d0b7..60a6f0eb249 100644 --- a/widget/windows/winrt/APZController.cpp +++ b/widget/windows/winrt/APZController.cpp @@ -16,6 +16,7 @@ #include "mozilla/dom/Element.h" #include "nsIDOMWindowUtils.h" #include "nsIInterfaceRequestorUtils.h" +#include "nsLayoutUtils.h" //#define DEBUG_CONTROLLER 1 @@ -49,31 +50,16 @@ IsTab(nsCOMPtr& aSubDocument) * Returns the sub document associated with the scroll id. */ static bool -GetDOMTargets(nsIPresShell* aPresShell, uint64_t aScrollId, +GetDOMTargets(uint64_t aScrollId, nsCOMPtr& aSubDocument, - nsCOMPtr& aTargetElement) + nsCOMPtr& aTargetContent) { - MOZ_ASSERT(aPresShell); - nsRefPtr rootDocument = aPresShell->GetDocument(); - if (!rootDocument) { - return false; - } - nsCOMPtr rootUtils; - nsCOMPtr rootWindow = rootDocument->GetDefaultView(); - if (!rootWindow) { - return false; - } - rootUtils = do_GetInterface(rootWindow); - if (!rootUtils) { - return false; - } - // For tabs and subframes this will return the HTML sub document - rootUtils->FindElementWithViewId(aScrollId, getter_AddRefs(aTargetElement)); - if (!aTargetElement) { + aTargetContent = nsLayoutUtils::FindContentFor(aScrollId); + if (!aTargetContent) { return false; } - nsCOMPtr domElement = do_QueryInterface(aTargetElement); + nsCOMPtr domElement = do_QueryInterface(aTargetContent); if (!domElement) { return false; } @@ -87,7 +73,7 @@ GetDOMTargets(nsIPresShell* aPresShell, uint64_t aScrollId, // If the root element equals domElement, FindElementWithViewId found // a document, vs. an element within a document. if (aSubDocument->GetRootElement() == domElement && IsTab(aSubDocument)) { - aTargetElement = nullptr; + aTargetContent = nullptr; } return true; @@ -116,28 +102,20 @@ public: mFrameMetrics.mScrollOffset.y); #endif - nsIPresShell* presShell = mWidgetListener->GetPresShell(); - if (!presShell) { - return NS_OK; - } - nsCOMPtr subDocument; - nsCOMPtr targetElement; - if (!GetDOMTargets(presShell, mFrameMetrics.mScrollId, - subDocument, targetElement)) { + nsCOMPtr targetContent; + if (!GetDOMTargets(mFrameMetrics.mScrollId, + subDocument, targetContent)) { return NS_OK; } // If we're dealing with a sub frame or content editable element, // call UpdateSubFrame. - if (targetElement) { + if (targetContent) { #ifdef DEBUG_CONTROLLER WinUtils::Log("APZController: detected subframe or content editable"); #endif - nsCOMPtr content = do_QueryInterface(targetElement); - if (content) { - APZCCallbackHelper::UpdateSubFrame(content, mFrameMetrics); - } + APZCCallbackHelper::UpdateSubFrame(targetContent, mFrameMetrics); return NS_OK; } @@ -274,4 +252,4 @@ APZController::HandlePanEnd() MetroUtils::FireObserver("apzc-handle-pan-end", L""); } -} } } \ No newline at end of file +} } } From 7d3a0058e04e1c50ae24fbec4515cfc820a5a418 Mon Sep 17 00:00:00 2001 From: Margaret Leibovic Date: Tue, 5 Nov 2013 15:24:21 -0800 Subject: [PATCH 38/53] Bug 934678 - Write test for Home.banner API. r=wesj --- mobile/android/base/tests/robocop.ini | 1 + .../roboextender/robocop_home_banner.html | 38 +++++++++++++++++++ .../android/base/tests/testHomeBanner.java.in | 38 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 mobile/android/base/tests/roboextender/robocop_home_banner.html create mode 100644 mobile/android/base/tests/testHomeBanner.java.in diff --git a/mobile/android/base/tests/robocop.ini b/mobile/android/base/tests/robocop.ini index cf15e78977b..7b825e30681 100644 --- a/mobile/android/base/tests/robocop.ini +++ b/mobile/android/base/tests/robocop.ini @@ -57,6 +57,7 @@ skip-if = processor == "x86" [testPrivateBrowsing] [testReaderMode] [testGetUserMedia] +[testHomeBanner] # Used for Talos, please don't use in mochitest #[testPan] diff --git a/mobile/android/base/tests/roboextender/robocop_home_banner.html b/mobile/android/base/tests/roboextender/robocop_home_banner.html new file mode 100644 index 00000000000..9ddaff91bfd --- /dev/null +++ b/mobile/android/base/tests/roboextender/robocop_home_banner.html @@ -0,0 +1,38 @@ + + + HomeBanner test page + + + + + + + diff --git a/mobile/android/base/tests/testHomeBanner.java.in b/mobile/android/base/tests/testHomeBanner.java.in new file mode 100644 index 00000000000..1bc94f6e109 --- /dev/null +++ b/mobile/android/base/tests/testHomeBanner.java.in @@ -0,0 +1,38 @@ +#filter substitution +package @ANDROID_PACKAGE_NAME@.tests; + +import @ANDROID_PACKAGE_NAME@.*; + +public class testHomeBanner extends BaseTest { + + private static final String TEST_URL = "chrome://roboextender/content/robocop_home_banner.html"; + private static final String TEXT = "The quick brown fox jumps over the lazy dog."; + + @Override + protected int getTestType() { + return TEST_MOCHITEST; + } + + public void testHomeBanner() { + blockForGeckoReady(); + + Actions.EventExpecter eventExpecter = mActions.expectGeckoEvent("TestHomeBanner:MessageAdded"); + + // Add a message to the home banner + inputAndLoadUrl(TEST_URL + "#addMessage"); + eventExpecter.blockForEvent(); + + // Load about:home, and test to make sure the onshown handler is called + eventExpecter = mActions.expectGeckoEvent("TestHomeBanner:MessageShown"); + inputAndLoadUrl("about:home"); + eventExpecter.blockForEvent(); + + // Verify that the correct message text showed up in the banner + mAsserter.ok(waitForText(TEXT), "banner text", "correct text appeared in the home banner"); + + // Test to make sure the onclick handler is called + eventExpecter = mActions.expectGeckoEvent("TestHomeBanner:MessageClicked"); + mSolo.clickOnText(TEXT); + eventExpecter.blockForEvent(); + } +} From 134bd32f1592733180ea297378558b358e0c4b65 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 5 Nov 2013 15:29:41 -0800 Subject: [PATCH 39/53] Bug 934744 - Support inspector and style editor in the chrome window [r=ally] --- browser/metro/base/content/browser-ui.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/browser/metro/base/content/browser-ui.js b/browser/metro/base/content/browser-ui.js index 52eaa528303..daa97f36c59 100644 --- a/browser/metro/base/content/browser-ui.js +++ b/browser/metro/base/content/browser-ui.js @@ -194,6 +194,10 @@ var BrowserUI = { DebuggerServer.init(); DebuggerServer.addBrowserActors(); DebuggerServer.addActors('chrome://browser/content/dbg-metro-actors.js'); + + // Add these globally for chrome, until per-window chrome debugging is supported (bug 928018): + DebuggerServer.addGlobalActor(DebuggerServer.tabActorFactories.inspectorActor, "inspectorActor"); + DebuggerServer.addGlobalActor(DebuggerServer.tabActorFactories.styleEditorActor, "styleEditorActor"); } DebuggerServer.openListener(port); }, From c537b6a6e9b3aaadc543d00c06a18ac2d7beb8c4 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 5 Nov 2013 15:29:51 -0800 Subject: [PATCH 40/53] Bug 934744 - Add some default prefs for devtools in metro.js [r=ally] --- browser/metro/profile/metro.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/browser/metro/profile/metro.js b/browser/metro/profile/metro.js index d860d48099a..965877ba36e 100644 --- a/browser/metro/profile/metro.js +++ b/browser/metro/profile/metro.js @@ -9,6 +9,10 @@ pref("nglayout.debug.disable_xul_cache", true); pref("nglayout.debug.disable_xul_fastload", true); pref("devtools.errorconsole.enabled", true); +pref("devtools.chrome.enabled", true); +#else +pref("devtools.errorconsole.enabled", false); +pref("devtools.chrome.enabled", false); #endif // Automatically submit crash reports @@ -383,9 +387,6 @@ pref("privacy.sanitize.migrateFx3Prefs", false); pref("geo.enabled", true); pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%"); -// JS error console -pref("devtools.errorconsole.enabled", false); - // snapped view pref("browser.ui.snapped.maxWidth", 600); From 04a57463baff21bc173fa058ec266926d2264839 Mon Sep 17 00:00:00 2001 From: Mark Hammond Date: Wed, 6 Nov 2013 11:18:45 +1100 Subject: [PATCH 41/53] Bug 932147 - Move remaining tests in browser/base/content/test/general/Makefile.in to manifest files. r=jhammel --- browser/base/content/test/general/Makefile.in | 66 ------------------- browser/base/content/test/general/browser.ini | 29 ++++++++ .../base/content/test/general/mochitest.ini | 8 +++ 3 files changed, 37 insertions(+), 66 deletions(-) delete mode 100644 browser/base/content/test/general/Makefile.in diff --git a/browser/base/content/test/general/Makefile.in b/browser/base/content/test/general/Makefile.in deleted file mode 100644 index 3d2a79a8ad7..00000000000 --- a/browser/base/content/test/general/Makefile.in +++ /dev/null @@ -1,66 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -# test_contextmenu.html and test_contextmenu_input are disabled on Linux due to bug 513558 -ifndef MOZ_WIDGET_GTK -MOCHITEST_FILES += \ - audio.ogg \ - privateBrowsingMode.js \ - subtst_contextmenu.html \ - contextmenu_common.js \ - test_contextmenu.html \ - test_contextmenu_input.html \ - $(NULL) -endif - -# The following tests are disabled because they are unreliable: -# browser_bug423833.js is bug 428712 -# browser_sanitize-download-history.js is bug 432425 -# -# browser_sanitizeDialog_treeView.js is disabled until the tree view is added -# back to the clear recent history dialog (sanitize.xul), if it ever is (bug -# 480169) - -# browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638. - -# browser_bug321000.js is disabled because newline handling is shaky (bug 592528) - -# Disable tests on Windows due to frequent failures (bugs 825739, 841341) -ifneq (windows,$(MOZ_WIDGET_TOOLKIT)) -MOCHITEST_BROWSER_FILES += \ - browser_bookmark_titles.js \ - browser_popupNotification.js \ - $(NULL) -endif - -ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT)) -MOCHITEST_BROWSER_FILES += \ - browser_bug462289.js \ - $(NULL) -else -MOCHITEST_BROWSER_FILES += \ - browser_bug565667.js \ - $(NULL) -endif - -ifdef MOZ_DATA_REPORTING -MOCHITEST_BROWSER_FILES += \ - browser_datareporting_notification.js \ - $(NULL) -endif - -ifdef MOZ_CRASHREPORTER -MOCHITEST_BROWSER_FILES += \ - browser_pluginCrashCommentAndURL.js \ - pluginCrashCommentAndURL.html \ - browser_CTP_crashreporting.js \ - $(NULL) -endif - -# browser_CTP_context_menu.js fails intermittently on Linux (bug 909342) -ifndef MOZ_WIDGET_GTK -MOCHITEST_BROWSER_FILES += \ - browser_CTP_context_menu.js \ - $(NULL) -endif diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index 8796d3dbf2b..ccff34245ca 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -67,6 +67,7 @@ support-files = plugin_test3.html plugin_two_types.html plugin_unknown.html + pluginCrashCommentAndURL.html print_postdata.sjs redirect_bug623155.sjs test-mixedcontent-securityerrors.html @@ -85,6 +86,10 @@ support-files = test_no_mcb_on_http_site_font2.html test_no_mcb_on_http_site_font2.css +[browser_CTP_context_menu.js] +skip-if = toolkit == "gtk2" || toolkit == "gtk3" # browser_CTP_context_menu.js fails intermittently on Linux (bug 909342) +[browser_CTP_crashreporting.js] +run-if = crashreporter [browser_CTP_data_urls.js] [browser_CTP_drag_drop.js] [browser_CTP_nonplugins.js] @@ -99,7 +104,11 @@ support-files = [browser_addon_bar_shortcut.js] [browser_alltabslistener.js] [browser_blob-channelname.js] +[browser_bookmark_titles.js] +skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341) [browser_bug304198.js] +[browser_bug321000.js] +skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528) [browser_bug329212.js] [browser_bug356571.js] [browser_bug380960.js] @@ -113,6 +122,8 @@ support-files = [browser_bug417483.js] [browser_bug419612.js] [browser_bug422590.js] +[browser_bug423833.js] +skip-if = true # bug 428712 [browser_bug424101.js] [browser_bug427559.js] [browser_bug432599.js] @@ -121,6 +132,8 @@ support-files = [browser_bug441778.js] [browser_bug455852.js] [browser_bug460146.js] +[browser_bug462289.js] +skip-if = toolkit == "cocoa" [browser_bug462673.js] [browser_bug477014.js] [browser_bug479408.js] @@ -147,6 +160,8 @@ support-files = [browser_bug562649.js] [browser_bug563588.js] [browser_bug565575.js] +[browser_bug565667.js] +run-if = toolkit == "cocoa" [browser_bug567306.js] [browser_bug575561.js] [browser_bug575830.js] @@ -218,9 +233,13 @@ support-files = [browser_ctrlTab.js] [browser_customize.js] [browser_customize_popupNotification.js] +[browser_datareporting_notification.js] +run-if = datareporting [browser_disablechrome.js] [browser_discovery.js] [browser_duplicateIDs.js] +[browser_drag.js] +skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638. [browser_findbarClose.js] [browser_fullscreen-window-open.js] [browser_gestureSupport.js] @@ -247,16 +266,26 @@ support-files = [browser_pluginnotification.js] [browser_pluginplaypreview.js] [browser_pluginplaypreview2.js] +[browser_pluginCrashCommentAndURL.js] +run-if = crashreporter [browser_plugins_added_dynamically.js] +[browser_popupNotification.js] +skip-if = toolkit == "windows" # Disabled on Windows due to frequent failures (bugs 825739, 841341) [browser_popupUI.js] [browser_private_browsing_window.js] [browser_private_no_prompt.js] [browser_relatedTabs.js] [browser_removeTabsToTheEnd.js] +[browser_sanitize-download-history.js] +skip-if = true # bug 432425 [browser_sanitize-passwordDisabledHosts.js] [browser_sanitize-sitepermissions.js] [browser_sanitize-timespans.js] [browser_sanitizeDialog.js] +[browser_sanitizeDialog_treeView.js] +skip-if = true # disabled until the tree view is added + # back to the clear recent history dialog (sanitize.xul), if + # it ever is (bug 480169) [browser_save_link-perwindowpb.js] [browser_save_private_link_perwindowpb.js] [browser_save_video.js] diff --git a/browser/base/content/test/general/mochitest.ini b/browser/base/content/test/general/mochitest.ini index 115228c86d3..7e16bb61a19 100644 --- a/browser/base/content/test/general/mochitest.ini +++ b/browser/base/content/test/general/mochitest.ini @@ -1,8 +1,10 @@ [DEFAULT] support-files = + audio.ogg bug364677-data.xml bug364677-data.xml^headers^ bug395533-data.txt + contextmenu_common.js ctxmenu-image.png feed_discovery.html gZipOfflineChild.cacheManifest @@ -20,10 +22,16 @@ support-files = offlineEvent.cacheManifest offlineEvent.cacheManifest^headers^ offlineEvent.html + privateBrowsingMode.js + subtst_contextmenu.html video.ogg [test_bug364677.html] [test_bug395533.html] +[test_contextmenu.html] +skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558 +[test_contextmenu_input.html] +skip-if = toolkit == "gtk2" || toolkit == "gtk3" # disabled on Linux due to bug 513558 [test_feed_discovery.html] [test_offlineNotification.html] [test_offline_gzip.html] From 9b55dd9557db717b0458b852d77548121e080881 Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Tue, 5 Nov 2013 17:57:04 -0800 Subject: [PATCH 42/53] Bug 935144 - Don't log so much about bindView short-circuiting. r=margaret --- mobile/android/base/home/TopSitesPage.java | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/mobile/android/base/home/TopSitesPage.java b/mobile/android/base/home/TopSitesPage.java index f1c9fb492f7..85a538f0c84 100644 --- a/mobile/android/base/home/TopSitesPage.java +++ b/mobile/android/base/home/TopSitesPage.java @@ -120,6 +120,21 @@ public class TopSitesPage extends HomeFragment { mUrlOpenListener = null; } + private static boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG); + private static boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE); + + private static void debug(final String message) { + if (logDebug) { + Log.d(LOGTAG, message); + } + } + + private static void trace(final String message) { + if (logVerbose) { + Log.v(LOGTAG, message); + } + } + @Override public void onAttach(Activity activity) { super.onAttach(activity); @@ -480,7 +495,7 @@ public class TopSitesPage extends HomeFragment { @Override public Cursor loadCursor() { - Log.d(LOGTAG, "TopSitesLoader.loadCursor()"); + trace("TopSitesLoader.loadCursor()"); return BrowserDB.getTopSites(getContext().getContentResolver(), mMaxGridEntries, SEARCH_LIMIT); } } @@ -583,7 +598,7 @@ public class TopSitesPage extends HomeFragment { // sooner than this. But we can avoid a duplicate favicon // fetch... if (!updated) { - Log.d(LOGTAG, "bindView called twice for same values; short-circuiting."); + debug("bindView called twice for same values; short-circuiting."); return; } @@ -629,7 +644,7 @@ public class TopSitesPage extends HomeFragment { private class CursorLoaderCallbacks implements LoaderCallbacks { @Override public Loader onCreateLoader(int id, Bundle args) { - Log.d(LOGTAG, "Creating TopSitesLoader: " + id); + trace("Creating TopSitesLoader: " + id); return new TopSitesLoader(getActivity()); } @@ -645,7 +660,7 @@ public class TopSitesPage extends HomeFragment { */ @Override public void onLoadFinished(Loader loader, Cursor c) { - Log.d(LOGTAG, "onLoadFinished: " + c.getCount() + " rows."); + debug("onLoadFinished: " + c.getCount() + " rows."); mListAdapter.swapCursor(c); mGridAdapter.swapCursor(c); From 6b679db257c1dab036204f848f8462614348dcde Mon Sep 17 00:00:00 2001 From: Richard Newman Date: Tue, 5 Nov 2013 17:57:04 -0800 Subject: [PATCH 43/53] Bug 935157 - Correctly cache favicons by favicon URL, not page URL, and don't log page URLs on failure. r=margaret --- mobile/android/base/favicons/cache/FaviconCache.java | 3 ++- mobile/android/base/home/TwoLinePageRow.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mobile/android/base/favicons/cache/FaviconCache.java b/mobile/android/base/favicons/cache/FaviconCache.java index eefa78063b8..6548b1820d0 100644 --- a/mobile/android/base/favicons/cache/FaviconCache.java +++ b/mobile/android/base/favicons/cache/FaviconCache.java @@ -433,7 +433,8 @@ public class FaviconCache { try { if (!mBackingMap.containsKey(key)) { - Log.w(LOGTAG, "Cannot compute dominant color of non-cached favicon " + key); + Log.w(LOGTAG, "Cannot compute dominant color of non-cached favicon. Cache fullness " + + mCurrentSize.get() + '/' + mMaxSizeBytes); finishRead(); return 0xFFFFFF; } diff --git a/mobile/android/base/home/TwoLinePageRow.java b/mobile/android/base/home/TwoLinePageRow.java index bf47634cf77..754df904f0c 100644 --- a/mobile/android/base/home/TwoLinePageRow.java +++ b/mobile/android/base/home/TwoLinePageRow.java @@ -62,7 +62,7 @@ public class TwoLinePageRow extends LinearLayout return; } - v.updateImage(favicon, url); + v.updateImage(favicon, faviconURL); } } From 082a95b42c239af5565f1b8e10002c3a5b736b7a Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 5 Nov 2013 20:24:17 -0800 Subject: [PATCH 44/53] Bug 930141 - Replace escodegen with pretty-fast in the debugger and scratchpad pretty printing backend; r=gps,dcamp,past,benvie --- .../test/browser_dbg_pretty-print-08.js | 3 +- .../test/browser_dbg_pretty-print-09.js | 3 +- browser/devtools/scratchpad/scratchpad.js | 68 +- browser/devtools/scratchpad/test/browser.ini | 5 +- .../test/browser_scratchpad_pprint-02.js | 22 +- .../test/browser_scratchpad_pprint.js | 11 +- toolkit/devtools/Loader.jsm | 13 +- toolkit/devtools/acorn/moz.build | 2 +- .../acorn/tests/unit/test_import_acorn.js | 4 +- .../acorn/tests/unit/test_lenient_parser.js | 2 +- .../acorn/tests/unit/test_same_ast.js | 2 +- toolkit/devtools/escodegen/LICENSE.BSD | 19 - toolkit/devtools/escodegen/UPGRADING.md | 54 - toolkit/devtools/escodegen/escodegen.js | 2065 ------ .../devtools/escodegen/escodegen.worker.js | 5539 ----------------- toolkit/devtools/escodegen/estraverse.js | 678 -- toolkit/devtools/escodegen/package.json.js | 57 - .../tests/unit/test_generate_source_maps.js | 71 - .../tests/unit/test_import_escodegen.js | 11 - .../escodegen/tests/unit/test_same_ast.js | 76 - .../escodegen/tests/unit/xpcshell.ini | 7 - toolkit/devtools/moz.build | 4 +- toolkit/devtools/pretty-fast/UPGRADING.md | 7 + .../{escodegen => pretty-fast}/moz.build | 7 +- toolkit/devtools/pretty-fast/pretty-fast.js | 781 +++ .../tests/unit/head_pretty-fast.js} | 7 +- .../devtools/pretty-fast/tests/unit/test.js | 470 ++ .../pretty-fast/tests/unit/xpcshell.ini | 5 + .../server/actors/pretty-print-worker.js | 27 +- toolkit/devtools/server/actors/script.js | 16 +- toolkit/devtools/server/main.js | 1 - toolkit/devtools/sourcemap/Makefile.in | 1 + toolkit/devtools/sourcemap/source-map.js | 1929 ++++++ 33 files changed, 3311 insertions(+), 8656 deletions(-) delete mode 100644 toolkit/devtools/escodegen/LICENSE.BSD delete mode 100644 toolkit/devtools/escodegen/UPGRADING.md delete mode 100644 toolkit/devtools/escodegen/escodegen.js delete mode 100644 toolkit/devtools/escodegen/escodegen.worker.js delete mode 100644 toolkit/devtools/escodegen/estraverse.js delete mode 100644 toolkit/devtools/escodegen/package.json.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/test_same_ast.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/xpcshell.ini create mode 100644 toolkit/devtools/pretty-fast/UPGRADING.md rename toolkit/devtools/{escodegen => pretty-fast}/moz.build (73%) create mode 100644 toolkit/devtools/pretty-fast/pretty-fast.js rename toolkit/devtools/{escodegen/tests/unit/head_escodegen.js => pretty-fast/tests/unit/head_pretty-fast.js} (82%) create mode 100644 toolkit/devtools/pretty-fast/tests/unit/test.js create mode 100644 toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini create mode 100644 toolkit/devtools/sourcemap/source-map.js diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js index 6985c72615a..8466ddf6f79 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js @@ -80,10 +80,9 @@ function testStepping() { function testHitBreakpoint() { gClient.addOneTimeListener("paused", (event, { why, frame }) => { is(why.type, "breakpoint"); - const { url, line, column } = frame.where; + const { url, line } = frame.where; is(url, CODE_URL); is(line, BP_LOCATION.line); - is(column, BP_LOCATION.column); resumeDebuggerThenCloseAndFinish(gPanel); }); diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js index 07bdeb2fa81..952f8a92f05 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js @@ -55,10 +55,9 @@ function runCode({ error }) { function testDbgStatement(event, { frame, why }) { is(why.type, "debuggerStatement"); - const { url, line, column } = frame.where; + const { url, line } = frame.where; is(url, B_URL); is(line, 2); - is(column, 2); disablePrettyPrint(); } diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index 48780058ece..c139c362007 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -34,7 +34,6 @@ const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesV const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const promise = require("sdk/core/promise"); const Telemetry = require("devtools/shared/telemetry"); -const escodegen = require("escodegen/escodegen"); const Editor = require("devtools/sourceeditor/editor"); const TargetFactory = require("devtools/framework/target").TargetFactory; @@ -516,25 +515,61 @@ var Scratchpad = { return deferred.promise; }, + _prettyPrintWorker: null, + + /** + * Get or create the worker that handles pretty printing. + */ + get prettyPrintWorker() { + if (!this._prettyPrintWorker) { + this._prettyPrintWorker = new ChromeWorker( + "resource://gre/modules/devtools/server/actors/pretty-print-worker.js"); + + this._prettyPrintWorker.addEventListener("error", ({ message, filename, lineno }) => { + DevToolsUtils.reportException(message + " @ " + filename + ":" + lineno); + }, false); + } + return this._prettyPrintWorker; + }, + /** * Pretty print the source text inside the scratchpad. + * + * @return Promise + * A promise resolved with the pretty printed code, or rejected with + * an error. */ prettyPrint: function SP_prettyPrint() { const uglyText = this.getText(); const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); - try { - const ast = Reflect.parse(uglyText); - const prettyText = escodegen.generate(ast, { - format: { - indent: { - style: " ".repeat(tabsize) - } - } - }); - this.editor.setText(prettyText); - } catch (e) { - this.writeAsErrorComment(DevToolsUtils.safeErrorString(e)); - } + const id = Math.random(); + const deferred = promise.defer(); + + const onReply = ({ data }) => { + if (data.id !== id) { + return; + } + this.prettyPrintWorker.removeEventListener("message", onReply, false); + + if (data.error) { + let errorString = DevToolsUtils.safeErrorString(data.error); + this.writeAsErrorComment(errorString); + deferred.reject(errorString); + } else { + this.editor.setText(data.code); + deferred.resolve(data.code); + } + }; + + this.prettyPrintWorker.addEventListener("message", onReply, false); + this.prettyPrintWorker.postMessage({ + id: id, + url: "(scratchpad)", + indent: tabsize, + source: uglyText + }); + + return deferred.promise; }, /** @@ -1375,6 +1410,11 @@ var Scratchpad = { this._sidebar = null; } + if (this._prettyPrintWorker) { + this._prettyPrintWorker.terminate(); + this._prettyPrintWorker = null; + } + scratchpadTargets = null; this.webConsoleClient = null; this.debuggerClient = null; diff --git a/browser/devtools/scratchpad/test/browser.ini b/browser/devtools/scratchpad/test/browser.ini index f1b27427250..57e39157a35 100644 --- a/browser/devtools/scratchpad/test/browser.ini +++ b/browser/devtools/scratchpad/test/browser.ini @@ -28,10 +28,9 @@ support-files = head.js [browser_scratchpad_long_string.js] [browser_scratchpad_open.js] [browser_scratchpad_open_error_console.js] -# Disabled, as escodegen is being replaced - bug 930141 -# [browser_scratchpad_pprint-02.js] -# [browser_scratchpad_pprint.js] [browser_scratchpad_throw_output.js] +[browser_scratchpad_pprint-02.js] +[browser_scratchpad_pprint.js] [browser_scratchpad_restore.js] [browser_scratchpad_tab_switch.js] [browser_scratchpad_ui.js] diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js b/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js index 8deffdda943..13a6e91c1cc 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js @@ -15,18 +15,26 @@ function test() content.location = "data:text/html;charset=utf8,test Scratchpad pretty print."; } +let gTabsize; + function runTests(sw) { - const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); + gTabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); Services.prefs.setIntPref("devtools.editor.tabsize", 6); const space = " ".repeat(6); const sp = sw.Scratchpad; sp.setText("function main() { console.log(5); }"); - sp.prettyPrint(); - const prettyText = sp.getText(); - ok(prettyText.contains(space)); - - Services.prefs.setIntPref("devtools.editor.tabsize", tabsize); - finish(); + sp.prettyPrint().then(() => { + const prettyText = sp.getText(); + ok(prettyText.contains(space)); + finish(); + }).then(null, error => { + ok(false, error); + }); } + +registerCleanupFunction(function () { + Services.prefs.setIntPref("devtools.editor.tabsize", gTabsize); + gTabsize = null; +}); diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js b/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js index 9b5a6b3d243..d8ff7039d41 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js @@ -19,8 +19,11 @@ function runTests(sw) { const sp = sw.Scratchpad; sp.setText("function main() { console.log(5); }"); - sp.prettyPrint(); - const prettyText = sp.getText(); - ok(prettyText.contains("\n")); - finish(); + sp.prettyPrint().then(() => { + const prettyText = sp.getText(); + ok(prettyText.contains("\n")); + finish(); + }).then(null, error => { + ok(false, error); + }); } diff --git a/toolkit/devtools/Loader.jsm b/toolkit/devtools/Loader.jsm index 6b68aeae508..a8fbef92a96 100644 --- a/toolkit/devtools/Loader.jsm +++ b/toolkit/devtools/Loader.jsm @@ -64,10 +64,10 @@ var BuiltinProvider = { "devtools/output-parser": "resource://gre/modules/devtools/output-parser", "devtools/touch-events": "resource://gre/modules/devtools/touch-events", "devtools/client": "resource://gre/modules/devtools/client", + "devtools/pretty-fast": "resource://gre/modules/devtools/pretty-fast.js", - "acorn": "resource://gre/modules/devtools/acorn", - "escodegen": "resource://gre/modules/devtools/escodegen", - "estraverse": "resource://gre/modules/devtools/escodegen/estraverse", + "acorn": "resource://gre/modules/devtools/acorn.js", + "acorn_loose": "resource://gre/modules/devtools/acorn_loose.js", // Allow access to xpcshell test items from the loader. "xpcshell-test": "resource://test" @@ -109,9 +109,8 @@ var SrcdirProvider = { let outputParserURI = this.fileURI(OS.Path.join(toolkitDir, "output-parser")); let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events")); let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client")); + let prettyFastURI = this.fileURI(OS.Path.join(toolkitDir), "pretty-fast.js"); let acornURI = this.fileURI(OS.Path.join(toolkitDir, "acorn")); - let escodegenURI = this.fileURI(OS.Path.join(toolkitDir, "escodegen")); - let estraverseURI = this.fileURI(OS.Path.join(toolkitDir, "escodegen", "estraverse")); this.loader = new loader.Loader({ modules: { "toolkit/loader": loader, @@ -129,9 +128,9 @@ var SrcdirProvider = { "devtools/output-parser": outputParserURI, "devtools/touch-events": touchEventsURI, "devtools/client": clientURI, + "devtools/pretty-fast": prettyFastURI, + "acorn": acornURI, - "escodegen": escodegenURI, - "estraverse": estraverseURI }, globals: loaderGlobals }); diff --git a/toolkit/devtools/acorn/moz.build b/toolkit/devtools/acorn/moz.build index 1eafb9bc925..8f3524f7d23 100644 --- a/toolkit/devtools/acorn/moz.build +++ b/toolkit/devtools/acorn/moz.build @@ -6,7 +6,7 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] -JS_MODULES_PATH = 'modules/devtools/acorn' +JS_MODULES_PATH = 'modules/devtools' EXTRA_JS_MODULES += [ 'acorn.js', diff --git a/toolkit/devtools/acorn/tests/unit/test_import_acorn.js b/toolkit/devtools/acorn/tests/unit/test_import_acorn.js index d9d72ef2684..969893f36c2 100644 --- a/toolkit/devtools/acorn/tests/unit/test_import_acorn.js +++ b/toolkit/devtools/acorn/tests/unit/test_import_acorn.js @@ -6,8 +6,8 @@ */ function run_test() { - const acorn = require("acorn/acorn"); - const acorn_loose = require("acorn/acorn_loose"); + const acorn = require("acorn"); + const acorn_loose = require("acorn_loose"); do_check_true(isObject(acorn)); do_check_true(isObject(acorn_loose)); do_check_eq(typeof acorn.parse, "function"); diff --git a/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js b/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js index 794918b6357..e72aac0f5c3 100644 --- a/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js +++ b/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js @@ -5,7 +5,7 @@ * Test that acorn's lenient parser gives something usable. */ -const acorn_loose = require("acorn/acorn_loose"); +const acorn_loose = require("acorn_loose"); function run_test() { let actualAST = acorn_loose.parse_dammit("let x = 10"); diff --git a/toolkit/devtools/acorn/tests/unit/test_same_ast.js b/toolkit/devtools/acorn/tests/unit/test_same_ast.js index ce2de6076d7..d01916d7abb 100644 --- a/toolkit/devtools/acorn/tests/unit/test_same_ast.js +++ b/toolkit/devtools/acorn/tests/unit/test_same_ast.js @@ -5,7 +5,7 @@ * Test that Reflect and acorn create the same AST for ES5. */ -const acorn = require("acorn/acorn"); +const acorn = require("acorn"); Cu.import("resource://gre/modules/reflect.jsm"); const testCode = "" + function main () { diff --git a/toolkit/devtools/escodegen/LICENSE.BSD b/toolkit/devtools/escodegen/LICENSE.BSD deleted file mode 100644 index 3e580c355a9..00000000000 --- a/toolkit/devtools/escodegen/LICENSE.BSD +++ /dev/null @@ -1,19 +0,0 @@ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/toolkit/devtools/escodegen/UPGRADING.md b/toolkit/devtools/escodegen/UPGRADING.md deleted file mode 100644 index bf8d2882d67..00000000000 --- a/toolkit/devtools/escodegen/UPGRADING.md +++ /dev/null @@ -1,54 +0,0 @@ -Assuming that escodegen's dependencies have not changed, to upgrade our tree's -escodegen to a new version: - -1. Clone the escodegen repository, and check out the version you want to upgrade -to: - - $ git clone https://github.com/Constellation/escodegen.git - $ cd escodegen - $ git checkout - -2. Make sure that all tests pass: - - $ npm install . - $ npm test - - If there are any test failures, do not upgrade to that version of escodegen! - -3. Copy escodegen.js to our tree: - - $ cp escodegen.js /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.js - -4. Copy the package.json to our tree, and append ".js" to make it work with our -loader: - - $ cp package.json /path/to/mozilla-central/toolkit/devtools/escodegen/package.json.js - -5. Prepend `module.exports = ` to the package.json file contents, so that the -JSON data is exported, and we can load package.json as a module. - - Bug 933482: Note, this is a workaround for Bug 910594, which will allow the SDK loader to require JSON files. To remove ambiguity, comment out the `require('./package.json').version` line in `escodegen.js` so that when Bug 910594 is uplifted into central, it does not attempt to look for `package.json`, rather than `package.json.js`. This is a temporary workaround, and once Bug 933500 is solved, either `package.json` or `package.json.js` will work. - -6. Copy the estraverse.js that escodegen depends on into our tree: - - $ cp node_modules/estraverse/estraverse.js /path/to/mozilla-central/devtools/escodegen/estraverse.js - -7. Build the version of the escodegen that we can use in workers: - - First we need to alias `self` as `window`: - - $ echo 'let window = self;' >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js - - Then we need to add the browser build of the source map library: - - $ git clone https://github.com/mozilla/source-map - $ cd source-map - $ git co - $ npm run-script build - $ cat dist/source-map.js >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js - - Then we need to build the browser version of escodegen: - - $ cd /path/to/escodegen - $ npm run-script build - $ cat escodegen.browser.js >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js diff --git a/toolkit/devtools/escodegen/escodegen.js b/toolkit/devtools/escodegen/escodegen.js deleted file mode 100644 index 41b32286431..00000000000 --- a/toolkit/devtools/escodegen/escodegen.js +++ /dev/null @@ -1,2065 +0,0 @@ -/* - Copyright (C) 2012-2013 Yusuke Suzuki - Copyright (C) 2012-2013 Michael Ficarra - Copyright (C) 2012-2013 Mathias Bynens - Copyright (C) 2013 Irakli Gozalishvili - Copyright (C) 2012 Robert Gust-Bardon - Copyright (C) 2012 John Freeman - Copyright (C) 2011-2012 Ariya Hidayat - Copyright (C) 2012 Joost-Wim Boekesteijn - Copyright (C) 2012 Kris Kowal - Copyright (C) 2012 Arpad Borsos - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/*jslint bitwise:true */ -/*global exports:true, generateStatement:true, generateExpression:true, require:true, global:true*/ -(function () { - 'use strict'; - - var Syntax, - Precedence, - BinaryPrecedence, - Regex, - SourceNode, - estraverse, - isArray, - base, - indent, - json, - renumber, - hexadecimal, - quotes, - escapeless, - newline, - space, - parentheses, - semicolons, - safeConcatenation, - directive, - extra, - parse, - sourceMap, - FORMAT_MINIFY, - FORMAT_DEFAULTS; - - estraverse = require('estraverse'); - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ComprehensionBlock: 'ComprehensionBlock', - ComprehensionExpression: 'ComprehensionExpression', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - - }; - - Precedence = { - Sequence: 0, - Assignment: 1, - Conditional: 2, - LogicalOR: 3, - LogicalAND: 4, - BitwiseOR: 5, - BitwiseXOR: 6, - BitwiseAND: 7, - Equality: 8, - Relational: 9, - BitwiseSHIFT: 10, - Additive: 11, - Multiplicative: 12, - Unary: 13, - Postfix: 14, - Call: 15, - New: 16, - Member: 17, - Primary: 18 - }; - - BinaryPrecedence = { - '||': Precedence.LogicalOR, - '&&': Precedence.LogicalAND, - '|': Precedence.BitwiseOR, - '^': Precedence.BitwiseXOR, - '&': Precedence.BitwiseAND, - '==': Precedence.Equality, - '!=': Precedence.Equality, - '===': Precedence.Equality, - '!==': Precedence.Equality, - 'is': Precedence.Equality, - 'isnt': Precedence.Equality, - '<': Precedence.Relational, - '>': Precedence.Relational, - '<=': Precedence.Relational, - '>=': Precedence.Relational, - 'in': Precedence.Relational, - 'instanceof': Precedence.Relational, - '<<': Precedence.BitwiseSHIFT, - '>>': Precedence.BitwiseSHIFT, - '>>>': Precedence.BitwiseSHIFT, - '+': Precedence.Additive, - '-': Precedence.Additive, - '*': Precedence.Multiplicative, - '%': Precedence.Multiplicative, - '/': Precedence.Multiplicative - }; - - Regex = { - 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]') - }; - - function getDefaultOptions() { - // default options - return { - indent: null, - base: null, - parse: null, - comment: false, - format: { - indent: { - style: ' ', - base: 0, - adjustMultilineComment: false - }, - json: false, - renumber: false, - hexadecimal: false, - quotes: 'single', - escapeless: false, - compact: false, - parentheses: true, - semicolons: true, - safeConcatenation: false - }, - moz: { - starlessGenerator: false, - parenthesizedComprehensionBlock: false - }, - sourceMap: null, - sourceMapRoot: null, - sourceMapWithCode: false, - directive: false, - verbatim: null - }; - } - - function stringToArray(str) { - var length = str.length, - result = [], - i; - for (i = 0; i < length; i += 1) { - result[i] = str.charAt(i); - } - return result; - } - - function stringRepeat(str, num) { - var result = ''; - - for (num |= 0; num > 0; num >>>= 1, str += str) { - if (num & 1) { - result += str; - } - } - - return result; - } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - - // Fallback for the non SourceMap environment - function SourceNodeMock(line, column, filename, chunk) { - var result = []; - - function flatten(input) { - var i, iz; - if (isArray(input)) { - for (i = 0, iz = input.length; i < iz; ++i) { - flatten(input[i]); - } - } else if (input instanceof SourceNodeMock) { - result.push(input); - } else if (typeof input === 'string' && input) { - result.push(input); - } - } - - flatten(chunk); - this.children = result; - } - - SourceNodeMock.prototype.toString = function toString() { - var res = '', i, iz, node; - for (i = 0, iz = this.children.length; i < iz; ++i) { - node = this.children[i]; - if (node instanceof SourceNodeMock) { - res += node.toString(); - } else { - res += node; - } - } - return res; - }; - - SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) { - var last = this.children[this.children.length - 1]; - if (last instanceof SourceNodeMock) { - last.replaceRight(pattern, replacement); - } else if (typeof last === 'string') { - this.children[this.children.length - 1] = last.replace(pattern, replacement); - } else { - this.children.push(''.replace(pattern, replacement)); - } - return this; - }; - - SourceNodeMock.prototype.join = function join(sep) { - var i, iz, result; - result = []; - iz = this.children.length; - if (iz > 0) { - for (i = 0, iz -= 1; i < iz; ++i) { - result.push(this.children[i], sep); - } - result.push(this.children[iz]); - this.children = result; - } - return this; - }; - - function hasLineTerminator(str) { - return (/[\r\n]/g).test(str); - } - - function endsWithLineTerminator(str) { - var ch = str.charAt(str.length - 1); - return ch === '\r' || ch === '\n'; - } - - function updateDeeply(target, override) { - var key, val; - - function isHashObject(target) { - return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); - } - - for (key in override) { - if (override.hasOwnProperty(key)) { - val = override[key]; - if (isHashObject(val)) { - if (isHashObject(target[key])) { - updateDeeply(target[key], val); - } else { - target[key] = updateDeeply({}, val); - } - } else { - target[key] = val; - } - } - } - return target; - } - - function generateNumber(value) { - var result, point, temp, exponent, pos; - - if (value !== value) { - throw new Error('Numeric literal whose value is NaN'); - } - if (value < 0 || (value === 0 && 1 / value < 0)) { - throw new Error('Numeric literal whose value is negative'); - } - - if (value === 1 / 0) { - return json ? 'null' : renumber ? '1e400' : '1e+400'; - } - - result = '' + value; - if (!renumber || result.length < 3) { - return result; - } - - point = result.indexOf('.'); - if (!json && result.charAt(0) === '0' && point === 1) { - point = 0; - result = result.slice(1); - } - temp = result; - result = result.replace('e+', 'e'); - exponent = 0; - if ((pos = temp.indexOf('e')) > 0) { - exponent = +temp.slice(pos + 1); - temp = temp.slice(0, pos); - } - if (point >= 0) { - exponent -= temp.length - point - 1; - temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; - } - pos = 0; - while (temp.charAt(temp.length + pos - 1) === '0') { - pos -= 1; - } - if (pos !== 0) { - exponent -= pos; - temp = temp.slice(0, pos); - } - if (exponent !== 0) { - temp += 'e' + exponent; - } - if ((temp.length < result.length || - (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) && - +temp === value) { - result = temp; - } - - return result; - } - - // Generate valid RegExp expression. - // This function is based on https://github.com/Constellation/iv Engine - - function escapeRegExpCharacter(ch, previousIsBackslash) { - // not handling '\' and handling \u2028 or \u2029 to unicode escape sequence - if ((ch & ~1) === 0x2028) { - return (previousIsBackslash ? 'u' : '\\u') + ((ch === 0x2028) ? '2028' : '2029'); - } else if (ch === 10 || ch === 13) { // \n, \r - return (previousIsBackslash ? '' : '\\') + ((ch === 10) ? 'n' : 'r'); - } - return String.fromCharCode(ch); - } - - function generateRegExp(reg) { - var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash; - - result = reg.toString(); - - if (reg.source) { - // extract flag from toString result - match = result.match(/\/([^/]*)$/); - if (!match) { - return result; - } - - flags = match[1]; - result = ''; - - characterInBrack = false; - previousIsBackslash = false; - for (i = 0, iz = reg.source.length; i < iz; ++i) { - ch = reg.source.charCodeAt(i); - - if (!previousIsBackslash) { - if (characterInBrack) { - if (ch === 93) { // ] - characterInBrack = false; - } - } else { - if (ch === 47) { // / - result += '\\'; - } else if (ch === 91) { // [ - characterInBrack = true; - } - } - result += escapeRegExpCharacter(ch, previousIsBackslash); - previousIsBackslash = ch === 92; // \ - } else { - // if new RegExp("\\\n') is provided, create /\n/ - result += escapeRegExpCharacter(ch, previousIsBackslash); - // prevent like /\\[/]/ - previousIsBackslash = false; - } - } - - return '/' + result + '/' + flags; - } - - return result; - } - - function escapeAllowedCharacter(ch, next) { - var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; - - switch (ch) { - case '\b': - result += 'b'; - break; - case '\f': - result += 'f'; - break; - case '\t': - result += 't'; - break; - default: - if (json || code > 0xff) { - result += 'u' + '0000'.slice(hex.length) + hex; - } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) { - result += '0'; - } else if (ch === '\x0B') { // '\v' - result += 'x0B'; - } else { - result += 'x' + '00'.slice(hex.length) + hex; - } - break; - } - - return result; - } - - function escapeDisallowedCharacter(ch) { - var result = '\\'; - switch (ch) { - case '\\': - result += '\\'; - break; - case '\n': - result += 'n'; - break; - case '\r': - result += 'r'; - break; - case '\u2028': - result += 'u2028'; - break; - case '\u2029': - result += 'u2029'; - break; - default: - throw new Error('Incorrectly classified character'); - } - - return result; - } - - function escapeDirective(str) { - var i, iz, ch, buf, quote; - - buf = str; - if (typeof buf[0] === 'undefined') { - buf = stringToArray(buf); - } - - quote = quotes === 'double' ? '"' : '\''; - for (i = 0, iz = buf.length; i < iz; i += 1) { - ch = buf[i]; - if (ch === '\'') { - quote = '"'; - break; - } else if (ch === '"') { - quote = '\''; - break; - } else if (ch === '\\') { - i += 1; - } - } - - return quote + str + quote; - } - - function escapeString(str) { - var result = '', i, len, ch, singleQuotes = 0, doubleQuotes = 0, single; - - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if (ch === '\'') { - singleQuotes += 1; - } else if (ch === '"') { - doubleQuotes += 1; - } else if (ch === '/' && json) { - result += '\\'; - } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { - result += escapeDisallowedCharacter(ch); - continue; - } else if ((json && ch < ' ') || !(json || escapeless || (ch >= ' ' && ch <= '~'))) { - result += escapeAllowedCharacter(ch, str[i + 1]); - continue; - } - result += ch; - } - - single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes)); - str = result; - result = single ? '\'' : '"'; - - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if ((ch === '\'' && single) || (ch === '"' && !single)) { - result += '\\'; - } - result += ch; - } - - return result + (single ? '\'' : '"'); - } - - function isWhiteSpace(ch) { - // Use `\x0B` instead of `\v` for IE < 9 compatibility - return '\t\x0B\f \xa0'.indexOf(ch) >= 0 || (ch.charCodeAt(0) >= 0x1680 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0); - } - - function isLineTerminator(ch) { - return '\n\r\u2028\u2029'.indexOf(ch) >= 0; - } - - 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)); - } - - function toSourceNode(generated, node) { - if (node == null) { - if (generated instanceof SourceNode) { - return generated; - } else { - node = {}; - } - } - if (node.loc == null) { - return new SourceNode(null, null, sourceMap, generated, node.name || null); - } - return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated, node.name || null); - } - - function join(left, right) { - var leftSource = toSourceNode(left).toString(), - rightSource = toSourceNode(right).toString(), - leftChar = leftSource.charAt(leftSource.length - 1), - rightChar = rightSource.charAt(0); - - if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) { - return [left, ' ', right]; - } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { - return [left, right]; - } - return [left, space, right]; - } - - function addIndent(stmt) { - return [base, stmt]; - } - - function withIndent(fn) { - var previousBase, result; - previousBase = base; - base += indent; - result = fn.call(this, base); - base = previousBase; - return result; - } - - function calculateSpaces(str) { - var i; - for (i = str.length - 1; i >= 0; i -= 1) { - if (isLineTerminator(str.charAt(i))) { - break; - } - } - return (str.length - 1) - i; - } - - function adjustMultilineComment(value, specialBase) { - var array, i, len, line, j, spaces, previousBase; - - array = value.split(/\r\n|[\r\n]/); - spaces = Number.MAX_VALUE; - - // first line doesn't have indentation - for (i = 1, len = array.length; i < len; i += 1) { - line = array[i]; - j = 0; - while (j < line.length && isWhiteSpace(line[j])) { - j += 1; - } - if (spaces > j) { - spaces = j; - } - } - - if (typeof specialBase !== 'undefined') { - // pattern like - // { - // var t = 20; /* - // * this is comment - // */ - // } - previousBase = base; - if (array[1][spaces] === '*') { - specialBase += ' '; - } - base = specialBase; - } else { - if (spaces & 1) { - // /* - // * - // */ - // If spaces are odd number, above pattern is considered. - // We waste 1 space. - spaces -= 1; - } - previousBase = base; - } - - for (i = 1, len = array.length; i < len; i += 1) { - array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join(''); - } - - base = previousBase; - - return array.join('\n'); - } - - function generateComment(comment, specialBase) { - if (comment.type === 'Line') { - if (endsWithLineTerminator(comment.value)) { - return '//' + comment.value; - } else { - // Always use LineTerminator - return '//' + comment.value + '\n'; - } - } - if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { - return adjustMultilineComment('/*' + comment.value + '*/', specialBase); - } - return '/*' + comment.value + '*/'; - } - - function addCommentsToStatement(stmt, result) { - var i, len, comment, save, tailingToStatement, specialBase, fragment; - - if (stmt.leadingComments && stmt.leadingComments.length > 0) { - save = result; - - comment = stmt.leadingComments[0]; - result = []; - if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { - result.push('\n'); - } - result.push(generateComment(comment)); - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push('\n'); - } - - for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { - comment = stmt.leadingComments[i]; - fragment = [generateComment(comment)]; - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - fragment.push('\n'); - } - result.push(addIndent(fragment)); - } - - result.push(addIndent(save)); - } - - if (stmt.trailingComments) { - tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString()); - specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([base, result, indent]).toString())); - for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { - comment = stmt.trailingComments[i]; - if (tailingToStatement) { - // We assume target like following script - // - // var t = 20; /** - // * This is comment of t - // */ - if (i === 0) { - // first case - result = [result, indent]; - } else { - result = [result, specialBase]; - } - result.push(generateComment(comment, specialBase)); - } else { - result = [result, addIndent(generateComment(comment))]; - } - if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) { - result = [result, '\n']; - } - } - } - - return result; - } - - function parenthesize(text, current, should) { - if (current < should) { - return ['(', text, ')']; - } - return text; - } - - function maybeBlock(stmt, semicolonOptional, functionBody) { - var result, noLeadingComment; - - noLeadingComment = !extra.comment || !stmt.leadingComments; - - if (stmt.type === Syntax.BlockStatement && noLeadingComment) { - return [space, generateStatement(stmt, { functionBody: functionBody })]; - } - - if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { - return ';'; - } - - withIndent(function () { - result = [newline, addIndent(generateStatement(stmt, { semicolonOptional: semicolonOptional, functionBody: functionBody }))]; - }); - - return result; - } - - function maybeBlockSuffix(stmt, result) { - var ends = endsWithLineTerminator(toSourceNode(result).toString()); - if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) { - return [result, space]; - } - if (ends) { - return [result, base]; - } - return [result, newline, base]; - } - - function generateVerbatim(expr, option) { - var i, result; - result = expr[extra.verbatim].split(/\r\n|\n/); - for (i = 1; i < result.length; i++) { - result[i] = newline + base + result[i]; - } - - result = parenthesize(result, Precedence.Sequence, option.precedence); - return toSourceNode(result, expr); - } - - function generateIdentifier(node) { - return toSourceNode(node.name, node); - } - - function generateFunctionBody(node) { - var result, i, len, expr; - result = ['(']; - for (i = 0, len = node.params.length; i < len; i += 1) { - result.push(generateIdentifier(node.params[i])); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - - if (node.expression) { - result.push(space); - expr = generateExpression(node.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }); - if (expr.toString().charAt(0) === '{') { - expr = ['(', expr, ')']; - } - result.push(expr); - } else { - result.push(maybeBlock(node.body, false, true)); - } - return result; - } - - function generateExpression(expr, option) { - var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, allowIn, allowCall, allowUnparenthesizedNew, property; - - precedence = option.precedence; - allowIn = option.allowIn; - allowCall = option.allowCall; - type = expr.type || option.type; - - if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { - return generateVerbatim(expr, option); - } - - switch (type) { - case Syntax.SequenceExpression: - result = []; - allowIn |= (Precedence.Sequence < precedence); - for (i = 0, len = expr.expressions.length; i < len; i += 1) { - result.push(generateExpression(expr.expressions[i], { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result = parenthesize(result, Precedence.Sequence, precedence); - break; - - case Syntax.AssignmentExpression: - allowIn |= (Precedence.Assignment < precedence); - result = parenthesize( - [ - generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: allowIn, - allowCall: true - }), - space + expr.operator + space, - generateExpression(expr.right, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], - Precedence.Assignment, - precedence - ); - break; - - case Syntax.ConditionalExpression: - allowIn |= (Precedence.Conditional < precedence); - result = parenthesize( - [ - generateExpression(expr.test, { - precedence: Precedence.LogicalOR, - allowIn: allowIn, - allowCall: true - }), - space + '?' + space, - generateExpression(expr.consequent, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space + ':' + space, - generateExpression(expr.alternate, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], - Precedence.Conditional, - precedence - ); - break; - - case Syntax.LogicalExpression: - case Syntax.BinaryExpression: - currentPrecedence = BinaryPrecedence[expr.operator]; - - allowIn |= (currentPrecedence < precedence); - - fragment = generateExpression(expr.left, { - precedence: currentPrecedence, - allowIn: allowIn, - allowCall: true - }); - - leftSource = fragment.toString(); - - if (leftSource.charAt(leftSource.length - 1) === '/' && isIdentifierPart(expr.operator.charAt(0))) { - result = [fragment, ' ', expr.operator]; - } else { - result = join(fragment, expr.operator); - } - - fragment = generateExpression(expr.right, { - precedence: currentPrecedence + 1, - allowIn: allowIn, - allowCall: true - }); - - if (expr.operator === '/' && fragment.toString().charAt(0) === '/') { - // If '/' concats with '/', it is interpreted as comment start - result.push(' ', fragment); - } else { - result = join(result, fragment); - } - - if (expr.operator === 'in' && !allowIn) { - result = ['(', result, ')']; - } else { - result = parenthesize(result, currentPrecedence, precedence); - } - - break; - - case Syntax.CallExpression: - result = [generateExpression(expr.callee, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true, - allowUnparenthesizedNew: false - })]; - - result.push('('); - for (i = 0, len = expr['arguments'].length; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - - if (!allowCall) { - result = ['(', result, ')']; - } else { - result = parenthesize(result, Precedence.Call, precedence); - } - break; - - case Syntax.NewExpression: - len = expr['arguments'].length; - allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; - - result = join( - 'new', - generateExpression(expr.callee, { - precedence: Precedence.New, - allowIn: true, - allowCall: false, - allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 - }) - ); - - if (!allowUnparenthesizedNew || parentheses || len > 0) { - result.push('('); - for (i = 0; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - } - - result = parenthesize(result, Precedence.New, precedence); - break; - - case Syntax.MemberExpression: - result = [generateExpression(expr.object, { - precedence: Precedence.Call, - allowIn: true, - allowCall: allowCall, - allowUnparenthesizedNew: false - })]; - - if (expr.computed) { - result.push('[', generateExpression(expr.property, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: allowCall - }), ']'); - } else { - if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { - fragment = toSourceNode(result).toString(); - if (fragment.indexOf('.') < 0) { - if (!/[eExX]/.test(fragment) && - !(fragment.length >= 2 && fragment.charCodeAt(0) === 48)) { // '0' - result.push('.'); - } - } - } - result.push('.', generateIdentifier(expr.property)); - } - - result = parenthesize(result, Precedence.Member, precedence); - break; - - case Syntax.UnaryExpression: - fragment = generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }); - - if (space === '') { - result = join(expr.operator, fragment); - } else { - result = [expr.operator]; - if (expr.operator.length > 2) { - // delete, void, typeof - // get `typeof []`, not `typeof[]` - result = join(result, fragment); - } else { - // Prevent inserting spaces between operator and argument if it is unnecessary - // like, `!cond` - leftSource = toSourceNode(result).toString(); - leftChar = leftSource.charAt(leftSource.length - 1); - rightChar = fragment.toString().charAt(0); - - if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) { - result.push(' ', fragment); - } else { - result.push(fragment); - } - } - } - result = parenthesize(result, Precedence.Unary, precedence); - break; - - case Syntax.YieldExpression: - if (expr.delegate) { - result = 'yield*'; - } else { - result = 'yield'; - } - if (expr.argument) { - result = join( - result, - generateExpression(expr.argument, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ); - } - break; - - case Syntax.UpdateExpression: - if (expr.prefix) { - result = parenthesize( - [ - expr.operator, - generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }) - ], - Precedence.Unary, - precedence - ); - } else { - result = parenthesize( - [ - generateExpression(expr.argument, { - precedence: Precedence.Postfix, - allowIn: true, - allowCall: true - }), - expr.operator - ], - Precedence.Postfix, - precedence - ); - } - break; - - case Syntax.FunctionExpression: - result = 'function'; - - if (expr.id) { - result = [result + ' ', - generateIdentifier(expr.id), - generateFunctionBody(expr)]; - } else { - result = [result + space, generateFunctionBody(expr)]; - } - - break; - - case Syntax.ArrayPattern: - case Syntax.ArrayExpression: - if (!expr.elements.length) { - result = '[]'; - break; - } - multiline = expr.elements.length > 1; - result = ['[', multiline ? newline : '']; - withIndent(function (indent) { - for (i = 0, len = expr.elements.length; i < len; i += 1) { - if (!expr.elements[i]) { - if (multiline) { - result.push(indent); - } - if (i + 1 === len) { - result.push(','); - } - } else { - result.push(multiline ? indent : '', generateExpression(expr.elements[i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - } - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', ']'); - break; - - case Syntax.Property: - if (expr.kind === 'get' || expr.kind === 'set') { - result = [ - expr.kind + ' ', - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - generateFunctionBody(expr.value) - ]; - } else { - if (expr.shorthand) { - result = generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - } else if (expr.method) { - result = []; - if (expr.value.generator) { - result.push('*'); - } - result.push(generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), generateFunctionBody(expr.value)); - } else { - result = [ - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ':' + space, - generateExpression(expr.value, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - } - } - break; - - case Syntax.ObjectExpression: - if (!expr.properties.length) { - result = '{}'; - break; - } - multiline = expr.properties.length > 1; - - withIndent(function () { - fragment = generateExpression(expr.properties[0], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - }); - }); - - if (!multiline) { - // issues 4 - // Do not transform from - // dejavu.Class.declare({ - // method2: function () {} - // }); - // to - // dejavu.Class.declare({method2: function () { - // }}); - if (!hasLineTerminator(toSourceNode(fragment).toString())) { - result = [ '{', space, fragment, space, '}' ]; - break; - } - } - - withIndent(function (indent) { - result = [ '{', newline, indent, fragment ]; - - if (multiline) { - result.push(',' + newline); - for (i = 1, len = expr.properties.length; i < len; i += 1) { - result.push(indent, generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - })); - if (i + 1 < len) { - result.push(',' + newline); - } - } - } - }); - - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(base, '}'); - break; - - case Syntax.ObjectPattern: - if (!expr.properties.length) { - result = '{}'; - break; - } - - multiline = false; - if (expr.properties.length === 1) { - property = expr.properties[0]; - if (property.value.type !== Syntax.Identifier) { - multiline = true; - } - } else { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - property = expr.properties[i]; - if (!property.shorthand) { - multiline = true; - break; - } - } - } - result = ['{', multiline ? newline : '' ]; - - withIndent(function (indent) { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - result.push(multiline ? indent : '', generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', '}'); - break; - - case Syntax.ThisExpression: - result = 'this'; - break; - - case Syntax.Identifier: - result = generateIdentifier(expr); - break; - - case Syntax.Literal: - if (expr.hasOwnProperty('raw') && parse) { - try { - raw = parse(expr.raw).body[0].expression; - if (raw.type === Syntax.Literal) { - if (raw.value === expr.value) { - result = expr.raw; - break; - } - } - } catch (e) { - // not use raw property - } - } - - if (expr.value === null) { - result = 'null'; - break; - } - - if (typeof expr.value === 'string') { - result = escapeString(expr.value); - break; - } - - if (typeof expr.value === 'number') { - result = generateNumber(expr.value); - break; - } - - if (typeof expr.value === 'boolean') { - result = expr.value ? 'true' : 'false'; - break; - } - - result = generateRegExp(expr.value); - break; - - case Syntax.ComprehensionExpression: - result = [ - '[', - generateExpression(expr.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - - if (expr.blocks) { - for (i = 0, len = expr.blocks.length; i < len; i += 1) { - fragment = generateExpression(expr.blocks[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - result = join(result, fragment); - } - } - - if (expr.filter) { - result = join(result, 'if' + space); - fragment = generateExpression(expr.filter, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - if (extra.moz.parenthesizedComprehensionBlock) { - result = join(result, [ '(', fragment, ')' ]); - } else { - result = join(result, fragment); - } - } - result.push(']'); - break; - - case Syntax.ComprehensionBlock: - if (expr.left.type === Syntax.VariableDeclaration) { - fragment = [ - expr.left.kind + ' ', - generateStatement(expr.left.declarations[0], { - allowIn: false - }) - ]; - } else { - fragment = generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - }); - } - - fragment = join(fragment, expr.of ? 'of' : 'in'); - fragment = join(fragment, generateExpression(expr.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - - if (extra.moz.parenthesizedComprehensionBlock) { - result = [ 'for' + space + '(', fragment, ')' ]; - } else { - result = join('for' + space, fragment); - } - break; - - default: - throw new Error('Unknown expression type: ' + expr.type); - } - - return toSourceNode(result, expr); - } - - function generateStatement(stmt, option) { - var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon; - - allowIn = true; - semicolon = ';'; - functionBody = false; - directiveContext = false; - if (option) { - allowIn = option.allowIn === undefined || option.allowIn; - if (!semicolons && option.semicolonOptional === true) { - semicolon = ''; - } - functionBody = option.functionBody; - directiveContext = option.directiveContext; - } - - switch (stmt.type) { - case Syntax.BlockStatement: - result = ['{', newline]; - - withIndent(function () { - for (i = 0, len = stmt.body.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.body[i], { - semicolonOptional: i === len - 1, - directiveContext: functionBody - })); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - - result.push(addIndent('}')); - break; - - case Syntax.BreakStatement: - if (stmt.label) { - result = 'break ' + stmt.label.name + semicolon; - } else { - result = 'break' + semicolon; - } - break; - - case Syntax.ContinueStatement: - if (stmt.label) { - result = 'continue ' + stmt.label.name + semicolon; - } else { - result = 'continue' + semicolon; - } - break; - - case Syntax.DirectiveStatement: - if (stmt.raw) { - result = stmt.raw + semicolon; - } else { - result = escapeDirective(stmt.directive) + semicolon; - } - break; - - case Syntax.DoWhileStatement: - // Because `do 42 while (cond)` is Syntax Error. We need semicolon. - result = join('do', maybeBlock(stmt.body)); - result = maybeBlockSuffix(stmt.body, result); - result = join(result, [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + semicolon - ]); - break; - - case Syntax.CatchClause: - withIndent(function () { - result = [ - 'catch' + space + '(', - generateExpression(stmt.param, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body)); - break; - - case Syntax.DebuggerStatement: - result = 'debugger' + semicolon; - break; - - case Syntax.EmptyStatement: - result = ';'; - break; - - case Syntax.ExpressionStatement: - result = [generateExpression(stmt.expression, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })]; - // 12.4 '{', 'function' is not allowed in this position. - // wrap expression with parentheses - fragment = toSourceNode(result).toString(); - if (fragment.charAt(0) === '{' || (fragment.slice(0, 8) === 'function' && ' ('.indexOf(fragment.charAt(8)) >= 0) || (directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) { - result = ['(', result, ')' + semicolon]; - } else { - result.push(semicolon); - } - break; - - case Syntax.VariableDeclarator: - if (stmt.init) { - result = [ - generateExpression(stmt.id, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space, - '=', - space, - generateExpression(stmt.init, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ]; - } else { - result = generateIdentifier(stmt.id); - } - break; - - case Syntax.VariableDeclaration: - result = [stmt.kind]; - // special path for - // var x = function () { - // }; - if (stmt.declarations.length === 1 && stmt.declarations[0].init && - stmt.declarations[0].init.type === Syntax.FunctionExpression) { - result.push(' ', generateStatement(stmt.declarations[0], { - allowIn: allowIn - })); - } else { - // VariableDeclarator is typed as Statement, - // but joined with comma (not LineTerminator). - // So if comment is attached to target node, we should specialize. - withIndent(function () { - node = stmt.declarations[0]; - if (extra.comment && node.leadingComments) { - result.push('\n', addIndent(generateStatement(node, { - allowIn: allowIn - }))); - } else { - result.push(' ', generateStatement(node, { - allowIn: allowIn - })); - } - - for (i = 1, len = stmt.declarations.length; i < len; i += 1) { - node = stmt.declarations[i]; - if (extra.comment && node.leadingComments) { - result.push(',' + newline, addIndent(generateStatement(node, { - allowIn: allowIn - }))); - } else { - result.push(',' + space, generateStatement(node, { - allowIn: allowIn - })); - } - } - }); - } - result.push(semicolon); - break; - - case Syntax.ThrowStatement: - result = [join( - 'throw', - generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }) - ), semicolon]; - break; - - case Syntax.TryStatement: - result = ['try', maybeBlock(stmt.block)]; - result = maybeBlockSuffix(stmt.block, result); - if (stmt.handlers) { - // old interface - for (i = 0, len = stmt.handlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.handlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.handlers[i].body, result); - } - } - } else { - // new interface - if (stmt.handler) { - result = join(result, generateStatement(stmt.handler)); - if (stmt.finalizer || stmt.guardedHandlers.length > 0) { - result = maybeBlockSuffix(stmt.handler.body, result); - } - } - - for (i = 0, len = stmt.guardedHandlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.guardedHandlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.guardedHandlers[i].body, result); - } - } - } - if (stmt.finalizer) { - result = join(result, ['finally', maybeBlock(stmt.finalizer)]); - } - break; - - case Syntax.SwitchStatement: - withIndent(function () { - result = [ - 'switch' + space + '(', - generateExpression(stmt.discriminant, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + space + '{' + newline - ]; - }); - if (stmt.cases) { - for (i = 0, len = stmt.cases.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.cases[i], {semicolonOptional: i === len - 1})); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - } - result.push(addIndent('}')); - break; - - case Syntax.SwitchCase: - withIndent(function () { - if (stmt.test) { - result = [ - join('case', generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - ':' - ]; - } else { - result = ['default:']; - } - - i = 0; - len = stmt.consequent.length; - if (len && stmt.consequent[0].type === Syntax.BlockStatement) { - fragment = maybeBlock(stmt.consequent[0]); - result.push(fragment); - i = 1; - } - - if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - - for (; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.consequent[i], {semicolonOptional: i === len - 1 && semicolon === ''})); - result.push(fragment); - if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - break; - - case Syntax.IfStatement: - withIndent(function () { - result = [ - 'if' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - if (stmt.alternate) { - result.push(maybeBlock(stmt.consequent)); - result = maybeBlockSuffix(stmt.consequent, result); - if (stmt.alternate.type === Syntax.IfStatement) { - result = join(result, ['else ', generateStatement(stmt.alternate, {semicolonOptional: semicolon === ''})]); - } else { - result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === ''))); - } - } else { - result.push(maybeBlock(stmt.consequent, semicolon === '')); - } - break; - - case Syntax.ForStatement: - withIndent(function () { - result = ['for' + space + '(']; - if (stmt.init) { - if (stmt.init.type === Syntax.VariableDeclaration) { - result.push(generateStatement(stmt.init, {allowIn: false})); - } else { - result.push(generateExpression(stmt.init, { - precedence: Precedence.Sequence, - allowIn: false, - allowCall: true - }), ';'); - } - } else { - result.push(';'); - } - - if (stmt.test) { - result.push(space, generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ';'); - } else { - result.push(';'); - } - - if (stmt.update) { - result.push(space, generateExpression(stmt.update, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ')'); - } else { - result.push(')'); - } - }); - - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - case Syntax.ForInStatement: - result = ['for' + space + '(']; - withIndent(function () { - if (stmt.left.type === Syntax.VariableDeclaration) { - withIndent(function () { - result.push(stmt.left.kind + ' ', generateStatement(stmt.left.declarations[0], { - allowIn: false - })); - }); - } else { - result.push(generateExpression(stmt.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - })); - } - - result = join(result, 'in'); - result = [join( - result, - generateExpression(stmt.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }) - ), ')']; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - case Syntax.LabeledStatement: - result = [stmt.label.name + ':', maybeBlock(stmt.body, semicolon === '')]; - break; - - case Syntax.Program: - len = stmt.body.length; - result = [safeConcatenation && len > 0 ? '\n' : '']; - for (i = 0; i < len; i += 1) { - fragment = addIndent( - generateStatement(stmt.body[i], { - semicolonOptional: !safeConcatenation && i === len - 1, - directiveContext: true - }) - ); - result.push(fragment); - if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - break; - - case Syntax.FunctionDeclaration: - result = [(stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function '), - generateIdentifier(stmt.id), - generateFunctionBody(stmt)]; - break; - - case Syntax.ReturnStatement: - if (stmt.argument) { - result = [join( - 'return', - generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }) - ), semicolon]; - } else { - result = ['return' + semicolon]; - } - break; - - case Syntax.WhileStatement: - withIndent(function () { - result = [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - case Syntax.WithStatement: - withIndent(function () { - result = [ - 'with' + space + '(', - generateExpression(stmt.object, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - default: - throw new Error('Unknown statement type: ' + stmt.type); - } - - // Attach comments - - if (extra.comment) { - result = addCommentsToStatement(stmt, result); - } - - fragment = toSourceNode(result).toString(); - if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') { - result = toSourceNode(result).replaceRight(/\s+$/, ''); - } - - return toSourceNode(result, stmt); - } - - function generate(node, options) { - var defaultOptions = getDefaultOptions(), result, pair; - - if (options != null) { - // Obsolete options - // - // `options.indent` - // `options.base` - // - // Instead of them, we can use `option.format.indent`. - if (typeof options.indent === 'string') { - defaultOptions.format.indent.style = options.indent; - } - if (typeof options.base === 'number') { - defaultOptions.format.indent.base = options.base; - } - options = updateDeeply(defaultOptions, options); - indent = options.format.indent.style; - if (typeof options.base === 'string') { - base = options.base; - } else { - base = stringRepeat(indent, options.format.indent.base); - } - } else { - options = defaultOptions; - indent = options.format.indent.style; - base = stringRepeat(indent, options.format.indent.base); - } - json = options.format.json; - renumber = options.format.renumber; - hexadecimal = json ? false : options.format.hexadecimal; - quotes = json ? 'double' : options.format.quotes; - escapeless = options.format.escapeless; - if (options.format.compact) { - newline = space = indent = base = ''; - } else { - newline = '\n'; - space = ' '; - } - parentheses = options.format.parentheses; - semicolons = options.format.semicolons; - safeConcatenation = options.format.safeConcatenation; - directive = options.directive; - parse = json ? null : options.parse; - sourceMap = options.sourceMap; - extra = options; - - if (sourceMap) { - if (!exports.browser) { - // We assume environment is node.js - // And prevent from including source-map by browserify - SourceNode = require('source-map').SourceNode; - } else { - SourceNode = global.sourceMap.SourceNode; - } - } else { - SourceNode = SourceNodeMock; - } - - switch (node.type) { - case Syntax.BlockStatement: - case Syntax.BreakStatement: - case Syntax.CatchClause: - case Syntax.ContinueStatement: - case Syntax.DirectiveStatement: - case Syntax.DoWhileStatement: - case Syntax.DebuggerStatement: - case Syntax.EmptyStatement: - case Syntax.ExpressionStatement: - case Syntax.ForStatement: - case Syntax.ForInStatement: - case Syntax.FunctionDeclaration: - case Syntax.IfStatement: - case Syntax.LabeledStatement: - case Syntax.Program: - case Syntax.ReturnStatement: - case Syntax.SwitchStatement: - case Syntax.SwitchCase: - case Syntax.ThrowStatement: - case Syntax.TryStatement: - case Syntax.VariableDeclaration: - case Syntax.VariableDeclarator: - case Syntax.WhileStatement: - case Syntax.WithStatement: - result = generateStatement(node); - break; - - case Syntax.AssignmentExpression: - case Syntax.ArrayExpression: - case Syntax.ArrayPattern: - case Syntax.BinaryExpression: - case Syntax.CallExpression: - case Syntax.ConditionalExpression: - case Syntax.FunctionExpression: - case Syntax.Identifier: - case Syntax.Literal: - case Syntax.LogicalExpression: - case Syntax.MemberExpression: - case Syntax.NewExpression: - case Syntax.ObjectExpression: - case Syntax.ObjectPattern: - case Syntax.Property: - case Syntax.SequenceExpression: - case Syntax.ThisExpression: - case Syntax.UnaryExpression: - case Syntax.UpdateExpression: - case Syntax.YieldExpression: - - result = generateExpression(node, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - break; - - default: - throw new Error('Unknown node type: ' + node.type); - } - - if (!sourceMap) { - return result.toString(); - } - - pair = result.toStringWithSourceMap({ - file: options.file, - sourceRoot: options.sourceMapRoot - }); - - if (options.sourceMapWithCode) { - return pair; - } - return pair.map.toString(); - } - - FORMAT_MINIFY = { - indent: { - style: '', - base: 0 - }, - renumber: true, - hexadecimal: true, - quotes: 'auto', - escapeless: true, - compact: true, - parentheses: false, - semicolons: false - }; - - FORMAT_DEFAULTS = getDefaultOptions().format; - - // exports.version = require('./package.json').version; - exports.generate = generate; - exports.attachComments = estraverse.attachComments; - exports.browser = false; - exports.FORMAT_MINIFY = FORMAT_MINIFY; - exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS; -}()); -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/toolkit/devtools/escodegen/escodegen.worker.js b/toolkit/devtools/escodegen/escodegen.worker.js deleted file mode 100644 index 16aaa2901d3..00000000000 --- a/toolkit/devtools/escodegen/escodegen.worker.js +++ /dev/null @@ -1,5539 +0,0 @@ -let window = self; -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -/** - * Define a module along with a payload. - * @param {string} moduleName Name for the payload - * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec - * @param {function} payload Function with (require, exports, module) params - */ -function define(moduleName, deps, payload) { - if (typeof moduleName != "string") { - throw new TypeError('Expected string, got: ' + moduleName); - } - - if (arguments.length == 2) { - payload = deps; - } - - if (moduleName in define.modules) { - throw new Error("Module already defined: " + moduleName); - } - define.modules[moduleName] = payload; -}; - -/** - * The global store of un-instantiated modules - */ -define.modules = {}; - - -/** - * We invoke require() in the context of a Domain so we can have multiple - * sets of modules running separate from each other. - * This contrasts with JSMs which are singletons, Domains allows us to - * optionally load a CommonJS module twice with separate data each time. - * Perhaps you want 2 command lines with a different set of commands in each, - * for example. - */ -function Domain() { - this.modules = {}; - this._currentModule = null; -} - -(function () { - - /** - * Lookup module names and resolve them by calling the definition function if - * needed. - * There are 2 ways to call this, either with an array of dependencies and a - * callback to call when the dependencies are found (which can happen - * asynchronously in an in-page context) or with a single string an no callback - * where the dependency is resolved synchronously and returned. - * The API is designed to be compatible with the CommonJS AMD spec and - * RequireJS. - * @param {string[]|string} deps A name, or names for the payload - * @param {function|undefined} callback Function to call when the dependencies - * are resolved - * @return {undefined|object} The module required or undefined for - * array/callback method - */ - Domain.prototype.require = function(deps, callback) { - if (Array.isArray(deps)) { - var params = deps.map(function(dep) { - return this.lookup(dep); - }, this); - if (callback) { - callback.apply(null, params); - } - return undefined; - } - else { - return this.lookup(deps); - } - }; - - function normalize(path) { - var bits = path.split('/'); - var i = 1; - while (i < bits.length) { - if (bits[i] === '..') { - bits.splice(i-1, 1); - } else if (bits[i] === '.') { - bits.splice(i, 1); - } else { - i++; - } - } - return bits.join('/'); - } - - function join(a, b) { - a = a.trim(); - b = b.trim(); - if (/^\//.test(b)) { - return b; - } else { - return a.replace(/\/*$/, '/') + b; - } - } - - function dirname(path) { - var bits = path.split('/'); - bits.pop(); - return bits.join('/'); - } - - /** - * Lookup module names and resolve them by calling the definition function if - * needed. - * @param {string} moduleName A name for the payload to lookup - * @return {object} The module specified by aModuleName or null if not found. - */ - Domain.prototype.lookup = function(moduleName) { - if (/^\./.test(moduleName)) { - moduleName = normalize(join(dirname(this._currentModule), moduleName)); - } - - if (moduleName in this.modules) { - var module = this.modules[moduleName]; - return module; - } - - if (!(moduleName in define.modules)) { - throw new Error("Module not defined: " + moduleName); - } - - var module = define.modules[moduleName]; - - if (typeof module == "function") { - var exports = {}; - var previousModule = this._currentModule; - this._currentModule = moduleName; - module(this.require.bind(this), exports, { id: moduleName, uri: "" }); - this._currentModule = previousModule; - module = exports; - } - - // cache the resulting module object for next time - this.modules[moduleName] = module; - - return module; - }; - -}()); - -define.Domain = Domain; -define.globalDomain = new Domain(); -var require = define.globalDomain.require.bind(define.globalDomain); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-map-generator', ['require', 'exports', 'module' , 'source-map/base64-vlq', 'source-map/util', 'source-map/array-set'], function(require, exports, module) { - - var base64VLQ = require('./base64-vlq'); - var util = require('./util'); - var ArraySet = require('./array-set').ArraySet; - - /** - * An instance of the SourceMapGenerator represents a source map which is - * being built incrementally. To create a new one, you must pass an object - * with the following properties: - * - * - file: The filename of the generated source. - * - sourceRoot: An optional root for all URLs in this source map. - */ - function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._sources = new ArraySet(); - this._names = new ArraySet(); - this._mappings = []; - this._sourcesContents = null; - } - - SourceMapGenerator.prototype._version = 3; - - /** - * Creates a new SourceMapGenerator based on a SourceMapConsumer - * - * @param aSourceMapConsumer The SourceMap. - */ - SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - - if (mapping.source) { - newMapping.source = mapping.source; - if (sourceRoot) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - - if (mapping.name) { - newMapping.name = mapping.name; - } - } - - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - - /** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. - */ - SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - - this._validateMapping(generated, original, source, name); - - if (source && !this._sources.has(source)) { - this._sources.add(source); - } - - if (name && !this._names.has(name)) { - this._names.add(name); - } - - this._mappings.push({ - generatedLine: generated.line, - generatedColumn: generated.column, - originalLine: original != null && original.line, - originalColumn: original != null && original.column, - source: source, - name: name - }); - }; - - /** - * Set the source content for a source file. - */ - SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot) { - source = util.relative(this._sourceRoot, source); - } - - if (aSourceContent !== null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = {}; - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - - /** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - */ - SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (!aSourceFile) { - aSourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "aSourceFile" relative if an absolute Url is passed. - if (sourceRoot) { - aSourceFile = util.relative(sourceRoot, aSourceFile); - } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); - - // Find mappings for the "aSourceFile" - this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.originalLine) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.originalLine, - column: mapping.originalColumn - }); - if (original.source !== null) { - // Copy mapping - if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; - } - 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 - mapping.name = original.name; - } - } - } - - var source = mapping.source; - if (source && !newSources.has(source)) { - newSources.add(source); - } - - var name = mapping.name; - if (name && !newNames.has(name)) { - newNames.add(name); - } - - }, this); - this._sources = newSources; - this._names = newNames; - - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - if (sourceRoot) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - - /** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. - * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. - */ - SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aGenerated.line > 0 && aGenerated.column >= 0 - && !aOriginal && !aSource && !aName) { - // Case 1. - return; - } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal - && aGenerated.line > 0 && aGenerated.column >= 0 - && aOriginal.line > 0 && aOriginal.column >= 0 - && aSource) { - // Cases 2 and 3. - return; - } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ - generated: aGenerated, - source: aSource, - orginal: aOriginal, - name: aName - })); - } - }; - - /** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. - */ - SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var mapping; - - // The mappings must be guaranteed to be in sorted order before we start - // serializing them or else the generated line numbers (which are defined - // via the ';' separators) will be all messed up. Note: it might be more - // performant to maintain the sorting as we insert them, rather than as we - // serialize them, but the big O is the same either way. - this._mappings.sort(util.compareByGeneratedPositions); - - for (var i = 0, len = this._mappings.length; i < len; i++) { - mapping = this._mappings[i]; - - if (mapping.generatedLine !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generatedLine !== previousGeneratedLine) { - result += ';'; - previousGeneratedLine++; - } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { - continue; - } - result += ','; - } - } - - result += base64VLQ.encode(mapping.generatedColumn - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generatedColumn; - - 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.originalLine - 1 - - previousOriginalLine); - previousOriginalLine = mapping.originalLine - 1; - - result += base64VLQ.encode(mapping.originalColumn - - previousOriginalColumn); - previousOriginalColumn = mapping.originalColumn; - - if (mapping.name) { - result += base64VLQ.encode(this._names.indexOf(mapping.name) - - previousName); - previousName = this._names.indexOf(mapping.name); - } - } - } - - 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. - */ - SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - file: this._file, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._sourceRoot) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); - } - - return map; - }; - - /** - * Render the source map being generated to a string. - */ - SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this); - }; - - exports.SourceMapGenerator = SourceMapGenerator; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - * - * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java - * - * Copyright 2011 The Closure Compiler Authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/base64'], function(require, exports, module) { - - var base64 = require('./base64'); - - // A single base 64 digit can contain 6 bits of data. For the base 64 variable - // length quantities we use in the source map spec, the first bit is the sign, - // the next four bits are the actual value, and the 6th bit is the - // continuation bit. The continuation bit tells us whether there are more - // digits in this value following this digit. - // - // Continuation - // | Sign - // | | - // V V - // 101011 - - var VLQ_BASE_SHIFT = 5; - - // binary: 100000 - var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - - // binary: 011111 - var VLQ_BASE_MASK = VLQ_BASE - 1; - - // binary: 100000 - var VLQ_CONTINUATION_BIT = VLQ_BASE; - - /** - * Converts from a two-complement value to a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) - */ - function toVLQSigned(aValue) { - return aValue < 0 - ? ((-aValue) << 1) + 1 - : (aValue << 1) + 0; - } - - /** - * Converts to a two-complement value from a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 - */ - function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative - ? -shifted - : shifted; - } - - /** - * Returns the base 64 VLQ encoded value. - */ - exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; - - var vlq = toVLQSigned(aValue); - - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - // There are still more digits in this value, so we must make sure the - // continuation bit is marked. - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - - return encoded; - }; - - /** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string. - */ - exports.decode = function base64VLQ_decode(aStr) { - var i = 0; - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - - do { - if (i >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); - } - digit = base64.decode(aStr.charAt(i++)); - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - return { - value: fromVLQSigned(result), - rest: aStr.slice(i) - }; - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/base64', ['require', 'exports', 'module' , ], function(require, exports, module) { - - var charToIntMap = {}; - var intToCharMap = {}; - - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - .split('') - .forEach(function (ch, index) { - charToIntMap[ch] = index; - intToCharMap[index] = ch; - }); - - /** - * Encode an integer in the range of 0 to 63 to a single base 64 digit. - */ - exports.encode = function base64_encode(aNumber) { - if (aNumber in intToCharMap) { - return intToCharMap[aNumber]; - } - throw new TypeError("Must be between 0 and 63: " + aNumber); - }; - - /** - * Decode a single base 64 digit to an integer. - */ - exports.decode = function base64_decode(aChar) { - if (aChar in charToIntMap) { - return charToIntMap[aChar]; - } - throw new TypeError("Not a valid base 64 digit: " + aChar); - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) { - - /** - * This is a helper function for getting values from parameter/options - * objects. - * - * @param args The object we are extracting values from - * @param name The name of the property we are getting. - * @param defaultValue An optional value to return if the property is missing - * from the object. If this is not specified and the property is missing, an - * error will be thrown. - */ - function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } - } - exports.getArg = getArg; - - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - var dataUrlRegexp = /^data:.+\,.+/; - - function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] - }; - } - exports.urlParse = urlParse; - - 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; - - if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { - return aPath; - } - - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); - } - - return aRoot.replace(/\/$/, '') + '/' + aPath; - } - exports.join = join; - - /** - * Because behavior goes wacky when you set `__proto__` on objects, we - * have to prefix all the strings in our set with an arbitrary character. - * - * See https://github.com/mozilla/source-map/pull/31 and - * https://github.com/mozilla/source-map/issues/30 - * - * @param String aStr - */ - function toSetString(aStr) { - return '$' + aStr; - } - exports.toSetString = toSetString; - - function fromSetString(aStr) { - return aStr.substr(1); - } - exports.fromSetString = fromSetString; - - function relative(aRoot, aPath) { - aRoot = aRoot.replace(/\/$/, ''); - - var url = urlParse(aRoot); - if (aPath.charAt(0) == "/" && url && url.path == "/") { - return aPath.slice(1); - } - - return aPath.indexOf(aRoot + '/') === 0 - ? aPath.substr(aRoot.length + 1) - : aPath; - } - exports.relative = relative; - - 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; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) { - - var util = require('./util'); - - /** - * A data structure which is a combination of an array and a set. Adding a new - * member is O(1), testing for membership is O(1), and finding the index of an - * element is O(1). Removing elements from the set is not supported. Only - * strings are supported for membership. - */ - function ArraySet() { - this._array = []; - this._set = {}; - } - - /** - * Static method for creating ArraySet instances from an existing array. - */ - ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); - } - return set; - }; - - /** - * Add the given string to this set. - * - * @param String aStr - */ - ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var isDuplicate = this.has(aStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - this._set[util.toSetString(aStr)] = idx; - } - }; - - /** - * Is the given string a member of this set? - * - * @param String aStr - */ - ArraySet.prototype.has = function ArraySet_has(aStr) { - return Object.prototype.hasOwnProperty.call(this._set, - util.toSetString(aStr)); - }; - - /** - * What is the index of the given string in the array? - * - * @param String aStr - */ - ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (this.has(aStr)) { - return this._set[util.toSetString(aStr)]; - } - throw new Error('"' + aStr + '" is not in the set.'); - }; - - /** - * What is the element at the given index? - * - * @param Number aIdx - */ - ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); - }; - - /** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ - ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); - }; - - exports.ArraySet = ArraySet; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'source-map/util', 'source-map/binary-search', 'source-map/array-set', 'source-map/base64-vlq'], function(require, exports, module) { - - var util = require('./util'); - var binarySearch = require('./binary-search'); - var ArraySet = require('./array-set').ArraySet; - var base64VLQ = require('./base64-vlq'); - - /** - * A SourceMapConsumer instance represents a parsed source map which we can - * query for information about the original file positions by giving it a file - * position in the generated source. - * - * The only parameter is the raw source map (either as a JSON string, or - * already parsed to an object). According to the spec, source maps have the - * following attributes: - * - * - version: Which version of the source map spec this map is following. - * - sources: An array of URLs to the original source files. - * - names: An array of identifiers which can be referrenced by individual mappings. - * - sourceRoot: Optional. The URL root from which all sources are relative. - * - sourcesContent: Optional. An array of contents of the original source files. - * - mappings: A string of base64 VLQs which contain the actual mappings. - * - file: The generated file this source map is associated with. - * - * Here is an example source map, taken from the source map spec[0]: - * - * { - * version : 3, - * file: "out.js", - * sourceRoot : "", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AA,AB;;ABCDE;" - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# - */ - function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - var names = util.getArg(sourceMap, 'names'); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - - if (version !== this._version) { - throw new Error('Unsupported version: ' + version); - } - - // 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; - - // `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); - } - - /** - * 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. - */ - SourceMapConsumer.prototype._version = 3; - - /** - * The list of original sources. - */ - Object.defineProperty(SourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot ? util.join(this.sourceRoot, s) : s; - }, this); - } - }); - - /** - * Parse the mappings in a string in to a data structure which we can easily - * query (an ordered list in this._generatedMappings). - */ - SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var mappingSeparator = /^[,;]/; - var str = aStr; - var mapping; - var temp; - - while (str.length > 0) { - if (str.charAt(0) === ';') { - generatedLine++; - str = str.slice(1); - previousGeneratedColumn = 0; - } - else if (str.charAt(0) === ',') { - str = str.slice(1); - } - else { - mapping = {}; - mapping.generatedLine = generatedLine; - - // Generated column. - temp = base64VLQ.decode(str); - mapping.generatedColumn = previousGeneratedColumn + temp.value; - previousGeneratedColumn = mapping.generatedColumn; - str = temp.rest; - - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original source. - temp = base64VLQ.decode(str); - mapping.source = this._sources.at(previousSource + temp.value); - previousSource += temp.value; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source, but no line and column'); - } - - // Original line. - temp = base64VLQ.decode(str); - mapping.originalLine = previousOriginalLine + temp.value; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source and line, but no column'); - } - - // Original column. - temp = base64VLQ.decode(str); - mapping.originalColumn = previousOriginalColumn + temp.value; - previousOriginalColumn = mapping.originalColumn; - str = temp.rest; - - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original name. - temp = base64VLQ.decode(str); - mapping.name = this._names.at(previousName + temp.value); - previousName += temp.value; - str = temp.rest; - } - } - - this._generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - this._originalMappings.push(mapping); - } - } - } - - this._originalMappings.sort(util.compareByOriginalPositions); - }; - - /** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ - SourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, - aColumnName, aComparator) { - // To return the position we are searching for, we must first find the - // mapping for the given position and then return the opposite position it - // points to. Because the mappings are sorted, we can use binary search to - // find the best mapping. - - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); - } - - return binarySearch.search(aNeedle, aMappings, aComparator); - }; - - /** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ - SourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - var mapping = this._findMapping(needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositions); - - if (mapping) { - var source = util.getArg(mapping, 'source', null); - if (source && this.sourceRoot) { - source = util.join(this.sourceRoot, source); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: util.getArg(mapping, 'name', null) - }; - } - - return { - source: null, - line: null, - column: null, - name: null - }; - }; - - /** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * availible. - */ - SourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource) { - if (!this.sourcesContent) { - return null; - } - - if (this.sourceRoot) { - 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.'); - }; - - /** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ - SourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - - if (this.sourceRoot) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - - var mapping = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions); - - if (mapping) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null) - }; - } - - return { - line: null, - column: null - }; - }; - - SourceMapConsumer.GENERATED_ORDER = 1; - SourceMapConsumer.ORIGINAL_ORDER = 2; - - /** - * Iterate over each mapping between an original source/line/column and a - * generated line/column in this source map. - * - * @param Function aCallback - * The function that is called with each mapping. - * @param Object aContext - * Optional. If specified, this object will be the value of `this` every - * time that `aCallback` is called. - * @param aOrder - * Either `SourceMapConsumer.GENERATED_ORDER` or - * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to - * iterate over the mappings sorted by the generated file's line/column - * order or the original's source/line/column order, respectively. Defaults to - * `SourceMapConsumer.GENERATED_ORDER`. - */ - SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error("Unknown order of iteration."); - } - - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source; - if (source && sourceRoot) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name - }; - }).forEach(aCallback, context); - }; - - exports.SourceMapConsumer = SourceMapConsumer; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/binary-search', ['require', 'exports', 'module' , ], function(require, exports, module) { - - /** - * Recursive implementation of binary search. - * - * @param aLow Indices here and lower do not contain the needle. - * @param aHigh Indices here and higher do not contain the needle. - * @param aNeedle The element being searched for. - * @param aHaystack The non-empty array being searched. - * @param aCompare Function which takes two elements and returns -1, 0, or 1. - */ - function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { - // This function terminates when one of the following is true: - // - // 1. We find the exact element we are looking for. - // - // 2. We did not find the exact element, but we can return the next - // closest element that is less than that element. - // - // 3. We did not find the exact element, and there is no next-closest - // element which is less than the one we are searching for, so we - // return null. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); - if (cmp === 0) { - // Found the element we are looking for. - return aHaystack[mid]; - } - else if (cmp > 0) { - // aHaystack[mid] is greater than our needle. - if (aHigh - mid > 1) { - // The element is in the upper half. - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); - } - // We did not find an exact match, return the next closest one - // (termination case 2). - return aHaystack[mid]; - } - else { - // aHaystack[mid] is less than our needle. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); - } - // The exact needle element was not found in this haystack. Determine if - // we are in termination case (2) or (3) and return the appropriate thing. - return aLow < 0 - ? null - : aHaystack[aLow]; - } - } - - /** - * This is an implementation of binary search which will always try and return - * the next lowest value checked if there is no exact hit. This is because - * mappings between original and generated line/col pairs are single points, - * and there is an implicit region between each of them, so a miss just means - * that you aren't on the very start of a region. - * - * @param aNeedle The element you are looking for. - * @param aHaystack The array that is being searched. - * @param aCompare A function which takes the needle and an element in the - * array and returns -1, 0, or 1 depending on whether the needle is less - * than, equal to, or greater than the element, respectively. - */ - exports.search = function search(aNeedle, aHaystack, aCompare) { - return aHaystack.length > 0 - ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) - : null; - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) { - - var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; - var util = require('./util'); - - /** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ - function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine === undefined ? null : aLine; - this.column = aColumn === undefined ? null : aColumn; - this.source = aSource === undefined ? null : aSource; - this.name = aName === undefined ? null : aName; - if (aChunks != null) this.add(aChunks); - } - - /** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - */ - SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); - - // The generated code - // Processed fragments are removed from this array. - var remainingLines = aGeneratedCode.split('\n'); - - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; - - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping === null) { - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(remainingLines.shift() + "\n"); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - } else { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - var code = ""; - // Associate full lines with "lastMapping" - do { - code += remainingLines.shift() + "\n"; - lastGeneratedLine++; - lastGeneratedColumn = 0; - } while (lastGeneratedLine < mapping.generatedLine); - // When we reached the correct line, we add code until we - // reach the correct column too. - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - code += nextLine.substr(0, mapping.generatedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - // Create the SourceNode. - addMappingWithCode(lastMapping, code); - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[0]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - } - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - // Associate the remaining code in the current line with "lastMapping" - // and add the remaining lines without any mapping - addMappingWithCode(lastMapping, remainingLines.join("\n")); - - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - node.setSourceContent(sourceFile, content); - } - }); - - return node; - - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - mapping.source, - code, - mapping.name)); - } - } - }; - - /** - * Add a chunk of generated JS to this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ - SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); - } - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; - }; - - /** - * Add a chunk of generated JS to the beginning of this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ - SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - this.children.unshift(aChunk); - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; - }; - - /** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk instanceof SourceNode) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { - aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); - } - } - } - }; - - /** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ - SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; - }; - - /** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ - SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild instanceof SourceNode) { - lastChild.replaceRight(aPattern, aReplacement); - } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } - else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; - }; - - /** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ - SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - - /** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { - if (this.children[i] instanceof SourceNode) { - this.children[i].walkSourceContents(aFn); - } - } - - 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]]); - } - }; - - /** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ - SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; - }; - - /** - * Returns the string representation of this source node along with a source - * map. - */ - SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - 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) { - 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({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - chunk.split('').forEach(function (ch) { - if (ch === '\n') { - generated.line++; - generated.column = 0; - } else { - generated.column++; - } - }); - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - - return { code: generated.code, map: map }; - }; - - exports.SourceNode = SourceNode; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/////////////////////////////////////////////////////////////////////////////// - -window.sourceMap = { - SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, - SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, - SourceNode: require('source-map/source-node').SourceNode -}; -// Generated by CommonJS Everywhere 0.8.1 -(function (global) { - function require(file, parentModule) { - if ({}.hasOwnProperty.call(require.cache, file)) - return require.cache[file]; - var resolved = require.resolve(file); - if (!resolved) - throw new Error('Failed to resolve module ' + file); - var module$ = { - id: file, - require: require, - filename: file, - exports: {}, - loaded: false, - parent: parentModule, - children: [] - }; - if (parentModule) - parentModule.children.push(module$); - var dirname = file.slice(0, file.lastIndexOf('/') + 1); - require.cache[file] = module$.exports; - resolved.call(module$.exports, module$, module$.exports, dirname, file); - module$.loaded = true; - return require.cache[file] = module$.exports; - } - require.modules = {}; - require.cache = {}; - require.resolve = function (file) { - return {}.hasOwnProperty.call(require.modules, file) ? require.modules[file] : void 0; - }; - require.define = function (file, fn) { - require.modules[file] = fn; - }; - var process = function () { - var cwd = '/'; - return { - title: 'browser', - version: 'v0.10.5', - browser: true, - env: {}, - argv: [], - nextTick: global.setImmediate || function (fn) { - setTimeout(fn, 0); - }, - cwd: function () { - return cwd; - }, - chdir: function (dir) { - cwd = dir; - } - }; - }(); - require.define('/tools/entry-point.js', function (module, exports, __dirname, __filename) { - (function () { - 'use strict'; - global.escodegen = require('/escodegen.js', module); - escodegen.browser = true; - }()); - }); - require.define('/escodegen.js', function (module, exports, __dirname, __filename) { - (function () { - 'use strict'; - var Syntax, Precedence, BinaryPrecedence, Regex, SourceNode, estraverse, isArray, base, indent, json, renumber, hexadecimal, quotes, escapeless, newline, space, parentheses, semicolons, safeConcatenation, directive, extra, parse, sourceMap, FORMAT_MINIFY, FORMAT_DEFAULTS; - estraverse = require('/node_modules/estraverse/estraverse.js', module); - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - ArrowFunctionExpression: 'ArrowFunctionExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ComprehensionBlock: 'ComprehensionBlock', - ComprehensionExpression: 'ComprehensionExpression', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - Precedence = { - Sequence: 0, - Assignment: 1, - Conditional: 2, - ArrowFunction: 2, - LogicalOR: 3, - LogicalAND: 4, - BitwiseOR: 5, - BitwiseXOR: 6, - BitwiseAND: 7, - Equality: 8, - Relational: 9, - BitwiseSHIFT: 10, - Additive: 11, - Multiplicative: 12, - Unary: 13, - Postfix: 14, - Call: 15, - New: 16, - Member: 17, - Primary: 18 - }; - BinaryPrecedence = { - '||': Precedence.LogicalOR, - '&&': Precedence.LogicalAND, - '|': Precedence.BitwiseOR, - '^': Precedence.BitwiseXOR, - '&': Precedence.BitwiseAND, - '==': Precedence.Equality, - '!=': Precedence.Equality, - '===': Precedence.Equality, - '!==': Precedence.Equality, - 'is': Precedence.Equality, - 'isnt': Precedence.Equality, - '<': Precedence.Relational, - '>': Precedence.Relational, - '<=': Precedence.Relational, - '>=': Precedence.Relational, - 'in': Precedence.Relational, - 'instanceof': Precedence.Relational, - '<<': Precedence.BitwiseSHIFT, - '>>': Precedence.BitwiseSHIFT, - '>>>': Precedence.BitwiseSHIFT, - '+': Precedence.Additive, - '-': Precedence.Additive, - '*': Precedence.Multiplicative, - '%': Precedence.Multiplicative, - '/': Precedence.Multiplicative - }; - Regex = { 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]') }; - function getDefaultOptions() { - return { - indent: null, - base: null, - parse: null, - comment: false, - format: { - indent: { - style: ' ', - base: 0, - adjustMultilineComment: false - }, - newline: '\n', - space: ' ', - json: false, - renumber: false, - hexadecimal: false, - quotes: 'single', - escapeless: false, - compact: false, - parentheses: true, - semicolons: true, - safeConcatenation: false - }, - moz: { - starlessGenerator: false, - parenthesizedComprehensionBlock: false - }, - sourceMap: null, - sourceMapRoot: null, - sourceMapWithCode: false, - directive: false, - verbatim: null - }; - } - function stringToArray(str) { - var length = str.length, result = [], i; - for (i = 0; i < length; i += 1) { - result[i] = str.charAt(i); - } - return result; - } - function stringRepeat(str, num) { - var result = ''; - for (num |= 0; num > 0; num >>>= 1, str += str) { - if (num & 1) { - result += str; - } - } - return result; - } - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - function SourceNodeMock(line, column, filename, chunk) { - var result = []; - function flatten(input) { - var i, iz; - if (isArray(input)) { - for (i = 0, iz = input.length; i < iz; ++i) { - flatten(input[i]); - } - } else if (input instanceof SourceNodeMock) { - result.push(input); - } else if (typeof input === 'string' && input) { - result.push(input); - } - } - flatten(chunk); - this.children = result; - } - SourceNodeMock.prototype.toString = function toString() { - var res = '', i, iz, node; - for (i = 0, iz = this.children.length; i < iz; ++i) { - node = this.children[i]; - if (node instanceof SourceNodeMock) { - res += node.toString(); - } else { - res += node; - } - } - return res; - }; - SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) { - var last = this.children[this.children.length - 1]; - if (last instanceof SourceNodeMock) { - last.replaceRight(pattern, replacement); - } else if (typeof last === 'string') { - this.children[this.children.length - 1] = last.replace(pattern, replacement); - } else { - this.children.push(''.replace(pattern, replacement)); - } - return this; - }; - SourceNodeMock.prototype.join = function join(sep) { - var i, iz, result; - result = []; - iz = this.children.length; - if (iz > 0) { - for (i = 0, iz -= 1; i < iz; ++i) { - result.push(this.children[i], sep); - } - result.push(this.children[iz]); - this.children = result; - } - return this; - }; - function hasLineTerminator(str) { - return /[\r\n]/g.test(str); - } - function endsWithLineTerminator(str) { - var ch = str.charAt(str.length - 1); - return ch === '\r' || ch === '\n'; - } - function updateDeeply(target, override) { - var key, val; - function isHashObject(target) { - return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); - } - for (key in override) { - if (override.hasOwnProperty(key)) { - val = override[key]; - if (isHashObject(val)) { - if (isHashObject(target[key])) { - updateDeeply(target[key], val); - } else { - target[key] = updateDeeply({}, val); - } - } else { - target[key] = val; - } - } - } - return target; - } - function generateNumber(value) { - var result, point, temp, exponent, pos; - if (value !== value) { - throw new Error('Numeric literal whose value is NaN'); - } - if (value < 0 || value === 0 && 1 / value < 0) { - throw new Error('Numeric literal whose value is negative'); - } - if (value === 1 / 0) { - return json ? 'null' : renumber ? '1e400' : '1e+400'; - } - result = '' + value; - if (!renumber || result.length < 3) { - return result; - } - point = result.indexOf('.'); - if (!json && result.charAt(0) === '0' && point === 1) { - point = 0; - result = result.slice(1); - } - temp = result; - result = result.replace('e+', 'e'); - exponent = 0; - if ((pos = temp.indexOf('e')) > 0) { - exponent = +temp.slice(pos + 1); - temp = temp.slice(0, pos); - } - if (point >= 0) { - exponent -= temp.length - point - 1; - temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; - } - pos = 0; - while (temp.charAt(temp.length + pos - 1) === '0') { - pos -= 1; - } - if (pos !== 0) { - exponent -= pos; - temp = temp.slice(0, pos); - } - if (exponent !== 0) { - temp += 'e' + exponent; - } - if ((temp.length < result.length || hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length) && +temp === value) { - result = temp; - } - return result; - } - function escapeRegExpCharacter(ch, previousIsBackslash) { - if ((ch & ~1) === 8232) { - return (previousIsBackslash ? 'u' : '\\u') + (ch === 8232 ? '2028' : '2029'); - } else if (ch === 10 || ch === 13) { - return (previousIsBackslash ? '' : '\\') + (ch === 10 ? 'n' : 'r'); - } - return String.fromCharCode(ch); - } - function generateRegExp(reg) { - var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash; - result = reg.toString(); - if (reg.source) { - match = result.match(/\/([^/]*)$/); - if (!match) { - return result; - } - flags = match[1]; - result = ''; - characterInBrack = false; - previousIsBackslash = false; - for (i = 0, iz = reg.source.length; i < iz; ++i) { - ch = reg.source.charCodeAt(i); - if (!previousIsBackslash) { - if (characterInBrack) { - if (ch === 93) { - characterInBrack = false; - } - } else { - if (ch === 47) { - result += '\\'; - } else if (ch === 91) { - characterInBrack = true; - } - } - result += escapeRegExpCharacter(ch, previousIsBackslash); - previousIsBackslash = ch === 92; - } else { - result += escapeRegExpCharacter(ch, previousIsBackslash); - previousIsBackslash = false; - } - } - return '/' + result + '/' + flags; - } - return result; - } - function escapeAllowedCharacter(ch, next) { - var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; - switch (ch) { - case '\b': - result += 'b'; - break; - case '\f': - result += 'f'; - break; - case '\t': - result += 't'; - break; - default: - if (json || code > 255) { - result += 'u' + '0000'.slice(hex.length) + hex; - } else if (ch === '\0' && '0123456789'.indexOf(next) < 0) { - result += '0'; - } else if (ch === '\x0B') { - result += 'x0B'; - } else { - result += 'x' + '00'.slice(hex.length) + hex; - } - break; - } - return result; - } - function escapeDisallowedCharacter(ch) { - var result = '\\'; - switch (ch) { - case '\\': - result += '\\'; - break; - case '\n': - result += 'n'; - break; - case '\r': - result += 'r'; - break; - case '\u2028': - result += 'u2028'; - break; - case '\u2029': - result += 'u2029'; - break; - default: - throw new Error('Incorrectly classified character'); - } - return result; - } - function escapeDirective(str) { - var i, iz, ch, buf, quote; - buf = str; - if (typeof buf[0] === 'undefined') { - buf = stringToArray(buf); - } - quote = quotes === 'double' ? '"' : "'"; - for (i = 0, iz = buf.length; i < iz; i += 1) { - ch = buf[i]; - if (ch === "'") { - quote = '"'; - break; - } else if (ch === '"') { - quote = "'"; - break; - } else if (ch === '\\') { - i += 1; - } - } - return quote + str + quote; - } - function escapeString(str) { - var result = '', i, len, ch, singleQuotes = 0, doubleQuotes = 0, single; - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if (ch === "'") { - singleQuotes += 1; - } else if (ch === '"') { - doubleQuotes += 1; - } else if (ch === '/' && json) { - result += '\\'; - } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { - result += escapeDisallowedCharacter(ch); - continue; - } else if (json && ch < ' ' || !(json || escapeless || ch >= ' ' && ch <= '~')) { - result += escapeAllowedCharacter(ch, str[i + 1]); - continue; - } - result += ch; - } - single = !(quotes === 'double' || quotes === 'auto' && doubleQuotes < singleQuotes); - str = result; - result = single ? "'" : '"'; - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if (ch === "'" && single || ch === '"' && !single) { - result += '\\'; - } - result += ch; - } - return result + (single ? "'" : '"'); - } - function isWhiteSpace(ch) { - return '\t\x0B\f \xa0'.indexOf(ch) >= 0 || ch.charCodeAt(0) >= 5760 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0; - } - function isLineTerminator(ch) { - return '\n\r\u2028\u2029'.indexOf(ch) >= 0; - } - function isIdentifierPart(ch) { - return ch === '$' || ch === '_' || ch === '\\' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch.charCodeAt(0) >= 128 && Regex.NonAsciiIdentifierPart.test(ch); - } - function isDecimalDigit(ch) { - return ch >= 48 && ch <= 57; - } - function toSourceNode(generated, node) { - if (node == null) { - if (generated instanceof SourceNode) { - return generated; - } else { - node = {}; - } - } - if (node.loc == null) { - return new SourceNode(null, null, sourceMap, generated, node.name || null); - } - return new SourceNode(node.loc.start.line, node.loc.start.column, sourceMap === true ? node.loc.source || null : sourceMap, generated, node.name || null); - } - function noEmptySpace() { - return space ? space : ' '; - } - function join(left, right) { - var leftSource = toSourceNode(left).toString(), rightSource = toSourceNode(right).toString(), leftChar = leftSource.charAt(leftSource.length - 1), rightChar = rightSource.charAt(0); - if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar) || leftChar === '/' && rightChar === 'i') { - return [ - left, - noEmptySpace(), - right - ]; - } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { - return [ - left, - right - ]; - } - return [ - left, - space, - right - ]; - } - function addIndent(stmt) { - return [ - base, - stmt - ]; - } - function withIndent(fn) { - var previousBase, result; - previousBase = base; - base += indent; - result = fn.call(this, base); - base = previousBase; - return result; - } - function calculateSpaces(str) { - var i; - for (i = str.length - 1; i >= 0; i -= 1) { - if (isLineTerminator(str.charAt(i))) { - break; - } - } - return str.length - 1 - i; - } - function adjustMultilineComment(value, specialBase) { - var array, i, len, line, j, spaces, previousBase; - array = value.split(/\r\n|[\r\n]/); - spaces = Number.MAX_VALUE; - for (i = 1, len = array.length; i < len; i += 1) { - line = array[i]; - j = 0; - while (j < line.length && isWhiteSpace(line[j])) { - j += 1; - } - if (spaces > j) { - spaces = j; - } - } - if (typeof specialBase !== 'undefined') { - previousBase = base; - if (array[1][spaces] === '*') { - specialBase += ' '; - } - base = specialBase; - } else { - if (spaces & 1) { - spaces -= 1; - } - previousBase = base; - } - for (i = 1, len = array.length; i < len; i += 1) { - array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join(''); - } - base = previousBase; - return array.join('\n'); - } - function generateComment(comment, specialBase) { - if (comment.type === 'Line') { - if (endsWithLineTerminator(comment.value)) { - return '//' + comment.value; - } else { - return '//' + comment.value + '\n'; - } - } - if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { - return adjustMultilineComment('/*' + comment.value + '*/', specialBase); - } - return '/*' + comment.value + '*/'; - } - function addCommentsToStatement(stmt, result) { - var i, len, comment, save, tailingToStatement, specialBase, fragment; - if (stmt.leadingComments && stmt.leadingComments.length > 0) { - save = result; - comment = stmt.leadingComments[0]; - result = []; - if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { - result.push('\n'); - } - result.push(generateComment(comment)); - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push('\n'); - } - for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { - comment = stmt.leadingComments[i]; - fragment = [generateComment(comment)]; - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - fragment.push('\n'); - } - result.push(addIndent(fragment)); - } - result.push(addIndent(save)); - } - if (stmt.trailingComments) { - tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString()); - specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([ - base, - result, - indent - ]).toString())); - for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { - comment = stmt.trailingComments[i]; - if (tailingToStatement) { - if (i === 0) { - result = [ - result, - indent - ]; - } else { - result = [ - result, - specialBase - ]; - } - result.push(generateComment(comment, specialBase)); - } else { - result = [ - result, - addIndent(generateComment(comment)) - ]; - } - if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) { - result = [ - result, - '\n' - ]; - } - } - } - return result; - } - function parenthesize(text, current, should) { - if (current < should) { - return [ - '(', - text, - ')' - ]; - } - return text; - } - function maybeBlock(stmt, semicolonOptional, functionBody) { - var result, noLeadingComment; - noLeadingComment = !extra.comment || !stmt.leadingComments; - if (stmt.type === Syntax.BlockStatement && noLeadingComment) { - return [ - space, - generateStatement(stmt, { functionBody: functionBody }) - ]; - } - if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { - return ';'; - } - withIndent(function () { - result = [ - newline, - addIndent(generateStatement(stmt, { - semicolonOptional: semicolonOptional, - functionBody: functionBody - })) - ]; - }); - return result; - } - function maybeBlockSuffix(stmt, result) { - var ends = endsWithLineTerminator(toSourceNode(result).toString()); - if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) { - return [ - result, - space - ]; - } - if (ends) { - return [ - result, - base - ]; - } - return [ - result, - newline, - base - ]; - } - function generateVerbatim(expr, option) { - var i, result; - result = expr[extra.verbatim].split(/\r\n|\n/); - for (i = 1; i < result.length; i++) { - result[i] = newline + base + result[i]; - } - result = parenthesize(result, Precedence.Sequence, option.precedence); - return toSourceNode(result, expr); - } - function generateIdentifier(node) { - return toSourceNode(node.name, node); - } - function generateFunctionBody(node) { - var result, i, len, expr, arrow; - arrow = node.type === Syntax.ArrowFunctionExpression; - if (arrow && node.params.length === 1 && node.params[0].type === Syntax.Identifier) { - result = [generateIdentifier(node.params[0])]; - } else { - result = ['(']; - for (i = 0, len = node.params.length; i < len; i += 1) { - result.push(generateIdentifier(node.params[i])); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - } - if (arrow) { - result.push(space, '=>'); - } - if (node.expression) { - result.push(space); - expr = generateExpression(node.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }); - if (expr.toString().charAt(0) === '{') { - expr = [ - '(', - expr, - ')' - ]; - } - result.push(expr); - } else { - result.push(maybeBlock(node.body, false, true)); - } - return result; - } - function generateExpression(expr, option) { - var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, allowIn, allowCall, allowUnparenthesizedNew, property; - precedence = option.precedence; - allowIn = option.allowIn; - allowCall = option.allowCall; - type = expr.type || option.type; - if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { - return generateVerbatim(expr, option); - } - switch (type) { - case Syntax.SequenceExpression: - result = []; - allowIn |= Precedence.Sequence < precedence; - for (i = 0, len = expr.expressions.length; i < len; i += 1) { - result.push(generateExpression(expr.expressions[i], { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result = parenthesize(result, Precedence.Sequence, precedence); - break; - case Syntax.AssignmentExpression: - allowIn |= Precedence.Assignment < precedence; - result = parenthesize([ - generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: allowIn, - allowCall: true - }), - space + expr.operator + space, - generateExpression(expr.right, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], Precedence.Assignment, precedence); - break; - case Syntax.ArrowFunctionExpression: - allowIn |= Precedence.ArrowFunction < precedence; - result = parenthesize(generateFunctionBody(expr), Precedence.ArrowFunction, precedence); - break; - case Syntax.ConditionalExpression: - allowIn |= Precedence.Conditional < precedence; - result = parenthesize([ - generateExpression(expr.test, { - precedence: Precedence.LogicalOR, - allowIn: allowIn, - allowCall: true - }), - space + '?' + space, - generateExpression(expr.consequent, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space + ':' + space, - generateExpression(expr.alternate, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], Precedence.Conditional, precedence); - break; - case Syntax.LogicalExpression: - case Syntax.BinaryExpression: - currentPrecedence = BinaryPrecedence[expr.operator]; - allowIn |= currentPrecedence < precedence; - fragment = generateExpression(expr.left, { - precedence: currentPrecedence, - allowIn: allowIn, - allowCall: true - }); - leftSource = fragment.toString(); - if (leftSource.charAt(leftSource.length - 1) === '/' && isIdentifierPart(expr.operator.charAt(0))) { - result = [ - fragment, - noEmptySpace(), - expr.operator - ]; - } else { - result = join(fragment, expr.operator); - } - fragment = generateExpression(expr.right, { - precedence: currentPrecedence + 1, - allowIn: allowIn, - allowCall: true - }); - if (expr.operator === '/' && fragment.toString().charAt(0) === '/' || expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') { - result.push(noEmptySpace(), fragment); - } else { - result = join(result, fragment); - } - if (expr.operator === 'in' && !allowIn) { - result = [ - '(', - result, - ')' - ]; - } else { - result = parenthesize(result, currentPrecedence, precedence); - } - break; - case Syntax.CallExpression: - result = [generateExpression(expr.callee, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true, - allowUnparenthesizedNew: false - })]; - result.push('('); - for (i = 0, len = expr['arguments'].length; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - if (!allowCall) { - result = [ - '(', - result, - ')' - ]; - } else { - result = parenthesize(result, Precedence.Call, precedence); - } - break; - case Syntax.NewExpression: - len = expr['arguments'].length; - allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; - result = join('new', generateExpression(expr.callee, { - precedence: Precedence.New, - allowIn: true, - allowCall: false, - allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 - })); - if (!allowUnparenthesizedNew || parentheses || len > 0) { - result.push('('); - for (i = 0; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - } - result = parenthesize(result, Precedence.New, precedence); - break; - case Syntax.MemberExpression: - result = [generateExpression(expr.object, { - precedence: Precedence.Call, - allowIn: true, - allowCall: allowCall, - allowUnparenthesizedNew: false - })]; - if (expr.computed) { - result.push('[', generateExpression(expr.property, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: allowCall - }), ']'); - } else { - if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { - fragment = toSourceNode(result).toString(); - if (fragment.indexOf('.') < 0 && !/[eExX]/.test(fragment) && isDecimalDigit(fragment.charCodeAt(fragment.length - 1)) && !(fragment.length >= 2 && fragment.charCodeAt(0) === 48)) { - result.push('.'); - } - } - result.push('.', generateIdentifier(expr.property)); - } - result = parenthesize(result, Precedence.Member, precedence); - break; - case Syntax.UnaryExpression: - fragment = generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }); - if (space === '') { - result = join(expr.operator, fragment); - } else { - result = [expr.operator]; - if (expr.operator.length > 2) { - result = join(result, fragment); - } else { - leftSource = toSourceNode(result).toString(); - leftChar = leftSource.charAt(leftSource.length - 1); - rightChar = fragment.toString().charAt(0); - if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar)) { - result.push(noEmptySpace(), fragment); - } else { - result.push(fragment); - } - } - } - result = parenthesize(result, Precedence.Unary, precedence); - break; - case Syntax.YieldExpression: - if (expr.delegate) { - result = 'yield*'; - } else { - result = 'yield'; - } - if (expr.argument) { - result = join(result, generateExpression(expr.argument, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - } - break; - case Syntax.UpdateExpression: - if (expr.prefix) { - result = parenthesize([ - expr.operator, - generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }) - ], Precedence.Unary, precedence); - } else { - result = parenthesize([ - generateExpression(expr.argument, { - precedence: Precedence.Postfix, - allowIn: true, - allowCall: true - }), - expr.operator - ], Precedence.Postfix, precedence); - } - break; - case Syntax.FunctionExpression: - result = 'function'; - if (expr.id) { - result = [ - result, - noEmptySpace(), - generateIdentifier(expr.id), - generateFunctionBody(expr) - ]; - } else { - result = [ - result + space, - generateFunctionBody(expr) - ]; - } - break; - case Syntax.ArrayPattern: - case Syntax.ArrayExpression: - if (!expr.elements.length) { - result = '[]'; - break; - } - multiline = expr.elements.length > 1; - result = [ - '[', - multiline ? newline : '' - ]; - withIndent(function (indent) { - for (i = 0, len = expr.elements.length; i < len; i += 1) { - if (!expr.elements[i]) { - if (multiline) { - result.push(indent); - } - if (i + 1 === len) { - result.push(','); - } - } else { - result.push(multiline ? indent : '', generateExpression(expr.elements[i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - } - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', ']'); - break; - case Syntax.Property: - if (expr.kind === 'get' || expr.kind === 'set') { - result = [ - expr.kind, - noEmptySpace(), - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - generateFunctionBody(expr.value) - ]; - } else { - if (expr.shorthand) { - result = generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - } else if (expr.method) { - result = []; - if (expr.value.generator) { - result.push('*'); - } - result.push(generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), generateFunctionBody(expr.value)); - } else { - result = [ - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ':' + space, - generateExpression(expr.value, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - } - } - break; - case Syntax.ObjectExpression: - if (!expr.properties.length) { - result = '{}'; - break; - } - multiline = expr.properties.length > 1; - withIndent(function () { - fragment = generateExpression(expr.properties[0], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - }); - }); - if (!multiline) { - if (!hasLineTerminator(toSourceNode(fragment).toString())) { - result = [ - '{', - space, - fragment, - space, - '}' - ]; - break; - } - } - withIndent(function (indent) { - result = [ - '{', - newline, - indent, - fragment - ]; - if (multiline) { - result.push(',' + newline); - for (i = 1, len = expr.properties.length; i < len; i += 1) { - result.push(indent, generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - })); - if (i + 1 < len) { - result.push(',' + newline); - } - } - } - }); - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(base, '}'); - break; - case Syntax.ObjectPattern: - if (!expr.properties.length) { - result = '{}'; - break; - } - multiline = false; - if (expr.properties.length === 1) { - property = expr.properties[0]; - if (property.value.type !== Syntax.Identifier) { - multiline = true; - } - } else { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - property = expr.properties[i]; - if (!property.shorthand) { - multiline = true; - break; - } - } - } - result = [ - '{', - multiline ? newline : '' - ]; - withIndent(function (indent) { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - result.push(multiline ? indent : '', generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', '}'); - break; - case Syntax.ThisExpression: - result = 'this'; - break; - case Syntax.Identifier: - result = generateIdentifier(expr); - break; - case Syntax.Literal: - if (expr.hasOwnProperty('raw') && parse) { - try { - raw = parse(expr.raw).body[0].expression; - if (raw.type === Syntax.Literal) { - if (raw.value === expr.value) { - result = expr.raw; - break; - } - } - } catch (e) { - } - } - if (expr.value === null) { - result = 'null'; - break; - } - if (typeof expr.value === 'string') { - result = escapeString(expr.value); - break; - } - if (typeof expr.value === 'number') { - result = generateNumber(expr.value); - break; - } - if (typeof expr.value === 'boolean') { - result = expr.value ? 'true' : 'false'; - break; - } - result = generateRegExp(expr.value); - break; - case Syntax.ComprehensionExpression: - result = [ - '[', - generateExpression(expr.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - if (expr.blocks) { - for (i = 0, len = expr.blocks.length; i < len; i += 1) { - fragment = generateExpression(expr.blocks[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - result = join(result, fragment); - } - } - if (expr.filter) { - result = join(result, 'if' + space); - fragment = generateExpression(expr.filter, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - if (extra.moz.parenthesizedComprehensionBlock) { - result = join(result, [ - '(', - fragment, - ')' - ]); - } else { - result = join(result, fragment); - } - } - result.push(']'); - break; - case Syntax.ComprehensionBlock: - if (expr.left.type === Syntax.VariableDeclaration) { - fragment = [ - expr.left.kind, - noEmptySpace(), - generateStatement(expr.left.declarations[0], { allowIn: false }) - ]; - } else { - fragment = generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - }); - } - fragment = join(fragment, expr.of ? 'of' : 'in'); - fragment = join(fragment, generateExpression(expr.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - if (extra.moz.parenthesizedComprehensionBlock) { - result = [ - 'for' + space + '(', - fragment, - ')' - ]; - } else { - result = join('for' + space, fragment); - } - break; - default: - throw new Error('Unknown expression type: ' + expr.type); - } - return toSourceNode(result, expr); - } - function generateStatement(stmt, option) { - var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon; - allowIn = true; - semicolon = ';'; - functionBody = false; - directiveContext = false; - if (option) { - allowIn = option.allowIn === undefined || option.allowIn; - if (!semicolons && option.semicolonOptional === true) { - semicolon = ''; - } - functionBody = option.functionBody; - directiveContext = option.directiveContext; - } - switch (stmt.type) { - case Syntax.BlockStatement: - result = [ - '{', - newline - ]; - withIndent(function () { - for (i = 0, len = stmt.body.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.body[i], { - semicolonOptional: i === len - 1, - directiveContext: functionBody - })); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - result.push(addIndent('}')); - break; - case Syntax.BreakStatement: - if (stmt.label) { - result = 'break ' + stmt.label.name + semicolon; - } else { - result = 'break' + semicolon; - } - break; - case Syntax.ContinueStatement: - if (stmt.label) { - result = 'continue ' + stmt.label.name + semicolon; - } else { - result = 'continue' + semicolon; - } - break; - case Syntax.DirectiveStatement: - if (stmt.raw) { - result = stmt.raw + semicolon; - } else { - result = escapeDirective(stmt.directive) + semicolon; - } - break; - case Syntax.DoWhileStatement: - result = join('do', maybeBlock(stmt.body)); - result = maybeBlockSuffix(stmt.body, result); - result = join(result, [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + semicolon - ]); - break; - case Syntax.CatchClause: - withIndent(function () { - result = [ - 'catch' + space + '(', - generateExpression(stmt.param, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body)); - break; - case Syntax.DebuggerStatement: - result = 'debugger' + semicolon; - break; - case Syntax.EmptyStatement: - result = ';'; - break; - case Syntax.ExpressionStatement: - result = [generateExpression(stmt.expression, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })]; - fragment = toSourceNode(result).toString(); - if (fragment.charAt(0) === '{' || fragment.slice(0, 8) === 'function' && ' ('.indexOf(fragment.charAt(8)) >= 0 || directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string') { - result = [ - '(', - result, - ')' + semicolon - ]; - } else { - result.push(semicolon); - } - break; - case Syntax.VariableDeclarator: - if (stmt.init) { - result = [ - generateExpression(stmt.id, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space, - '=', - space, - generateExpression(stmt.init, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ]; - } else { - result = generateIdentifier(stmt.id); - } - break; - case Syntax.VariableDeclaration: - result = [stmt.kind]; - if (stmt.declarations.length === 1 && stmt.declarations[0].init && stmt.declarations[0].init.type === Syntax.FunctionExpression) { - result.push(noEmptySpace(), generateStatement(stmt.declarations[0], { allowIn: allowIn })); - } else { - withIndent(function () { - node = stmt.declarations[0]; - if (extra.comment && node.leadingComments) { - result.push('\n', addIndent(generateStatement(node, { allowIn: allowIn }))); - } else { - result.push(noEmptySpace(), generateStatement(node, { allowIn: allowIn })); - } - for (i = 1, len = stmt.declarations.length; i < len; i += 1) { - node = stmt.declarations[i]; - if (extra.comment && node.leadingComments) { - result.push(',' + newline, addIndent(generateStatement(node, { allowIn: allowIn }))); - } else { - result.push(',' + space, generateStatement(node, { allowIn: allowIn })); - } - } - }); - } - result.push(semicolon); - break; - case Syntax.ThrowStatement: - result = [ - join('throw', generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - semicolon - ]; - break; - case Syntax.TryStatement: - result = [ - 'try', - maybeBlock(stmt.block) - ]; - result = maybeBlockSuffix(stmt.block, result); - if (stmt.handlers) { - for (i = 0, len = stmt.handlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.handlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.handlers[i].body, result); - } - } - } else { - if (stmt.handler) { - result = join(result, generateStatement(stmt.handler)); - if (stmt.finalizer || stmt.guardedHandlers.length > 0) { - result = maybeBlockSuffix(stmt.handler.body, result); - } - } - for (i = 0, len = stmt.guardedHandlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.guardedHandlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.guardedHandlers[i].body, result); - } - } - } - if (stmt.finalizer) { - result = join(result, [ - 'finally', - maybeBlock(stmt.finalizer) - ]); - } - break; - case Syntax.SwitchStatement: - withIndent(function () { - result = [ - 'switch' + space + '(', - generateExpression(stmt.discriminant, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + space + '{' + newline - ]; - }); - if (stmt.cases) { - for (i = 0, len = stmt.cases.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.cases[i], { semicolonOptional: i === len - 1 })); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - } - result.push(addIndent('}')); - break; - case Syntax.SwitchCase: - withIndent(function () { - if (stmt.test) { - result = [ - join('case', generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - ':' - ]; - } else { - result = ['default:']; - } - i = 0; - len = stmt.consequent.length; - if (len && stmt.consequent[0].type === Syntax.BlockStatement) { - fragment = maybeBlock(stmt.consequent[0]); - result.push(fragment); - i = 1; - } - if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - for (; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.consequent[i], { semicolonOptional: i === len - 1 && semicolon === '' })); - result.push(fragment); - if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - break; - case Syntax.IfStatement: - withIndent(function () { - result = [ - 'if' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - if (stmt.alternate) { - result.push(maybeBlock(stmt.consequent)); - result = maybeBlockSuffix(stmt.consequent, result); - if (stmt.alternate.type === Syntax.IfStatement) { - result = join(result, [ - 'else ', - generateStatement(stmt.alternate, { semicolonOptional: semicolon === '' }) - ]); - } else { - result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === ''))); - } - } else { - result.push(maybeBlock(stmt.consequent, semicolon === '')); - } - break; - case Syntax.ForStatement: - withIndent(function () { - result = ['for' + space + '(']; - if (stmt.init) { - if (stmt.init.type === Syntax.VariableDeclaration) { - result.push(generateStatement(stmt.init, { allowIn: false })); - } else { - result.push(generateExpression(stmt.init, { - precedence: Precedence.Sequence, - allowIn: false, - allowCall: true - }), ';'); - } - } else { - result.push(';'); - } - if (stmt.test) { - result.push(space, generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ';'); - } else { - result.push(';'); - } - if (stmt.update) { - result.push(space, generateExpression(stmt.update, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ')'); - } else { - result.push(')'); - } - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - case Syntax.ForInStatement: - result = ['for' + space + '(']; - withIndent(function () { - if (stmt.left.type === Syntax.VariableDeclaration) { - withIndent(function () { - result.push(stmt.left.kind + noEmptySpace(), generateStatement(stmt.left.declarations[0], { allowIn: false })); - }); - } else { - result.push(generateExpression(stmt.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - })); - } - result = join(result, 'in'); - result = [ - join(result, generateExpression(stmt.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - case Syntax.LabeledStatement: - result = [ - stmt.label.name + ':', - maybeBlock(stmt.body, semicolon === '') - ]; - break; - case Syntax.Program: - len = stmt.body.length; - result = [safeConcatenation && len > 0 ? '\n' : '']; - for (i = 0; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.body[i], { - semicolonOptional: !safeConcatenation && i === len - 1, - directiveContext: true - })); - result.push(fragment); - if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - break; - case Syntax.FunctionDeclaration: - result = [ - stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function ', - generateIdentifier(stmt.id), - generateFunctionBody(stmt) - ]; - break; - case Syntax.ReturnStatement: - if (stmt.argument) { - result = [ - join('return', generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - semicolon - ]; - } else { - result = ['return' + semicolon]; - } - break; - case Syntax.WhileStatement: - withIndent(function () { - result = [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - case Syntax.WithStatement: - withIndent(function () { - result = [ - 'with' + space + '(', - generateExpression(stmt.object, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - default: - throw new Error('Unknown statement type: ' + stmt.type); - } - if (extra.comment) { - result = addCommentsToStatement(stmt, result); - } - fragment = toSourceNode(result).toString(); - if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') { - result = toSourceNode(result).replaceRight(/\s+$/, ''); - } - return toSourceNode(result, stmt); - } - function generate(node, options) { - var defaultOptions = getDefaultOptions(), result, pair; - if (options != null) { - if (typeof options.indent === 'string') { - defaultOptions.format.indent.style = options.indent; - } - if (typeof options.base === 'number') { - defaultOptions.format.indent.base = options.base; - } - options = updateDeeply(defaultOptions, options); - indent = options.format.indent.style; - if (typeof options.base === 'string') { - base = options.base; - } else { - base = stringRepeat(indent, options.format.indent.base); - } - } else { - options = defaultOptions; - indent = options.format.indent.style; - base = stringRepeat(indent, options.format.indent.base); - } - json = options.format.json; - renumber = options.format.renumber; - hexadecimal = json ? false : options.format.hexadecimal; - quotes = json ? 'double' : options.format.quotes; - escapeless = options.format.escapeless; - newline = options.format.newline; - space = options.format.space; - if (options.format.compact) { - newline = space = indent = base = ''; - } - parentheses = options.format.parentheses; - semicolons = options.format.semicolons; - safeConcatenation = options.format.safeConcatenation; - directive = options.directive; - parse = json ? null : options.parse; - sourceMap = options.sourceMap; - extra = options; - if (sourceMap) { - if (!exports.browser) { - SourceNode = require('/node_modules/source-map/lib/source-map.js', module).SourceNode; - } else { - SourceNode = global.sourceMap.SourceNode; - } - } else { - SourceNode = SourceNodeMock; - } - switch (node.type) { - case Syntax.BlockStatement: - case Syntax.BreakStatement: - case Syntax.CatchClause: - case Syntax.ContinueStatement: - case Syntax.DirectiveStatement: - case Syntax.DoWhileStatement: - case Syntax.DebuggerStatement: - case Syntax.EmptyStatement: - case Syntax.ExpressionStatement: - case Syntax.ForStatement: - case Syntax.ForInStatement: - case Syntax.FunctionDeclaration: - case Syntax.IfStatement: - case Syntax.LabeledStatement: - case Syntax.Program: - case Syntax.ReturnStatement: - case Syntax.SwitchStatement: - case Syntax.SwitchCase: - case Syntax.ThrowStatement: - case Syntax.TryStatement: - case Syntax.VariableDeclaration: - case Syntax.VariableDeclarator: - case Syntax.WhileStatement: - case Syntax.WithStatement: - result = generateStatement(node); - break; - case Syntax.AssignmentExpression: - case Syntax.ArrayExpression: - case Syntax.ArrayPattern: - case Syntax.BinaryExpression: - case Syntax.CallExpression: - case Syntax.ConditionalExpression: - case Syntax.FunctionExpression: - case Syntax.Identifier: - case Syntax.Literal: - case Syntax.LogicalExpression: - case Syntax.MemberExpression: - case Syntax.NewExpression: - case Syntax.ObjectExpression: - case Syntax.ObjectPattern: - case Syntax.Property: - case Syntax.SequenceExpression: - case Syntax.ThisExpression: - case Syntax.UnaryExpression: - case Syntax.UpdateExpression: - case Syntax.YieldExpression: - result = generateExpression(node, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - break; - default: - throw new Error('Unknown node type: ' + node.type); - } - if (!sourceMap) { - return result.toString(); - } - pair = result.toStringWithSourceMap({ - file: options.file, - sourceRoot: options.sourceMapRoot - }); - if (options.sourceMapWithCode) { - return pair; - } - return pair.map.toString(); - } - FORMAT_MINIFY = { - indent: { - style: '', - base: 0 - }, - renumber: true, - hexadecimal: true, - quotes: 'auto', - escapeless: true, - compact: true, - parentheses: false, - semicolons: false - }; - FORMAT_DEFAULTS = getDefaultOptions().format; - exports.version = require('/package.json', module).version; - exports.generate = generate; - exports.attachComments = estraverse.attachComments; - exports.browser = false; - exports.FORMAT_MINIFY = FORMAT_MINIFY; - exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS; - }()); - }); - require.define('/package.json', function (module, exports, __dirname, __filename) { - module.exports = { - 'name': 'escodegen', - 'description': 'ECMAScript code generator', - 'homepage': 'http://github.com/Constellation/escodegen.html', - 'main': 'escodegen.js', - 'bin': { - 'esgenerate': './bin/esgenerate.js', - 'escodegen': './bin/escodegen.js' - }, - 'version': '0.0.28-dev', - 'engines': { 'node': '>=0.4.0' }, - 'maintainers': [{ - 'name': 'Yusuke Suzuki', - 'email': 'utatane.tea@gmail.com', - 'web': 'http://github.com/Constellation' - }], - 'repository': { - 'type': 'git', - 'url': 'http://github.com/Constellation/escodegen.git' - }, - 'dependencies': { - 'esprima': '~1.0.2', - 'estraverse': '~1.3.0' - }, - 'optionalDependencies': { 'source-map': '>= 0.1.2' }, - 'devDependencies': { - 'esprima-moz': '*', - 'commonjs-everywhere': '~0.8.0', - 'q': '*', - 'bower': '*', - 'semver': '*', - 'chai': '~1.7.2', - 'grunt-contrib-jshint': '~0.5.0', - 'grunt-cli': '~0.1.9', - 'grunt': '~0.4.1', - 'grunt-mocha-test': '~0.6.2' - }, - 'licenses': [{ - 'type': 'BSD', - 'url': 'http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD' - }], - 'scripts': { - 'test': 'grunt travis', - 'unit-test': 'grunt test', - 'lint': 'grunt lint', - 'release': 'node tools/release.js', - 'build-min': './node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js', - 'build': './node_modules/.bin/cjsify -a path: tools/entry-point.js > escodegen.browser.js' - } - }; - }); - require.define('/node_modules/source-map/lib/source-map.js', function (module, exports, __dirname, __filename) { - exports.SourceMapGenerator = require('/node_modules/source-map/lib/source-map/source-map-generator.js', module).SourceMapGenerator; - exports.SourceMapConsumer = require('/node_modules/source-map/lib/source-map/source-map-consumer.js', module).SourceMapConsumer; - exports.SourceNode = require('/node_modules/source-map/lib/source-map/source-node.js', module).SourceNode; - }); - require.define('/node_modules/source-map/lib/source-map/source-node.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var SourceMapGenerator = require('/node_modules/source-map/lib/source-map/source-map-generator.js', module).SourceMapGenerator; - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine === undefined ? null : aLine; - this.column = aColumn === undefined ? null : aColumn; - this.source = aSource === undefined ? null : aSource; - this.name = aName === undefined ? null : aName; - if (aChunks != null) - this.add(aChunks); - } - SourceNode.fromStringWithSourceMap = function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { - var node = new SourceNode; - var remainingLines = aGeneratedCode.split('\n'); - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - var lastMapping = null; - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping === null) { - 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 (lastGeneratedLine < mapping.generatedLine) { - var code = ''; - do { - code += remainingLines.shift() + '\n'; - lastGeneratedLine++; - lastGeneratedColumn = 0; - } while (lastGeneratedLine < mapping.generatedLine); - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - code += nextLine.substr(0, mapping.generatedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - addMappingWithCode(lastMapping, code); - } else { - var nextLine = remainingLines[0]; - var code = nextLine.substr(0, mapping.generatedColumn - lastGeneratedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - } - } - lastMapping = mapping; - }, this); - addMappingWithCode(lastMapping, remainingLines.join('\n')); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - node.setSourceContent(sourceFile, content); - } - }); - return node; - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - node.add(new SourceNode(mapping.originalLine, mapping.originalColumn, mapping.source, code, mapping.name)); - } - } - }; - SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } else if (aChunk instanceof SourceNode || typeof aChunk === 'string') { - if (aChunk) { - this.children.push(aChunk); - } - } else { - throw new TypeError('Expected a SourceNode, string, or an array of SourceNodes and strings. Got ' + aChunk); - } - return this; - }; - SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length - 1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } else if (aChunk instanceof SourceNode || typeof aChunk === 'string') { - this.children.unshift(aChunk); - } else { - throw new TypeError('Expected a SourceNode, string, or an array of SourceNodes and strings. Got ' + aChunk); - } - return this; - }; - SourceNode.prototype.walk = function SourceNode_walk(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walk(aFn); - } else { - if (chunk !== '') { - aFn(chunk, { - source: this.source, - line: this.line, - column: this.column, - name: this.name - }); - } - } - }, this); - }; - SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len - 1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; - }; - SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild instanceof SourceNode) { - lastChild.replaceRight(aPattern, aReplacement); - } else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; - }; - SourceNode.prototype.setSourceContent = function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - SourceNode.prototype.walkSourceContents = function SourceNode_walkSourceContents(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walkSourceContents(aFn); - } - }, this); - Object.keys(this.sourceContents).forEach(function (sourceFileKey) { - aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); - }, this); - }; - SourceNode.prototype.toString = function SourceNode_toString() { - var str = ''; - this.walk(function (chunk) { - str += chunk; - }); - return str; - }; - SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: '', - line: 1, - column: 0 - }; - 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) { - 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({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - chunk.split('').forEach(function (ch) { - if (ch === '\n') { - generated.line++; - generated.column = 0; - } else { - generated.column++; - } - }); - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - return { - code: generated.code, - map: map - }; - }; - exports.SourceNode = SourceNode; - }); - }); - require.define('/node_modules/source-map/lib/source-map/util.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } - } - exports.getArg = getArg; - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] - }; - } - exports.urlParse = urlParse; - 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; - if (aPath.match(urlRegexp)) { - return aPath; - } - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); - } - return aRoot.replace(/\/$/, '') + '/' + aPath; - } - exports.join = join; - function toSetString(aStr) { - return '$' + aStr; - } - exports.toSetString = toSetString; - function fromSetString(aStr) { - return aStr.substr(1); - } - exports.fromSetString = fromSetString; - function relative(aRoot, aPath) { - aRoot = aRoot.replace(/\/$/, ''); - var url = urlParse(aRoot); - if (aPath.charAt(0) == '/' && url && url.path == '/') { - return aPath.slice(1); - } - return aPath.indexOf(aRoot + '/') === 0 ? aPath.substr(aRoot.length + 1) : aPath; - } - exports.relative = relative; - }); - }); - require.define('/node_modules/source-map/node_modules/amdefine/amdefine.js', function (module, exports, __dirname, __filename) { - 'use strict'; - function amdefine(module, requireFn) { - 'use strict'; - var defineCache = {}, loaderCache = {}, alreadyCalled = false, path = require('path', module), makeRequire, stringRequire; - 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] === '..')) { - break; - } else if (i > 0) { - ary.splice(i - 1, 2); - i -= 2; - } - } - } - } - function normalize(name, baseName) { - var baseParts; - if (name && name.charAt(0) === '.') { - if (baseName) { - baseParts = baseName.split('/'); - baseParts = baseParts.slice(0, baseParts.length - 1); - baseParts = baseParts.concat(name.split('/')); - trimDots(baseParts); - name = baseParts.join('/'); - } - } - return name; - } - function makeNormalize(relName) { - return function (name) { - return normalize(name, relName); - }; - } - function makeLoad(id) { - function load(value) { - loaderCache[id] = value; - } - load.fromText = function (id, text) { - throw new Error('amdefine does not implement load.fromText'); - }; - return load; - } - makeRequire = function (systemRequire, exports, module, relId) { - function amdRequire(deps, callback) { - if (typeof deps === 'string') { - return stringRequire(systemRequire, exports, module, deps, relId); - } else { - deps = deps.map(function (depName) { - return stringRequire(systemRequire, exports, module, depName, relId); - }); - process.nextTick(function () { - callback.apply(null, deps); - }); - } - } - amdRequire.toUrl = function (filePath) { - if (filePath.indexOf('.') === 0) { - return normalize(filePath, path.dirname(module.filename)); - } else { - return filePath; - } - }; - return amdRequire; - }; - requireFn = requireFn || function req() { - return module.require.apply(module, arguments); - }; - function runFactory(id, deps, factory) { - var r, e, m, result; - if (id) { - e = loaderCache[id] = {}; - m = { - id: id, - uri: __filename, - exports: e - }; - r = makeRequire(requireFn, e, m, id); - } else { - if (alreadyCalled) { - throw new Error('amdefine with no module ID cannot be called more than once per file.'); - } - alreadyCalled = true; - e = module.exports; - m = module; - r = makeRequire(requireFn, e, m, module.id); - } - if (deps) { - deps = deps.map(function (depName) { - return r(depName); - }); - } - if (typeof factory === 'function') { - result = factory.apply(m.exports, deps); - } else { - result = factory; - } - if (result !== undefined) { - m.exports = result; - if (id) { - loaderCache[id] = m.exports; - } - } - } - stringRequire = function (systemRequire, exports, module, id, relId) { - var index = id.indexOf('!'), originalId = id, prefix, plugin; - if (index === -1) { - id = normalize(id, relId); - if (id === 'require') { - return makeRequire(systemRequire, exports, module, relId); - } else if (id === 'exports') { - return exports; - } else if (id === 'module') { - return module; - } else if (loaderCache.hasOwnProperty(id)) { - return loaderCache[id]; - } else if (defineCache[id]) { - runFactory.apply(null, defineCache[id]); - return loaderCache[id]; - } else { - if (systemRequire) { - return systemRequire(originalId); - } else { - throw new Error('No module with ID: ' + id); - } - } - } else { - prefix = id.substring(0, index); - id = id.substring(index + 1, id.length); - plugin = stringRequire(systemRequire, exports, module, prefix, relId); - if (plugin.normalize) { - id = plugin.normalize(id, makeNormalize(relId)); - } else { - id = normalize(id, relId); - } - if (loaderCache[id]) { - return loaderCache[id]; - } else { - plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); - return loaderCache[id]; - } - } - }; - function define(id, deps, factory) { - if (Array.isArray(id)) { - factory = deps; - deps = id; - id = undefined; - } else if (typeof id !== 'string') { - factory = id; - id = deps = undefined; - } - if (deps && !Array.isArray(deps)) { - factory = deps; - deps = undefined; - } - if (!deps) { - deps = [ - 'require', - 'exports', - 'module' - ]; - } - if (id) { - defineCache[id] = [ - id, - deps, - factory - ]; - } else { - runFactory(id, deps, factory); - } - } - define.require = function (id) { - if (loaderCache[id]) { - return loaderCache[id]; - } - if (defineCache[id]) { - runFactory.apply(null, defineCache[id]); - return loaderCache[id]; - } - }; - define.amd = {}; - return define; - } - module.exports = amdefine; - }); - require.define('/node_modules/source-map/lib/source-map/source-map-generator.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var base64VLQ = require('/node_modules/source-map/lib/source-map/base64-vlq.js', module); - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - var ArraySet = require('/node_modules/source-map/lib/source-map/array-set.js', module).ArraySet; - function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._sources = new ArraySet; - this._names = new ArraySet; - this._mappings = []; - this._sourcesContents = null; - } - SourceMapGenerator.prototype._version = 3; - SourceMapGenerator.fromSourceMap = function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - if (mapping.source) { - newMapping.source = mapping.source; - if (sourceRoot) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - if (mapping.name) { - newMapping.name = mapping.name; - } - } - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - SourceMapGenerator.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - this._validateMapping(generated, original, source, name); - if (source && !this._sources.has(source)) { - this._sources.add(source); - } - if (name && !this._names.has(name)) { - this._names.add(name); - } - this._mappings.push({ - generated: generated, - original: original, - source: source, - name: name - }); - }; - SourceMapGenerator.prototype.setSourceContent = function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot) { - source = util.relative(this._sourceRoot, source); - } - if (aSourceContent !== null) { - if (!this._sourcesContents) { - this._sourcesContents = {}; - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else { - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - SourceMapGenerator.prototype.applySourceMap = function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { - if (!aSourceFile) { - aSourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - if (sourceRoot) { - aSourceFile = util.relative(sourceRoot, aSourceFile); - } - var newSources = new ArraySet; - var newNames = new ArraySet; - this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.original) { - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.original.line, - column: mapping.original.column - }); - if (original.source !== null) { - if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; - } - mapping.original.line = original.line; - mapping.original.column = original.column; - if (original.name !== null && mapping.name !== null) { - mapping.name = original.name; - } - } - } - var source = mapping.source; - if (source && !newSources.has(source)) { - newSources.add(source); - } - var name = mapping.name; - if (name && !newNames.has(name)) { - newNames.add(name); - } - }, this); - this._sources = newSources; - this._names = newNames; - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - if (sourceRoot) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - SourceMapGenerator.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) { - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { - return; - } else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aOriginal && 'line' in aOriginal && 'column' in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { - return; - } else { - throw new Error('Invalid mapping.'); - } - }; - 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); - } - SourceMapGenerator.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var mapping; - this._mappings.sort(cmpMapping); - for (var i = 0, len = this._mappings.length; i < len; i++) { - mapping = this._mappings[i]; - if (mapping.generated.line !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generated.line !== previousGeneratedLine) { - result += ';'; - previousGeneratedLine++; - } - } else { - if (i > 0) { - if (!cmpMapping(mapping, this._mappings[i - 1])) { - continue; - } - result += ','; - } - } - result += base64VLQ.encode(mapping.generated.column - previousGeneratedColumn); - previousGeneratedColumn = mapping.generated.column; - if (mapping.source && mapping.original) { - result += base64VLQ.encode(this._sources.indexOf(mapping.source) - previousSource); - previousSource = this._sources.indexOf(mapping.source); - result += base64VLQ.encode(mapping.original.line - 1 - previousOriginalLine); - previousOriginalLine = mapping.original.line - 1; - result += base64VLQ.encode(mapping.original.column - previousOriginalColumn); - previousOriginalColumn = mapping.original.column; - if (mapping.name) { - result += base64VLQ.encode(this._names.indexOf(mapping.name) - previousName); - previousName = this._names.indexOf(mapping.name); - } - } - } - return result; - }; - SourceMapGenerator.prototype.toJSON = function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - file: this._file, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._sourceRoot) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = map.sources.map(function (source) { - if (map.sourceRoot) { - source = util.relative(map.sourceRoot, source); - } - return Object.prototype.hasOwnProperty.call(this._sourcesContents, util.toSetString(source)) ? this._sourcesContents[util.toSetString(source)] : null; - }, this); - } - return map; - }; - SourceMapGenerator.prototype.toString = function SourceMapGenerator_toString() { - return JSON.stringify(this); - }; - exports.SourceMapGenerator = SourceMapGenerator; - }); - }); - require.define('/node_modules/source-map/lib/source-map/array-set.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - function ArraySet() { - this._array = []; - this._set = {}; - } - 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], aAllowDuplicates); - } - return set; - }; - ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var isDuplicate = this.has(aStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - this._set[util.toSetString(aStr)] = idx; - } - }; - ArraySet.prototype.has = function ArraySet_has(aStr) { - return Object.prototype.hasOwnProperty.call(this._set, util.toSetString(aStr)); - }; - ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (this.has(aStr)) { - return this._set[util.toSetString(aStr)]; - } - throw new Error('"' + aStr + '" is not in the set.'); - }; - ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); - }; - ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); - }; - exports.ArraySet = ArraySet; - }); - }); - require.define('/node_modules/source-map/lib/source-map/base64-vlq.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var base64 = require('/node_modules/source-map/lib/source-map/base64.js', module); - var VLQ_BASE_SHIFT = 5; - var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - var VLQ_BASE_MASK = VLQ_BASE - 1; - var VLQ_CONTINUATION_BIT = VLQ_BASE; - function toVLQSigned(aValue) { - return aValue < 0 ? (-aValue << 1) + 1 : (aValue << 1) + 0; - } - function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative ? -shifted : shifted; - } - exports.encode = function base64VLQ_encode(aValue) { - var encoded = ''; - var digit; - var vlq = toVLQSigned(aValue); - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - return encoded; - }; - exports.decode = function base64VLQ_decode(aStr) { - var i = 0; - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - do { - if (i >= strLen) { - throw new Error('Expected more digits in base 64 VLQ value.'); - } - digit = base64.decode(aStr.charAt(i++)); - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - return { - value: fromVLQSigned(result), - rest: aStr.slice(i) - }; - }; - }); - }); - require.define('/node_modules/source-map/lib/source-map/base64.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var charToIntMap = {}; - var intToCharMap = {}; - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('').forEach(function (ch, index) { - charToIntMap[ch] = index; - intToCharMap[index] = ch; - }); - exports.encode = function base64_encode(aNumber) { - if (aNumber in intToCharMap) { - return intToCharMap[aNumber]; - } - throw new TypeError('Must be between 0 and 63: ' + aNumber); - }; - exports.decode = function base64_decode(aChar) { - if (aChar in charToIntMap) { - return charToIntMap[aChar]; - } - throw new TypeError('Not a valid base 64 digit: ' + aChar); - }; - }); - }); - require.define('/node_modules/source-map/lib/source-map/source-map-consumer.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - var binarySearch = require('/node_modules/source-map/lib/source-map/binary-search.js', module); - var ArraySet = require('/node_modules/source-map/lib/source-map/array-set.js', module).ArraySet; - var base64VLQ = require('/node_modules/source-map/lib/source-map/base64-vlq.js', module); - function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - var names = util.getArg(sourceMap, 'names'); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - if (version !== this._version) { - throw new Error('Unsupported version: ' + version); - } - this._names = ArraySet.fromArray(names, true); - this._sources = ArraySet.fromArray(sources, true); - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this.file = file; - this._generatedMappings = []; - this._originalMappings = []; - this._parseMappings(mappings, sourceRoot); - } - SourceMapConsumer.prototype._version = 3; - Object.defineProperty(SourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot ? util.join(this.sourceRoot, s) : s; - }, this); - } - }); - SourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var mappingSeparator = /^[,;]/; - var str = aStr; - var mapping; - var temp; - while (str.length > 0) { - if (str.charAt(0) === ';') { - generatedLine++; - str = str.slice(1); - previousGeneratedColumn = 0; - } else if (str.charAt(0) === ',') { - str = str.slice(1); - } else { - mapping = {}; - mapping.generatedLine = generatedLine; - temp = base64VLQ.decode(str); - mapping.generatedColumn = previousGeneratedColumn + temp.value; - previousGeneratedColumn = mapping.generatedColumn; - str = temp.rest; - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - temp = base64VLQ.decode(str); - mapping.source = this._sources.at(previousSource + temp.value); - previousSource += temp.value; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source, but no line and column'); - } - temp = base64VLQ.decode(str); - mapping.originalLine = previousOriginalLine + temp.value; - previousOriginalLine = mapping.originalLine; - mapping.originalLine += 1; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source and line, but no column'); - } - temp = base64VLQ.decode(str); - mapping.originalColumn = previousOriginalColumn + temp.value; - previousOriginalColumn = mapping.originalColumn; - str = temp.rest; - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - temp = base64VLQ.decode(str); - mapping.name = this._names.at(previousName + temp.value); - previousName += temp.value; - str = temp.rest; - } - } - this._generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - this._originalMappings.push(mapping); - } - } - } - this._originalMappings.sort(this._compareOriginalPositions); - }; - 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; - } - }; - SourceMapConsumer.prototype._compareGeneratedPositions = function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - return cmp === 0 ? mappingA.generatedColumn - mappingB.generatedColumn : cmp; - }; - SourceMapConsumer.prototype._findMapping = function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, aColumnName, aComparator) { - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' + aNeedle[aColumnName]); - } - return binarySearch.search(aNeedle, aMappings, aComparator); - }; - SourceMapConsumer.prototype.originalPositionFor = function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - var mapping = this._findMapping(needle, this._generatedMappings, 'generatedLine', 'generatedColumn', this._compareGeneratedPositions); - if (mapping) { - var source = util.getArg(mapping, 'source', null); - if (source && this.sourceRoot) { - source = util.join(this.sourceRoot, source); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: util.getArg(mapping, 'name', null) - }; - } - return { - source: null, - line: null, - column: null, - name: null - }; - }; - SourceMapConsumer.prototype.sourceContentFor = function SourceMapConsumer_sourceContentFor(aSource) { - if (!this.sourcesContent) { - return null; - } - if (this.sourceRoot) { - 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))) { - 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.'); - }; - SourceMapConsumer.prototype.generatedPositionFor = function SourceMapConsumer_generatedPositionFor(aArgs) { - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - if (this.sourceRoot) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - var mapping = this._findMapping(needle, this._originalMappings, 'originalLine', 'originalColumn', this._compareOriginalPositions); - if (mapping) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null) - }; - } - return { - line: null, - column: null - }; - }; - SourceMapConsumer.GENERATED_ORDER = 1; - SourceMapConsumer.ORIGINAL_ORDER = 2; - SourceMapConsumer.prototype.eachMapping = function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error('Unknown order of iteration.'); - } - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source; - if (source && sourceRoot) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name - }; - }).forEach(aCallback, context); - }; - exports.SourceMapConsumer = SourceMapConsumer; - }); - }); - require.define('/node_modules/source-map/lib/source-map/binary-search.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid]); - if (cmp === 0) { - return aHaystack[mid]; - } else if (cmp > 0) { - if (aHigh - mid > 1) { - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); - } - return aHaystack[mid]; - } else { - if (mid - aLow > 1) { - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); - } - return aLow < 0 ? null : aHaystack[aLow]; - } - } - exports.search = function search(aNeedle, aHaystack, aCompare) { - return aHaystack.length > 0 ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) : null; - }; - }); - }); - require.define('/node_modules/estraverse/estraverse.js', function (module, exports, __dirname, __filename) { - (function (root, factory) { - 'use strict'; - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory(root.estraverse = {}); - } - }(this, function (exports) { - 'use strict'; - var Syntax, isArray, VisitorOption, VisitorKeys, BREAK, SKIP; - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrowFunctionExpression: 'ArrowFunctionExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - function ignoreJSHintError() { - } - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - function deepCopy(obj) { - var ret = {}, key, val; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - ret[key] = deepCopy(val); - } else { - ret[key] = val; - } - } - } - return ret; - } - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - ignoreJSHintError(shallowCopy); - function upperBound(array, func) { - var diff, len, i, current; - len = array.length; - i = 0; - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - len = diff; - } else { - i = current + 1; - len -= diff + 1; - } - } - return i; - } - function lowerBound(array, func) { - var diff, len, i, current; - len = array.length; - i = 0; - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - i = current + 1; - len -= diff + 1; - } else { - len = diff; - } - } - return i; - } - ignoreJSHintError(lowerBound); - VisitorKeys = { - AssignmentExpression: [ - 'left', - 'right' - ], - ArrayExpression: ['elements'], - ArrowFunctionExpression: [ - 'params', - 'body' - ], - BlockStatement: ['body'], - BinaryExpression: [ - 'left', - 'right' - ], - BreakStatement: ['label'], - CallExpression: [ - 'callee', - 'arguments' - ], - CatchClause: [ - 'param', - 'body' - ], - ConditionalExpression: [ - 'test', - 'consequent', - 'alternate' - ], - ContinueStatement: ['label'], - DebuggerStatement: [], - DirectiveStatement: [], - DoWhileStatement: [ - 'body', - 'test' - ], - EmptyStatement: [], - ExpressionStatement: ['expression'], - ForStatement: [ - 'init', - 'test', - 'update', - 'body' - ], - ForInStatement: [ - 'left', - 'right', - 'body' - ], - FunctionDeclaration: [ - 'id', - 'params', - 'body' - ], - FunctionExpression: [ - 'id', - 'params', - 'body' - ], - Identifier: [], - IfStatement: [ - 'test', - 'consequent', - 'alternate' - ], - Literal: [], - LabeledStatement: [ - 'label', - 'body' - ], - LogicalExpression: [ - 'left', - 'right' - ], - MemberExpression: [ - 'object', - 'property' - ], - NewExpression: [ - 'callee', - 'arguments' - ], - ObjectExpression: ['properties'], - Program: ['body'], - Property: [ - 'key', - 'value' - ], - ReturnStatement: ['argument'], - SequenceExpression: ['expressions'], - SwitchStatement: [ - 'discriminant', - 'cases' - ], - SwitchCase: [ - 'test', - 'consequent' - ], - ThisExpression: [], - ThrowStatement: ['argument'], - TryStatement: [ - 'block', - 'handlers', - 'handler', - 'guardedHandlers', - 'finalizer' - ], - UnaryExpression: ['argument'], - UpdateExpression: ['argument'], - VariableDeclaration: ['declarations'], - VariableDeclarator: [ - 'id', - 'init' - ], - WhileStatement: [ - 'test', - 'body' - ], - WithStatement: [ - 'object', - 'body' - ], - YieldExpression: ['argument'] - }; - BREAK = {}; - SKIP = {}; - VisitorOption = { - Break: BREAK, - Skip: SKIP - }; - function Reference(parent, key) { - this.parent = parent; - this.key = key; - } - Reference.prototype.replace = function replace(node) { - this.parent[this.key] = node; - }; - function Element(node, path, wrap, ref) { - this.node = node; - this.path = path; - this.wrap = wrap; - this.ref = ref; - } - function Controller() { - } - Controller.prototype.path = function path() { - var i, iz, j, jz, result, element; - function addToPath(result, path) { - if (isArray(path)) { - for (j = 0, jz = path.length; j < jz; ++j) { - result.push(path[j]); - } - } else { - result.push(path); - } - } - if (!this.__current.path) { - return null; - } - result = []; - for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { - element = this.__leavelist[i]; - addToPath(result, element.path); - } - addToPath(result, this.__current.path); - return result; - }; - Controller.prototype.parents = function parents() { - var i, iz, result; - result = []; - for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { - result.push(this.__leavelist[i].node); - } - return result; - }; - Controller.prototype.current = function current() { - return this.__current.node; - }; - Controller.prototype.__execute = function __execute(callback, element) { - var previous, result; - result = undefined; - previous = this.__current; - this.__current = element; - this.__state = null; - if (callback) { - result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); - } - this.__current = previous; - return result; - }; - Controller.prototype.notify = function notify(flag) { - this.__state = flag; - }; - Controller.prototype.skip = function () { - this.notify(SKIP); - }; - Controller.prototype['break'] = function () { - this.notify(BREAK); - }; - Controller.prototype.__initialize = function (root, visitor) { - this.visitor = visitor; - this.root = root; - this.__worklist = []; - this.__leavelist = []; - this.__current = null; - this.__state = null; - }; - Controller.prototype.traverse = function traverse(root, visitor) { - var worklist, leavelist, element, node, nodeType, ret, key, current, current2, candidates, candidate, sentinel; - this.__initialize(root, visitor); - sentinel = {}; - worklist = this.__worklist; - leavelist = this.__leavelist; - worklist.push(new Element(root, null, null, null)); - leavelist.push(new Element(null, null, null, null)); - while (worklist.length) { - element = worklist.pop(); - if (element === sentinel) { - element = leavelist.pop(); - ret = this.__execute(visitor.leave, element); - if (this.__state === BREAK || ret === BREAK) { - return; - } - continue; - } - if (element.node) { - ret = this.__execute(visitor.enter, element); - if (this.__state === BREAK || ret === BREAK) { - return; - } - worklist.push(sentinel); - leavelist.push(element); - if (this.__state === SKIP || ret === SKIP) { - continue; - } - node = element.node; - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, null)); - continue; - } - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [ - key, - current2 - ], 'Property', null); - } else { - element = new Element(candidate[current2], [ - key, - current2 - ], null, null); - } - worklist.push(element); - } - } - } - } - }; - Controller.prototype.replace = function replace(root, visitor) { - var worklist, leavelist, node, nodeType, target, element, current, current2, candidates, candidate, sentinel, outer, key; - this.__initialize(root, visitor); - sentinel = {}; - worklist = this.__worklist; - leavelist = this.__leavelist; - outer = { root: root }; - element = new Element(root, null, null, new Reference(outer, 'root')); - worklist.push(element); - leavelist.push(element); - while (worklist.length) { - element = worklist.pop(); - if (element === sentinel) { - element = leavelist.pop(); - target = this.__execute(visitor.leave, element); - if (target !== undefined && target !== BREAK && target !== SKIP) { - element.ref.replace(target); - } - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - continue; - } - target = this.__execute(visitor.enter, element); - if (target !== undefined && target !== BREAK && target !== SKIP) { - element.ref.replace(target); - element.node = target; - } - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - node = element.node; - if (!node) { - continue; - } - worklist.push(sentinel); - leavelist.push(element); - if (this.__state === SKIP || target === SKIP) { - continue; - } - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, new Reference(node, key))); - continue; - } - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [ - key, - current2 - ], 'Property', new Reference(candidate, current2)); - } else { - element = new Element(candidate[current2], [ - key, - current2 - ], null, new Reference(candidate, current2)); - } - worklist.push(element); - } - } - } - return outer.root; - }; - function traverse(root, visitor) { - var controller = new Controller; - return controller.traverse(root, visitor); - } - function replace(root, visitor) { - var controller = new Controller; - return controller.replace(root, visitor); - } - function extendCommentRange(comment, tokens) { - var target, token; - target = upperBound(tokens, function search(token) { - return token.range[0] > comment.range[0]; - }); - comment.extendedRange = [ - comment.range[0], - comment.range[1] - ]; - if (target !== tokens.length) { - comment.extendedRange[1] = tokens[target].range[0]; - } - target -= 1; - if (target >= 0) { - if (target < tokens.length) { - comment.extendedRange[0] = tokens[target].range[1]; - } else if (token.length) { - comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; - } - } - return comment; - } - function attachComments(tree, providedComments, tokens) { - var comments = [], comment, len, i, cursor; - if (!tree.range) { - throw new Error('attachComments needs range information'); - } - if (!tokens.length) { - if (providedComments.length) { - for (i = 0, len = providedComments.length; i < len; i += 1) { - comment = deepCopy(providedComments[i]); - comment.extendedRange = [ - 0, - tree.range[0] - ]; - comments.push(comment); - } - tree.leadingComments = comments; - } - return tree; - } - for (i = 0, len = providedComments.length; i < len; i += 1) { - comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); - } - cursor = 0; - traverse(tree, { - enter: function (node) { - var comment; - while (cursor < comments.length) { - comment = comments[cursor]; - if (comment.extendedRange[1] > node.range[0]) { - break; - } - if (comment.extendedRange[1] === node.range[0]) { - if (!node.leadingComments) { - node.leadingComments = []; - } - node.leadingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - if (cursor === comments.length) { - return VisitorOption.Break; - } - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - cursor = 0; - traverse(tree, { - leave: function (node) { - var comment; - while (cursor < comments.length) { - comment = comments[cursor]; - if (node.range[1] < comment.extendedRange[0]) { - break; - } - if (node.range[1] === comment.extendedRange[0]) { - if (!node.trailingComments) { - node.trailingComments = []; - } - node.trailingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - if (cursor === comments.length) { - return VisitorOption.Break; - } - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - return tree; - } - exports.version = '1.3.1'; - exports.Syntax = Syntax; - exports.traverse = traverse; - exports.replace = replace; - exports.attachComments = attachComments; - exports.VisitorKeys = VisitorKeys; - exports.VisitorOption = VisitorOption; - exports.Controller = Controller; - })); - }); - require('/tools/entry-point.js'); -}.call(this, this)); diff --git a/toolkit/devtools/escodegen/estraverse.js b/toolkit/devtools/escodegen/estraverse.js deleted file mode 100644 index 211617d24ef..00000000000 --- a/toolkit/devtools/escodegen/estraverse.js +++ /dev/null @@ -1,678 +0,0 @@ -/* - Copyright (C) 2012-2013 Yusuke Suzuki - Copyright (C) 2012 Ariya Hidayat - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/*jslint vars:false*/ -/*jshint indent:4*/ -/*global exports:true, define:true*/ -(function (root, factory) { - 'use strict'; - - // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, - // and plain browser loading, - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.estraverse = {})); - } -}(this, function (exports) { - 'use strict'; - - var Syntax, - isArray, - VisitorOption, - VisitorKeys, - BREAK, - SKIP; - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - - function ignoreJSHintError() { } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - - function deepCopy(obj) { - var ret = {}, key, val; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - ret[key] = deepCopy(val); - } else { - ret[key] = val; - } - } - } - return ret; - } - - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - ignoreJSHintError(shallowCopy); - - // based on LLVM libc++ upper_bound / lower_bound - // MIT License - - function upperBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - len = diff; - } else { - i = current + 1; - len -= diff + 1; - } - } - return i; - } - - function lowerBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - i = current + 1; - len -= diff + 1; - } else { - len = diff; - } - } - return i; - } - ignoreJSHintError(lowerBound); - - VisitorKeys = { - AssignmentExpression: ['left', 'right'], - ArrayExpression: ['elements'], - BlockStatement: ['body'], - BinaryExpression: ['left', 'right'], - BreakStatement: ['label'], - CallExpression: ['callee', 'arguments'], - CatchClause: ['param', 'body'], - ConditionalExpression: ['test', 'consequent', 'alternate'], - ContinueStatement: ['label'], - DebuggerStatement: [], - DirectiveStatement: [], - DoWhileStatement: ['body', 'test'], - EmptyStatement: [], - ExpressionStatement: ['expression'], - ForStatement: ['init', 'test', 'update', 'body'], - ForInStatement: ['left', 'right', 'body'], - FunctionDeclaration: ['id', 'params', 'body'], - FunctionExpression: ['id', 'params', 'body'], - Identifier: [], - IfStatement: ['test', 'consequent', 'alternate'], - Literal: [], - LabeledStatement: ['label', 'body'], - LogicalExpression: ['left', 'right'], - MemberExpression: ['object', 'property'], - NewExpression: ['callee', 'arguments'], - ObjectExpression: ['properties'], - Program: ['body'], - Property: ['key', 'value'], - ReturnStatement: ['argument'], - SequenceExpression: ['expressions'], - SwitchStatement: ['discriminant', 'cases'], - SwitchCase: ['test', 'consequent'], - ThisExpression: [], - ThrowStatement: ['argument'], - TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], - UnaryExpression: ['argument'], - UpdateExpression: ['argument'], - VariableDeclaration: ['declarations'], - VariableDeclarator: ['id', 'init'], - WhileStatement: ['test', 'body'], - WithStatement: ['object', 'body'], - YieldExpression: ['argument'] - }; - - // unique id - BREAK = {}; - SKIP = {}; - - VisitorOption = { - Break: BREAK, - Skip: SKIP - }; - - function Reference(parent, key) { - this.parent = parent; - this.key = key; - } - - Reference.prototype.replace = function replace(node) { - this.parent[this.key] = node; - }; - - function Element(node, path, wrap, ref) { - this.node = node; - this.path = path; - this.wrap = wrap; - this.ref = ref; - } - - function Controller() { } - - // API: - // return property path array from root to current node - Controller.prototype.path = function path() { - var i, iz, j, jz, result, element; - - function addToPath(result, path) { - if (isArray(path)) { - for (j = 0, jz = path.length; j < jz; ++j) { - result.push(path[j]); - } - } else { - result.push(path); - } - } - - // root node - if (!this.__current.path) { - return null; - } - - // first node is sentinel, second node is root element - result = []; - for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { - element = this.__leavelist[i]; - addToPath(result, element.path); - } - addToPath(result, this.__current.path); - return result; - }; - - // API: - // return array of parent elements - Controller.prototype.parents = function parents() { - var i, iz, result; - - // first node is sentinel - result = []; - for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { - result.push(this.__leavelist[i].node); - } - - return result; - }; - - // API: - // return current node - Controller.prototype.current = function current() { - return this.__current.node; - }; - - Controller.prototype.__execute = function __execute(callback, element) { - var previous, result; - - result = undefined; - - previous = this.__current; - this.__current = element; - this.__state = null; - if (callback) { - result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); - } - this.__current = previous; - - return result; - }; - - // API: - // notify control skip / break - Controller.prototype.notify = function notify(flag) { - this.__state = flag; - }; - - // API: - // skip child nodes of current node - Controller.prototype.skip = function () { - this.notify(SKIP); - }; - - // API: - // break traversals - Controller.prototype['break'] = function () { - this.notify(BREAK); - }; - - Controller.prototype.__initialize = function(root, visitor) { - this.visitor = visitor; - this.root = root; - this.__worklist = []; - this.__leavelist = []; - this.__current = null; - this.__state = null; - }; - - Controller.prototype.traverse = function traverse(root, visitor) { - var worklist, - leavelist, - element, - node, - nodeType, - ret, - key, - current, - current2, - candidates, - candidate, - sentinel; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - worklist.push(new Element(root, null, null, null)); - leavelist.push(new Element(null, null, null, null)); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - ret = this.__execute(visitor.leave, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - continue; - } - - if (element.node) { - - ret = this.__execute(visitor.enter, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || ret === SKIP) { - continue; - } - - node = element.node; - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, null)); - continue; - } - - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [key, current2], 'Property', null); - } else { - element = new Element(candidate[current2], [key, current2], null, null); - } - worklist.push(element); - } - } - } - } - }; - - Controller.prototype.replace = function replace(root, visitor) { - var worklist, - leavelist, - node, - nodeType, - target, - element, - current, - current2, - candidates, - candidate, - sentinel, - outer, - key; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - outer = { - root: root - }; - element = new Element(root, null, null, new Reference(outer, 'root')); - worklist.push(element); - leavelist.push(element); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - target = this.__execute(visitor.leave, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP) { - // replace - element.ref.replace(target); - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - continue; - } - - target = this.__execute(visitor.enter, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP) { - // replace - element.ref.replace(target); - element.node = target; - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - - // node may be null - node = element.node; - if (!node) { - continue; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || target === SKIP) { - continue; - } - - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, new Reference(node, key))); - continue; - } - - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); - } else { - element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); - } - worklist.push(element); - } - } - } - - return outer.root; - }; - - function traverse(root, visitor) { - var controller = new Controller(); - return controller.traverse(root, visitor); - } - - function replace(root, visitor) { - var controller = new Controller(); - return controller.replace(root, visitor); - } - - function extendCommentRange(comment, tokens) { - var target, token; - - target = upperBound(tokens, function search(token) { - return token.range[0] > comment.range[0]; - }); - - comment.extendedRange = [comment.range[0], comment.range[1]]; - - if (target !== tokens.length) { - comment.extendedRange[1] = tokens[target].range[0]; - } - - target -= 1; - if (target >= 0) { - if (target < tokens.length) { - comment.extendedRange[0] = tokens[target].range[1]; - } else if (token.length) { - comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; - } - } - - return comment; - } - - function attachComments(tree, providedComments, tokens) { - // At first, we should calculate extended comment ranges. - var comments = [], comment, len, i, cursor; - - if (!tree.range) { - throw new Error('attachComments needs range information'); - } - - // tokens array is empty, we attach comments to tree as 'leadingComments' - if (!tokens.length) { - if (providedComments.length) { - for (i = 0, len = providedComments.length; i < len; i += 1) { - comment = deepCopy(providedComments[i]); - comment.extendedRange = [0, tree.range[0]]; - comments.push(comment); - } - tree.leadingComments = comments; - } - return tree; - } - - for (i = 0, len = providedComments.length; i < len; i += 1) { - comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); - } - - // This is based on John Freeman's implementation. - cursor = 0; - traverse(tree, { - enter: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (comment.extendedRange[1] > node.range[0]) { - break; - } - - if (comment.extendedRange[1] === node.range[0]) { - if (!node.leadingComments) { - node.leadingComments = []; - } - node.leadingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - cursor = 0; - traverse(tree, { - leave: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (node.range[1] < comment.extendedRange[0]) { - break; - } - - if (node.range[1] === comment.extendedRange[0]) { - if (!node.trailingComments) { - node.trailingComments = []; - } - node.trailingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - return tree; - } - - exports.version = '1.3.0'; - exports.Syntax = Syntax; - exports.traverse = traverse; - exports.replace = replace; - exports.attachComments = attachComments; - exports.VisitorKeys = VisitorKeys; - exports.VisitorOption = VisitorOption; - exports.Controller = Controller; -})); -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/toolkit/devtools/escodegen/package.json.js b/toolkit/devtools/escodegen/package.json.js deleted file mode 100644 index 84c83e733a7..00000000000 --- a/toolkit/devtools/escodegen/package.json.js +++ /dev/null @@ -1,57 +0,0 @@ -module.exports = { - "name": "escodegen", - "description": "ECMAScript code generator", - "homepage": "http://github.com/Constellation/escodegen.html", - "main": "escodegen.js", - "bin": { - "esgenerate": "./bin/esgenerate.js", - "escodegen": "./bin/escodegen.js" - }, - "version": "0.0.26", - "engines": { - "node": ">=0.4.0" - }, - "maintainers": [ - { - "name": "Yusuke Suzuki", - "email": "utatane.tea@gmail.com", - "web": "http://github.com/Constellation" - } - ], - "repository": { - "type": "git", - "url": "http://github.com/Constellation/escodegen.git" - }, - "dependencies": { - "esprima": "~1.0.2", - "estraverse": "~1.3.0" - }, - "optionalDependencies": { - "source-map": ">= 0.1.2" - }, - "devDependencies": { - "esprima-moz": "*", - "commonjs-everywhere": "~0.8.0", - "q": "*", - "bower": "*", - "semver": "*", - "chai": "~1.7.2", - "grunt-contrib-jshint": "~0.5.0", - "grunt-cli": "~0.1.9", - "grunt": "~0.4.1", - "grunt-mocha-test": "~0.6.2" - }, - "licenses": [ - { - "type": "BSD", - "url": "http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD" - } - ], - "scripts": { - "test": "grunt travis", - "unit-test": "grunt test", - "lint": "grunt lint", - "release": "node tools/release.js", - "build": "./node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.js" - } -}; diff --git a/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js b/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js deleted file mode 100644 index c7f6ba96bf0..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js +++ /dev/null @@ -1,71 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test that we can generate source maps via escodegen. - */ - -Components.utils.import("resource://gre/modules/reflect.jsm"); -Components.utils.import("resource://gre/modules/devtools/SourceMap.jsm"); -const escodegen = require("escodegen/escodegen"); - -const testCode = "" + function main() { - var a = 5 + 3; - var b = 19 * 52; - return a / b; -}; - -function run_test() { - const ast = Reflect.parse(testCode); - const { code, map } = escodegen.generate(ast, { - format: { - indent: { - // Single space indents so we are mapping different locations. - style: " " - } - }, - sourceMap: "testCode.js", - sourceMapWithCode: true - }); - const smc = new SourceMapConsumer(map.toString()); - - let mapping = smc.originalPositionFor({ - line: 2, - column: 1 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 2); - do_check_eq(mapping.column, 2); - - mapping = smc.originalPositionFor({ - line: 2, - column: 5 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 2); - do_check_eq(mapping.column, 6); - - mapping = smc.originalPositionFor({ - line: 3, - column: 1 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 3); - do_check_eq(mapping.column, 2); - - mapping = smc.originalPositionFor({ - line: 3, - column: 5 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 3); - do_check_eq(mapping.column, 6); - - mapping = smc.originalPositionFor({ - line: 4, - column: 1 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 4); - do_check_eq(mapping.column, 2); -}; diff --git a/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js b/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js deleted file mode 100644 index a9f76e41fed..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js +++ /dev/null @@ -1,11 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test that we can require escodegen. - */ - -function run_test() { - const escodegen = require("escodegen/escodegen"); - do_check_eq(typeof escodegen.generate, "function"); -} diff --git a/toolkit/devtools/escodegen/tests/unit/test_same_ast.js b/toolkit/devtools/escodegen/tests/unit/test_same_ast.js deleted file mode 100644 index 72b4200a05d..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/test_same_ast.js +++ /dev/null @@ -1,76 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test that we can go AST -> JS -> AST via escodegen and Reflect. - */ - -const escodegen = require("escodegen/escodegen"); -Components.utils.import("resource://gre/modules/reflect.jsm"); - -const testCode = "" + function main () { - function makeAcc(n) { - return function () { - return ++n; - }; - } - - var acc = makeAcc(10); - - for (var i = 0; i < 10; i++) { - acc(); - } - - console.log(acc()); -}; - -function run_test() { - const originalAST = Reflect.parse(testCode); - const generatedCode = escodegen.generate(originalAST); - const generatedAST = Reflect.parse(generatedCode); - - do_print("Original AST:"); - do_print(JSON.stringify(originalAST, null, 2)); - do_print("Generated AST:"); - do_print(JSON.stringify(generatedAST, null, 2)); - - checkEquivalentASTs(originalAST, generatedAST); -} - -const isObject = (obj) => typeof obj === "object" && obj !== null; -const zip = (a, b) => { - let pairs = []; - for (let i = 0; i < a.length && i < b.length; i++) { - pairs.push([a[i], b[i]]); - } - return pairs; -}; -const isntLoc = k => k !== "loc"; - -function checkEquivalentASTs(expected, actual, prop = []) { - do_print("Checking: " + prop.join(" ")); - - if (!isObject(expected)) { - return void do_check_eq(expected, actual); - } - - do_check_true(isObject(actual)); - - if (Array.isArray(expected)) { - do_check_true(Array.isArray(actual)); - do_check_eq(expected.length, actual.length); - let i = 0; - for (let [e, a] of zip(expected, actual)) { - checkEquivalentASTs(a, e, prop.concat([i++])); - } - return; - } - - const expectedKeys = Object.keys(expected).filter(isntLoc).sort(); - const actualKeys = Object.keys(actual).filter(isntLoc).sort(); - do_check_eq(expectedKeys.length, actualKeys.length); - for (let [ek, ak] of zip(expectedKeys, actualKeys)) { - do_check_eq(ek, ak); - checkEquivalentASTs(expected[ek], actual[ak], prop.concat([ek])); - } -} diff --git a/toolkit/devtools/escodegen/tests/unit/xpcshell.ini b/toolkit/devtools/escodegen/tests/unit/xpcshell.ini deleted file mode 100644 index e8d9f152bae..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/xpcshell.ini +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -head = head_escodegen.js -tail = - -[test_import_escodegen.js] -[test_same_ast.js] -[test_generate_source_maps.js] diff --git a/toolkit/devtools/moz.build b/toolkit/devtools/moz.build index 16897d5e427..20022d77b59 100644 --- a/toolkit/devtools/moz.build +++ b/toolkit/devtools/moz.build @@ -14,6 +14,6 @@ PARALLEL_DIRS += [ 'webconsole', 'apps', 'styleinspector', - 'escodegen', - 'acorn' + 'acorn', + 'pretty-fast' ] diff --git a/toolkit/devtools/pretty-fast/UPGRADING.md b/toolkit/devtools/pretty-fast/UPGRADING.md new file mode 100644 index 00000000000..6ad0071c896 --- /dev/null +++ b/toolkit/devtools/pretty-fast/UPGRADING.md @@ -0,0 +1,7 @@ +# UPGRADING + +1. `git clone https://github.com/mozilla/pretty-fast.git` + +2. Copy `pretty-fast/pretty-fast.js` to `toolkit/devtools/pretty-fast/pretty-fast.js` + +3. Copy `pretty-fast/test.js` to `toolkit/devtools/pretty-fast/tests/unit/test.js` diff --git a/toolkit/devtools/escodegen/moz.build b/toolkit/devtools/pretty-fast/moz.build similarity index 73% rename from toolkit/devtools/escodegen/moz.build rename to toolkit/devtools/pretty-fast/moz.build index 4c70f2f5b6d..1190adac810 100644 --- a/toolkit/devtools/escodegen/moz.build +++ b/toolkit/devtools/pretty-fast/moz.build @@ -6,11 +6,8 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] -JS_MODULES_PATH = 'modules/devtools/escodegen' +JS_MODULES_PATH = 'modules/devtools' EXTRA_JS_MODULES += [ - 'escodegen.js', - 'escodegen.worker.js', - 'estraverse.js', - 'package.json.js', + 'pretty-fast.js', ] diff --git a/toolkit/devtools/pretty-fast/pretty-fast.js b/toolkit/devtools/pretty-fast/pretty-fast.js new file mode 100644 index 00000000000..33b7f82e6e9 --- /dev/null +++ b/toolkit/devtools/pretty-fast/pretty-fast.js @@ -0,0 +1,781 @@ +/* + * Copyright 2013 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.md or: + * http://opensource.org/licenses/BSD-2-Clause + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.prettyFast = factory(); + } +}(this, function () { + "use strict"; + + var acorn = this.acorn || require("acorn"); + var sourceMap = this.sourceMap || require("source-map"); + var SourceNode = sourceMap.SourceNode; + + // If any of these tokens are seen before a "[" token, we know that "[" token + // is the start of an array literal, rather than a property access. + // + // The only exception is "}", which would need to be disambiguated by + // parsing. The majority of the time, an open bracket following a closing + // curly is going to be an array literal, so we brush the complication under + // the rug, and handle the ambiguity by always assuming that it will be an + // array literal. + var PRE_ARRAY_LITERAL_TOKENS = { + "typeof": true, + "void": true, + "delete": true, + "case": true, + "do": true, + "=": true, + "in": true, + "{": true, + "*": true, + "/": true, + "%": true, + "else": true, + ";": true, + "++": true, + "--": true, + "+": true, + "-": true, + "~": true, + "!": true, + ":": true, + "?": true, + ">>": true, + ">>>": true, + "<<": true, + "||": true, + "&&": true, + "<": true, + ">": true, + "<=": true, + ">=": true, + "instanceof": true, + "&": true, + "^": true, + "|": true, + "==": true, + "!=": true, + "===": true, + "!==": true, + ",": true, + + "}": true + }; + + /** + * Determines if we think that the given token starts an array literal. + * + * @param Object token + * The token we want to determine if it is an array literal. + * @param Object lastToken + * The last token we added to the pretty printed results. + * + * @returns Boolean + * True if we believe it is an array literal, false otherwise. + */ + function isArrayLiteral(token, lastToken) { + if (token.type.type != "[") { + return false; + } + if (!lastToken) { + return true; + } + if (lastToken.type.isAssign) { + return true; + } + return !!PRE_ARRAY_LITERAL_TOKENS[lastToken.type.keyword || lastToken.type.type]; + } + + // If any of these tokens are followed by a token on a new line, we know that + // ASI cannot happen. + var PREVENT_ASI_AFTER_TOKENS = { + // Binary operators + "*": true, + "/": true, + "%": true, + "+": true, + "-": true, + "<<": true, + ">>": true, + ">>>": true, + "<": true, + ">": true, + "<=": true, + ">=": true, + "instanceof": true, + "in": true, + "==": true, + "!=": true, + "===": true, + "!==": true, + "&": true, + "^": true, + "|": true, + "&&": true, + "||": true, + ",": true, + ".": true, + "=": true, + "*=": true, + "/=": true, + "%=": true, + "+=": true, + "-=": true, + "<<=": true, + ">>=": true, + ">>>=": true, + "&=": true, + "^=": true, + "|=": true, + // Unary operators + "delete": true, + "void": true, + "typeof": true, + "~": true, + "!": true, + "new": true, + // Function calls and grouped expressions + "(": true + }; + + // If any of these tokens are on a line after the token before it, we know + // that ASI cannot happen. + var PREVENT_ASI_BEFORE_TOKENS = { + // Binary operators + "*": true, + "/": true, + "%": true, + "<<": true, + ">>": true, + ">>>": true, + "<": true, + ">": true, + "<=": true, + ">=": true, + "instanceof": true, + "in": true, + "==": true, + "!=": true, + "===": true, + "!==": true, + "&": true, + "^": true, + "|": true, + "&&": true, + "||": true, + ",": true, + ".": true, + "=": true, + "*=": true, + "/=": true, + "%=": true, + "+=": true, + "-=": true, + "<<=": true, + ">>=": true, + ">>>=": true, + "&=": true, + "^=": true, + "|=": true, + // Function calls + "(": true + }; + + /** + * Determines if Automatic Semicolon Insertion (ASI) occurs between these + * tokens. + * + * @param Object token + * The token we want to determine if it is an array literal. + * @param Object lastToken + * The last token we added to the pretty printed results. + * + * @returns Boolean + * True if we believe ASI occurs. + */ + function isASI(token, lastToken) { + if (!lastToken) { + return false; + } + if (token.startLoc.line === lastToken.startLoc.line) { + return false; + } + if (PREVENT_ASI_AFTER_TOKENS[lastToken.type.type || lastToken.type.keyword]) { + return false; + } + if (PREVENT_ASI_BEFORE_TOKENS[token.type.type || token.type.keyword]) { + return false; + } + return true; + } + + /** + * Determine if we should add a newline after the given token. + * + * @param Object token + * The token we are looking at. + * @param Array stack + * The stack of open parens/curlies/brackets/etc. + * + * @returns Boolean + * True if we should add a newline. + */ + function isLineDelimiter(token, stack) { + if (token.isArrayLiteral) { + return true; + } + var ttt = token.type.type; + var top = stack[stack.length - 1]; + return ttt == ";" && top != "(" + || ttt == "{" + || ttt == "," && top != "(" + || ttt == ":" && (top == "case" || top == "default"); + } + + /** + * Append the necessary whitespace to the result after we have added the given + * token. + * + * @param Object token + * The token that was just added to the result. + * @param Function write + * The function to write to the pretty printed results. + * @param Array stack + * The stack of open parens/curlies/brackets/etc. + * + * @returns Boolean + * Returns true if we added a newline to result, false in all other + * cases. + */ + function appendNewline(token, write, stack) { + if (isLineDelimiter(token, stack)) { + write("\n", token.startLoc.line, token.startLoc.column); + return true; + } + return false; + } + + /** + * Determines if we need to add a space between the last token we added and + * the token we are about to add. + * + * @param Object token + * The token we are about to add to the pretty printed code. + * @param Object lastToken + * The last token added to the pretty printed code. + */ + function needsSpaceAfter(token, lastToken) { + if (lastToken) { + if (lastToken.type.isLoop) { + return true; + } + if (lastToken.type.isAssign) { + return true; + } + if (lastToken.type.binop != null) { + return true; + } + + var ltt = lastToken.type.type; + if (ltt == "?") { + return true; + } + if (ltt == ":") { + return true; + } + if (ltt == ",") { + return true; + } + if (ltt == ";") { + return true; + } + + var ltk = lastToken.type.keyword; + if (ltk != null + && ltk != "debugger" + && ltk != "null" + && ltk != "true" + && ltk != "false" + && ltk != "this" + && ltk != "break" + && ltk != "continue" + && ltk != "default") { + return true; + } + + if (ltt == ")" && (token.type.type != ")" + && token.type.type != "]" + && token.type.type != ";" + && token.type.type != ",")) { + return true; + } + } + + if (token.type.isAssign) { + return true; + } + if (token.type.binop != null) { + return true; + } + if (token.type.type == "?") { + return true; + } + + return false; + } + + /** + * Add the required whitespace before this token, whether that is a single + * space, newline, and/or the indent on fresh lines. + * + * @param Object token + * The token we are about to add to the pretty printed code. + * @param Object lastToken + * The last token we added to the pretty printed code. + * @param Boolean addedNewline + * Whether we added a newline after adding the last token to the pretty + * printed code. + * @param Function write + * The function to write pretty printed code to the result SourceNode. + * @param Object options + * The options object. + * @param Number indentLevel + * The number of indents deep we are. + * @param Array stack + * The stack of open curlies, brackets, etc. + */ + function prependWhiteSpace(token, lastToken, addedNewline, write, options, + indentLevel, stack) { + var ttk = token.type.keyword; + var ttt = token.type.type; + var newlineAdded = addedNewline; + + // Handle whitespace and newlines after "}" here instead of in + // `isLineDelimiter` because it is only a line delimiter some of the + // time. For example, we don't want to put "else if" on a new line after + // the first if's block. + if (lastToken && lastToken.type.type == "}") { + if (ttk == "while" && stack[stack.length - 1] == "do") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } else if (ttk == "else" || + ttk == "catch" || + ttk == "finally") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } else if (ttt != "(" && + ttt != ";" && + ttt != "," && + ttt != ")" && + ttt != ".") { + write("\n", + lastToken.startLoc.line, + lastToken.startLoc.column); + newlineAdded = true; + } + } + + if (ttt == ":" && stack[stack.length - 1] == "?") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } + + if (lastToken && lastToken.type.type != "}" && ttk == "else") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } + + function ensureNewline() { + if (!newlineAdded) { + write("\n", + lastToken.startLoc.line, + lastToken.startLoc.column); + newlineAdded = true; + } + } + + if (isASI(token, lastToken)) { + ensureNewline(); + } + + if (decrementsIndent(ttt, stack)) { + ensureNewline(); + } + + if (newlineAdded) { + if (ttk == "case" || ttk == "default") { + write(repeat(options.indent, indentLevel - 1), + token.startLoc.line, + token.startLoc.column); + } else { + write(repeat(options.indent, indentLevel), + token.startLoc.line, + token.startLoc.column); + } + } else if (needsSpaceAfter(token, lastToken)) { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } + } + + /** + * Repeat the `str` string `n` times. + * + * @param String str + * The string to be repeated. + * @param Number n + * The number of times to repeat the string. + * + * @returns String + * The repeated string. + */ + function repeat(str, n) { + var result = ""; + while (n > 0) { + if (n & 1) { + result += str; + } + n >>= 1; + str += str; + } + return result; + } + + /** + * Make sure that we put "\n" into the output instead of actual newlines. + */ + function sanitizeNewlines(str) { + return str.replace(/\n/g, "\\n"); + } + + /** + * Add the given token to the pretty printed results. + * + * @param Object token + * The token to add. + * @param Function write + * The function to write pretty printed code to the result SourceNode. + * @param Object options + * The options object. + */ + function addToken(token, write, options) { + if (token.type.type == "string") { + write("'" + sanitizeNewlines(token.value) + "'", + token.startLoc.line, + token.startLoc.column); + } else { + write(String(token.value != null ? token.value : token.type.type), + token.startLoc.line, + token.startLoc.column); + } + } + + /** + * Returns true if the given token type belongs on the stack. + */ + function belongsOnStack(token) { + var ttt = token.type.type; + var ttk = token.type.keyword; + return ttt == "{" + || ttt == "(" + || ttt == "[" + || ttt == "?" + || ttk == "do" + || ttk == "case" + || ttk == "default"; + } + + /** + * Returns true if the given token should cause us to pop the stack. + */ + function shouldStackPop(token, stack) { + var ttt = token.type.type; + var ttk = token.type.keyword; + var top = stack[stack.length - 1]; + return ttt == "]" + || ttt == ")" + || ttt == "}" + || (ttt == ":" && (top == "case" || top == "default" || top == "?")) + || (ttk == "while" && top == "do"); + } + + /** + * Returns true if the given token type should cause us to decrement the + * indent level. + */ + function decrementsIndent(tokenType, stack) { + return tokenType == "}" + || (tokenType == "]" && stack[stack.length - 1] == "[\n") + } + + /** + * Returns true if the given token should cause us to increment the indent + * level. + */ + function incrementsIndent(token) { + return token.type.type == "{" || token.isArrayLiteral; + } + + /** + * Add a comment to the pretty printed code. + * + * @param Function write + * The function to write pretty printed code to the result SourceNode. + * @param Number indentLevel + * The number of indents deep we are. + * @param Object options + * The options object. + * @param Boolean block + * True if the comment is a multiline block style comment. + * @param String text + * The text of the comment. + * @param Number line + * The line number to comment appeared on. + * @param Number column + * The column number the comment appeared on. + */ + function addComment(write, indentLevel, options, block, text, line, column) { + var indentString = repeat(options.indent, indentLevel); + + write(indentString, line, column); + if (block) { + write("/*"); + write(text + .split(new RegExp("/\n" + indentString + "/", "g")) + .join("\n" + indentString)); + write("*/"); + } else { + write("//"); + write(text); + } + write("\n"); + } + + /** + * The main function. + * + * @param String input + * The ugly JS code we want to pretty print. + * @param Object options + * The options object. Provides configurability of the pretty + * printing. Properties: + * - url: The URL string of the ugly JS code. + * - indent: The string to indent code by. + * + * @returns Object + * An object with the following properties: + * - code: The pretty printed code string. + * - map: A SourceMapGenerator instance. + */ + return function prettyFast(input, options) { + // The level of indents deep we are. + var indentLevel = 0; + + // We will accumulate the pretty printed code in this SourceNode. + var result = new SourceNode(); + + /** + * Write a pretty printed string to the result SourceNode. + * + * We buffer our writes so that we only create one mapping for each line in + * the source map. This enhances performance by avoiding extraneous mapping + * serialization, and flattening the tree that + * `SourceNode#toStringWithSourceMap` will have to recursively walk. When + * timing how long it takes to pretty print jQuery, this optimization + * brought the time down from ~390 ms to ~190ms! + * + * @param String str + * The string to be added to the result. + * @param Number line + * The line number the string came from in the ugly source. + * @param Number column + * The column number the string came from in the ugly source. + */ + var write = (function () { + var buffer = []; + var bufferLine = -1; + var bufferColumn = -1; + return function write(str, line, column) { + if (line != null && bufferLine === -1) { + bufferLine = line; + } + if (column != null && bufferColumn === -1) { + bufferColumn = column; + } + buffer.push(str); + + if (str == "\n") { + var lineStr = ""; + for (var i = 0, len = buffer.length; i < len; i++) { + lineStr += buffer[i]; + } + result.add(new SourceNode(bufferLine, bufferColumn, options.url, lineStr)); + buffer.splice(0, buffer.length); + bufferLine = -1; + bufferColumn = -1; + } + } + }()); + + // Whether or not we added a newline on after we added the last token. + var addedNewline = false; + + // The current token we will be adding to the pretty printed code. + var token; + + // Shorthand for token.type.type, so we don't have to repeatedly access + // properties. + var ttt; + + // Shorthand for token.type.keyword, so we don't have to repeatedly access + // properties. + var ttk; + + // The last token we added to the pretty printed code. + var lastToken; + + // Stack of token types/keywords that can affect whether we want to add a + // newline or a space. We can make that decision based on what token type is + // on the top of the stack. For example, a comma in a parameter list should + // be followed by a space, while a comma in an object literal should be + // followed by a newline. + // + // Strings that go on the stack: + // + // - "{" + // - "(" + // - "[" + // - "[\n" + // - "do" + // - "?" + // - "case" + // - "default" + // + // The difference between "[" and "[\n" is that "[\n" is used when we are + // treating "[" and "]" tokens as line delimiters and should increment and + // decrement the indent level when we find them. + var stack = []; + + // Acorn's tokenizer will always yield comments *before* the token they + // follow (unless the very first thing in the source is a comment), so we + // have to queue the comments in order to pretty print them in the correct + // location. For example, the source file: + // + // foo + // // a + // // b + // bar + // + // When tokenized by acorn, gives us the following token stream: + // + // [ '// a', '// b', foo, bar ] + var commentQueue = []; + + var getToken = acorn.tokenize(input, { + locations: true, + sourceFile: options.url, + onComment: function (block, text, start, end, startLoc, endLoc) { + if (lastToken) { + commentQueue.push({ + block: block, + text: text, + line: startLoc.line, + column: startLoc.column + }); + } else { + addComment(write, indentLevel, options, block, text, startLoc.line, + startLoc.column); + addedNewline = true; + } + } + }); + + while (true) { + token = getToken(); + + ttk = token.type.keyword; + ttt = token.type.type; + + if (ttt == "eof") { + if (!addedNewline) { + write("\n"); + } + break; + } + + token.isArrayLiteral = isArrayLiteral(token, lastToken); + + if (belongsOnStack(token)) { + if (token.isArrayLiteral) { + stack.push("[\n"); + } else { + stack.push(ttt || ttk); + } + } + + if (decrementsIndent(ttt, stack)) { + indentLevel--; + } + + prependWhiteSpace(token, lastToken, addedNewline, write, options, + indentLevel, stack); + addToken(token, write, options); + addedNewline = appendNewline(token, write, stack); + + if (shouldStackPop(token, stack)) { + stack.pop(); + } + + if (incrementsIndent(token)) { + indentLevel++; + } + + // Acorn's tokenizer re-uses tokens, so we have to copy the last token on + // every iteration. We follow acorn's lead here, and reuse the lastToken + // object the same way that acorn reuses the token object. This allows us + // to avoid allocations and minimize GC pauses. + if (!lastToken) { + lastToken = { startLoc: {}, endLoc: {} }; + } + lastToken.start = token.start; + lastToken.end = token.end; + lastToken.startLoc.line = token.startLoc.line; + lastToken.startLoc.column = token.startLoc.column; + lastToken.endLoc.line = token.endLoc.line; + lastToken.endLoc.column = token.endLoc.column; + lastToken.type = token.type; + lastToken.value = token.value; + lastToken.isArrayLiteral = token.isArrayLiteral; + + // Apply all the comments that have been queued up. + if (commentQueue.length) { + if (!addedNewline) { + write("\n"); + } + for (var i = 0, n = commentQueue.length; i < n; i++) { + var comment = commentQueue[i]; + addComment(write, indentLevel, options, comment.block, comment.text, + comment.line, comment.column); + } + addedNewline = true; + commentQueue.splice(0, commentQueue.length); + } + } + + return result.toStringWithSourceMap({ file: options.url }); + }; + +}.bind(this))); diff --git a/toolkit/devtools/escodegen/tests/unit/head_escodegen.js b/toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js similarity index 82% rename from toolkit/devtools/escodegen/tests/unit/head_escodegen.js rename to toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js index 1a51912ec72..0dfdca9c59e 100644 --- a/toolkit/devtools/escodegen/tests/unit/head_escodegen.js +++ b/toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js @@ -7,6 +7,11 @@ const Cr = Components.results; const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const { require } = devtools; +this.sourceMap = require("source-map"); +this.acorn = require("acorn"); +this.prettyFast = require("devtools/pretty-fast"); +const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); + // Register a console listener, so console messages don't just disappear // into the ether. let errorCount = 0; @@ -31,7 +36,7 @@ let listener = { } } - do_throw("head_dbg.js got console message: " + string + "\n"); + do_throw("head_pretty-fast.js got console message: " + string + "\n"); } }; diff --git a/toolkit/devtools/pretty-fast/tests/unit/test.js b/toolkit/devtools/pretty-fast/tests/unit/test.js new file mode 100644 index 00000000000..bada192e487 --- /dev/null +++ b/toolkit/devtools/pretty-fast/tests/unit/test.js @@ -0,0 +1,470 @@ +/* + * Copyright 2013 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.md or: + * http://opensource.org/licenses/BSD-2-Clause + */ +var prettyFast = this.prettyFast || require("./pretty-fast"); + +var testCases = [ + { + name: "Simple function", + input: "function foo() { bar(); }", + output: "function foo() {\n" + + " bar();\n" + + "}\n", + mappings: [ + // function foo() { + { + inputLine: 1, + outputLine: 1 + }, + // bar(); + { + inputLine: 1, + outputLine: 2 + }, + // } + { + inputLine: 1, + outputLine: 3 + }, + ] + }, + + { + name: "Nested function", + input: "function foo() { function bar() { debugger; } bar(); }", + output: "function foo() {\n" + + " function bar() {\n" + + " debugger;\n" + + " }\n" + + " bar();\n" + + "}\n", + mappings: [ + // function bar() { + { + inputLine: 1, + outputLine: 2 + }, + // debugger; + { + inputLine: 1, + outputLine: 3 + }, + // bar(); + { + inputLine: 1, + outputLine: 5 + }, + ] + }, + + { + name: "Immediately invoked function expression", + input: "(function(){thingy()}())", + output: "(function () {\n" + + " thingy()\n" + + "}())\n" + }, + + { + name: "Single line comment", + input: "// Comment\n" + + "function foo() { bar(); }\n", + output: "// Comment\n" + + "function foo() {\n" + + " bar();\n" + + "}\n", + mappings: [ + // // Comment + { + inputLine: 1, + outputLine: 1 + } + ] + }, + + { + name: "Multi line comment", + input: "/* Comment\n" + + "more comment */\n" + + "function foo() { bar(); }\n", + output: "/* Comment\n" + + "more comment */\n" + + "function foo() {\n" + + " bar();\n" + + "}\n", + mappings: [ + // /* Comment + { + inputLine: 1, + outputLine: 1 + }, + // \nmore comment */ + { + inputLine: 1, + outputLine: 2 + } + ] + }, + + { + name: "Null assignment", + input: "var i=null;\n", + output: "var i = null;\n", + mappings: [ + { + inputLine: 1, + outputLine: 1 + } + ] + }, + + { + name: "Undefined assignment", + input: "var i=undefined;\n", + output: "var i = undefined;\n" + }, + + { + name: "Void 0 assignment", + input: "var i=void 0;\n", + output: "var i = void 0;\n" + }, + + { + name: "This property access", + input: "var foo=this.foo;\n", + output: "var foo = this.foo;\n" + }, + + { + name: "True assignment", + input: "var foo=true;\n", + output: "var foo = true;\n" + }, + + { + name: "False assignment", + input: "var foo=false;\n", + output: "var foo = false;\n" + }, + + { + name: "For loop", + input: "for (var i = 0; i < n; i++) { console.log(i); }", + output: "for (var i = 0; i < n; i++) {\n" + + " console.log(i);\n" + + "}\n", + mappings: [ + // for (var i = 0; i < n; i++) { + { + inputLine: 1, + outputLine: 1 + }, + // console.log(i); + { + inputLine: 1, + outputLine: 2 + }, + ] + }, + + { + name: "String with semicolon", + input: "var foo = ';';\n", + output: "var foo = ';';\n" + }, + + { + name: "String with quote", + input: "var foo = \"'\";\n", + output: "var foo = '\'';\n" + }, + + { + name: "Function calls", + input: "var result=func(a,b,c,d);", + output: "var result = func(a, b, c, d);\n" + }, + + { + name: "Regexp", + input: "var r=/foobar/g;", + output: "var r = /foobar/g;\n" + }, + + { + name: "In operator", + input: "if(foo in bar){doThing()}", + output: "if (foo in bar) {\n" + + " doThing()\n" + + "}\n" + }, + + { + name: "With statement", + input: "with(obj){crock()}", + output: "with (obj) {\n" + + " crock()\n" + + "}\n" + }, + + { + name: "New expression", + input: "var foo=new Foo();", + output: "var foo = new Foo();\n" + }, + + { + name: "Continue/break statements", + input: "while(1){if(x){continue}if(y){break}}", + output: "while (1) {\n" + + " if (x) {\n" + + " continue\n" + + " }\n" + + " if (y) {\n" + + " break\n" + + " }\n" + + "}\n" + }, + + { + name: "Instanceof", + input: "var a=x instanceof y;", + output: "var a = x instanceof y;\n" + }, + + { + name: "Binary operators", + input: "var a=5*30;var b=5>>3;", + output: "var a = 5 * 30;\n" + + "var b = 5 >> 3;\n" + }, + + { + name: "Delete", + input: "delete obj.prop;", + output: "delete obj.prop;\n" + }, + + { + name: "Try/catch/finally statement", + input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}", + output: "try {\n" + + " dangerous()\n" + + "} catch (e) {\n" + + " handle(e)\n" + + "} finally {\n" + + " cleanup()\n" + + "}\n" + }, + + { + name: "If/else statement", + input: "if(c){then()}else{other()}", + output: "if (c) {\n" + + " then()\n" + + "} else {\n" + + " other()\n" + + "}\n" + }, + + { + name: "If/else without curlies", + input: "if(c) a else b", + output: "if (c) a else b\n" + }, + + { + name: "Objects", + input: "var o={a:1,\n" + + " b:2};", + output: "var o = {\n" + + " a: 1,\n" + + " b: 2\n" + + "};\n", + mappings: [ + // a: 1, + { + inputLine: 1, + outputLine: 2 + }, + // b: 2 + { + inputLine: 2, + outputLine: 3 + }, + ] + }, + + { + name: "Do/while loop", + input: "do{x}while(y)", + output: "do {\n" + + " x\n" + + "} while (y)\n" + }, + + { + name: "Arrays", + input: "var a=[1,2,3];", + output: "var a = [\n" + + " 1,\n" + + " 2,\n" + + " 3\n" + + "];\n" + }, + + { + name: "Code that relies on ASI", + input: "var foo = 10\n" + + "var bar = 20\n" + + "function g() {\n" + + " a()\n" + + " b()\n" + + "}", + output: "var foo = 10\n" + + "var bar = 20\n" + + "function g() {\n" + + " a()\n" + + " b()\n" + + "}\n" + }, + + { + name: "Ternary operator", + input: "bar?baz:bang;", + output: "bar ? baz : bang;\n" + }, + + { + name: "Switch statements", + input: "switch(x){case a:foo();break;default:bar()}", + output: "switch (x) {\n" + + "case a:\n" + + " foo();\n" + + " break;\n" + + "default:\n" + + " bar()\n" + + "}\n" + }, + + { + name: "Multiple single line comments", + input: "function f() {\n" + + " // a\n" + + " // b\n" + + " // c\n" + + "}\n", + output: "function f() {\n" + + " // a\n" + + " // b\n" + + " // c\n" + + "}\n", + }, + + { + name: "Indented multiline comment", + input: "function foo() {\n" + + " /**\n" + + " * java doc style comment\n" + + " * more comment\n" + + " */\n" + + " bar();\n" + + "}\n", + output: "function foo() {\n" + + " /**\n" + + " * java doc style comment\n" + + " * more comment\n" + + " */\n" + + " bar();\n" + + "}\n", + }, + + { + name: "ASI return", + input: "function f() {\n" + + " return\n" + + " {}\n" + + "}\n", + output: "function f() {\n" + + " return\n" + + " {\n" + + " }\n" + + "}\n", + }, + + { + name: "Non-ASI property access", + input: "[1,2,3]\n" + + "[0]", + output: "[\n" + + " 1,\n" + + " 2,\n" + + " 3\n" + + "]\n" + + "[0]\n" + }, + + { + name: "Non-ASI in", + input: "'x'\n" + + "in foo", + output: "'x' in foo\n" + }, + + { + name: "Non-ASI function call", + input: "f\n" + + "()", + output: "f()\n" + }, + + { + name: "Non-ASI new", + input: "new\n" + + "F()", + output: "new F()\n" + }, + +]; + +var sourceMap = this.sourceMap || require("source-map"); + +function run_test() { + testCases.forEach(function (test) { + console.log(test.name); + + var actual = prettyFast(test.input, { + indent: " ", + url: "test.js" + }); + + if (actual.code !== test.output) { + throw new Error("Expected:\n" + test.output + + "\nGot:\n" + actual.code); + } + + if (test.mappings) { + var smc = new sourceMap.SourceMapConsumer(actual.map.toJSON()); + test.mappings.forEach(function (m) { + var query = { line: m.outputLine, column: 0 }; + var original = smc.originalPositionFor(query); + if (original.line != m.inputLine) { + throw new Error("Querying:\n" + JSON.stringify(query, null, 2) + "\n" + + "Expected line:\n" + m.inputLine + "\n" + + "Got:\n" + JSON.stringify(original, null, 2)); + } + }); + } + }); + console.log("✓ All tests pass!"); +} + +// Only run the tests if this is node and we are running this file +// directly. (Firefox's test runner will import this test file, and then call +// run_test itself.) +if (typeof exports == "object") { + run_test(); +} diff --git a/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini b/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini new file mode 100644 index 00000000000..94833e29289 --- /dev/null +++ b/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = head_pretty-fast.js +tail = + +[test.js] diff --git a/toolkit/devtools/server/actors/pretty-print-worker.js b/toolkit/devtools/server/actors/pretty-print-worker.js index 404b24390a8..07fad4eaafe 100644 --- a/toolkit/devtools/server/actors/pretty-print-worker.js +++ b/toolkit/devtools/server/actors/pretty-print-worker.js @@ -8,11 +8,11 @@ * This file is meant to be loaded as a ChromeWorker. It accepts messages which * have data of the form: * - * { id, url, indent, ast } + * { id, url, indent, source } * * Where `id` is a unique ID to identify this request, `url` is the url of the * source being pretty printed, `indent` is the number of spaces to indent the - * code by, and `ast` is the source's abstract syntax tree. + * code by, and `source` is the source text. * * On success, the worker responds with a message of the form: * @@ -20,25 +20,23 @@ * * Where `id` is the same unique ID from the request, `code` is the pretty * printed source text, and `mappings` is an array or source mappings from the - * pretty printed code to the AST's source locations. + * pretty printed code back to the ugly source text. * * In the case of an error, the worker responds with a message of the form: * - * { error } + * { id, error } */ -importScripts("resource://gre/modules/devtools/escodegen/escodegen.worker.js"); +importScripts("resource://gre/modules/devtools/acorn.js"); +importScripts("resource://gre/modules/devtools/source-map.js"); +importScripts("resource://gre/modules/devtools/pretty-fast.js"); -self.onmessage = ({ data: { id, url, indent, ast } }) => { +self.onmessage = (event) => { + const { data: { id, url, indent, source } } = event; try { - const prettified = escodegen.generate(ast, { - format: { - indent: { - style: " ".repeat(indent) - } - }, - sourceMap: url, - sourceMapWithCode: true + const prettified = prettyFast(source, { + url: url, + indent: " ".repeat(indent) }); self.postMessage({ @@ -48,6 +46,7 @@ self.onmessage = ({ data: { id, url, indent, ast } }) => { }); } catch (e) { self.postMessage({ + id: id, error: e.message + "\n" + e.stack }); } diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index f11ceb4870b..715c9d52713 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -497,8 +497,8 @@ ThreadActor.prototype = { return this._prettyPrintWorker; }, - _onPrettyPrintError: function (error) { - reportError(new Error(error)); + _onPrettyPrintError: function ({ message, filename, lineno }) { + reportError(new Error(message + " @ " + filename + ":" + lineno)); }, _onPrettyPrintMsg: function ({ data }) { @@ -2459,7 +2459,6 @@ SourceActor.prototype = { onPrettyPrint: function ({ indent }) { this.threadActor.sources.prettyPrint(this._url, indent); return this._getSourceText() - .then(this._parseAST) .then(this._sendToPrettyPrintWorker(indent)) .then(this._invertSourceMap) .then(this._saveMap) @@ -2480,13 +2479,6 @@ SourceActor.prototype = { }); }, - /** - * Parse the source content into an AST. - */ - _parseAST: function SA__parseAST({ content}) { - return Reflect.parse(content); - }, - /** * Return a function that sends a request to the pretty print worker, waits on * the worker's response, and then returns the pretty printed code. @@ -2500,7 +2492,7 @@ SourceActor.prototype = { * printed code, and `mappings` is an array of source mappings. */ _sendToPrettyPrintWorker: function SA__sendToPrettyPrintWorker(aIndent) { - return aAST => { + return ({ content }) => { const deferred = promise.defer(); const id = Math.random(); @@ -2522,7 +2514,7 @@ SourceActor.prototype = { id: id, url: this._url, indent: aIndent, - ast: aAST + source: content }); return deferred.promise; diff --git a/toolkit/devtools/server/main.js b/toolkit/devtools/server/main.js index dad9ea1106a..a221682c3b8 100644 --- a/toolkit/devtools/server/main.js +++ b/toolkit/devtools/server/main.js @@ -74,7 +74,6 @@ loadSubScript.call(this, "resource://gre/modules/commonjs/sdk/core/promise.js"); this.require = loaderRequire; Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); -const escodegen = localRequire("escodegen/escodegen"); loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js"); diff --git a/toolkit/devtools/sourcemap/Makefile.in b/toolkit/devtools/sourcemap/Makefile.in index aad3588f054..aa6749658d5 100644 --- a/toolkit/devtools/sourcemap/Makefile.in +++ b/toolkit/devtools/sourcemap/Makefile.in @@ -7,3 +7,4 @@ include $(topsrcdir)/config/rules.mk libs:: $(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools + $(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools diff --git a/toolkit/devtools/sourcemap/source-map.js b/toolkit/devtools/sourcemap/source-map.js new file mode 100644 index 00000000000..57fe57f02f3 --- /dev/null +++ b/toolkit/devtools/sourcemap/source-map.js @@ -0,0 +1,1929 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/** + * Define a module along with a payload. + * @param {string} moduleName Name for the payload + * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec + * @param {function} payload Function with (require, exports, module) params + */ +function define(moduleName, deps, payload) { + if (typeof moduleName != "string") { + throw new TypeError('Expected string, got: ' + moduleName); + } + + if (arguments.length == 2) { + payload = deps; + } + + if (moduleName in define.modules) { + throw new Error("Module already defined: " + moduleName); + } + define.modules[moduleName] = payload; +}; + +/** + * The global store of un-instantiated modules + */ +define.modules = {}; + + +/** + * We invoke require() in the context of a Domain so we can have multiple + * sets of modules running separate from each other. + * This contrasts with JSMs which are singletons, Domains allows us to + * optionally load a CommonJS module twice with separate data each time. + * Perhaps you want 2 command lines with a different set of commands in each, + * for example. + */ +function Domain() { + this.modules = {}; + this._currentModule = null; +} + +(function () { + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * There are 2 ways to call this, either with an array of dependencies and a + * callback to call when the dependencies are found (which can happen + * asynchronously in an in-page context) or with a single string an no callback + * where the dependency is resolved synchronously and returned. + * The API is designed to be compatible with the CommonJS AMD spec and + * RequireJS. + * @param {string[]|string} deps A name, or names for the payload + * @param {function|undefined} callback Function to call when the dependencies + * are resolved + * @return {undefined|object} The module required or undefined for + * array/callback method + */ + Domain.prototype.require = function(deps, callback) { + if (Array.isArray(deps)) { + var params = deps.map(function(dep) { + return this.lookup(dep); + }, this); + if (callback) { + callback.apply(null, params); + } + return undefined; + } + else { + return this.lookup(deps); + } + }; + + function normalize(path) { + var bits = path.split('/'); + var i = 1; + while (i < bits.length) { + if (bits[i] === '..') { + bits.splice(i-1, 1); + } else if (bits[i] === '.') { + bits.splice(i, 1); + } else { + i++; + } + } + return bits.join('/'); + } + + function join(a, b) { + a = a.trim(); + b = b.trim(); + if (/^\//.test(b)) { + return b; + } else { + return a.replace(/\/*$/, '/') + b; + } + } + + function dirname(path) { + var bits = path.split('/'); + bits.pop(); + return bits.join('/'); + } + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * @param {string} moduleName A name for the payload to lookup + * @return {object} The module specified by aModuleName or null if not found. + */ + Domain.prototype.lookup = function(moduleName) { + if (/^\./.test(moduleName)) { + moduleName = normalize(join(dirname(this._currentModule), moduleName)); + } + + if (moduleName in this.modules) { + var module = this.modules[moduleName]; + return module; + } + + if (!(moduleName in define.modules)) { + throw new Error("Module not defined: " + moduleName); + } + + var module = define.modules[moduleName]; + + if (typeof module == "function") { + var exports = {}; + var previousModule = this._currentModule; + this._currentModule = moduleName; + module(this.require.bind(this), exports, { id: moduleName, uri: "" }); + this._currentModule = previousModule; + module = exports; + } + + // cache the resulting module object for next time + this.modules[moduleName] = module; + + return module; + }; + +}()); + +define.Domain = Domain; +define.globalDomain = new Domain(); +var require = define.globalDomain.require.bind(define.globalDomain); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-map-generator', ['require', 'exports', 'module' , 'source-map/base64-vlq', 'source-map/util', 'source-map/array-set'], function(require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + 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 + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); + } + }; + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guaranteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(util.compareByGeneratedPositions); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; + + 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.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; + + result += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + 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. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/base64'], function(require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/base64', ['require', 'exports', 'module' , ], function(require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + + 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; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + 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; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'source-map/util', 'source-map/binary-search', 'source-map/array-set', 'source-map/base64-vlq'], function(require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + var names = util.getArg(sourceMap, 'names'); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } + + // 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._mappings = mappings; + this.file = file; + } + + /** + * 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. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + // `__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 (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this.__generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this.__originalMappings.push(mapping); + } + } + } + + this.__originalMappings.sort(util.compareByOriginalPositions); + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + 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.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/binary-search', ['require', 'exports', 'module' , ], function(require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + 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]]); + } + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + 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) { + 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({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +this.sourceMap = { + SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, + SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, + SourceNode: require('source-map/source-node').SourceNode +}; From 6b1e3de27120b28ad65e7b63f5f25a0bc777db9a Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Tue, 5 Nov 2013 22:07:55 -0800 Subject: [PATCH 45/53] Bug 933275 - Switching WebrtcUI.js to use the new notifications.jsm api; r=wesj --- mobile/android/chrome/content/WebrtcUI.js | 37 +++++++++++------------ mobile/android/modules/Notifications.jsm | 8 +++++ 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/mobile/android/chrome/content/WebrtcUI.js b/mobile/android/chrome/content/WebrtcUI.js index a7e474b371a..3c7def88f0c 100644 --- a/mobile/android/chrome/content/WebrtcUI.js +++ b/mobile/android/chrome/content/WebrtcUI.js @@ -3,7 +3,11 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; +XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm"); + var WebrtcUI = { + _notificationId: null, + observe: function(aSubject, aTopic, aData) { if (aTopic === "getUserMedia:request") { this.handleRequest(aSubject, aTopic, aData); @@ -17,24 +21,17 @@ var WebrtcUI = { } }, - get notificationId() { - delete this.notificationId; - return this.notificationId = uuidgen.generateUUID().toString(); - }, - notify: function() { let windows = MediaManagerService.activeMediaCaptureWindows; let count = windows.Count(); let msg = {}; if (count == 0) { - msg = { - type: "Notification:Hide", - id: this.notificationId + if (this._notificationId) { + Notifications.cancel(this._notificationId); + this._notificationId = null; } } else { - msg = { - type: "Notification:Show", - id: this.notificationId, + let notificationOptions = { title: Strings.brand.GetStringFromName("brandShortName"), when: null, // hide the date row light: [0xFF9500FF, 1000, 1000], @@ -53,24 +50,26 @@ var WebrtcUI = { } if (cameraActive && audioActive) { - msg.text = Strings.browser.GetStringFromName("getUserMedia.sharingCameraAndMicrophone.message2"); - msg.smallicon = "drawable:alert_mic_camera"; + notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCameraAndMicrophone.message2"); + notificationOptions.icon = "drawable:alert_mic_camera"; } else if (cameraActive) { - msg.text = Strings.browser.GetStringFromName("getUserMedia.sharingCamera.message2"); - msg.smallicon = "drawable:alert_camera"; + notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingCamera.message2"); + notificationOptions.icon = "drawable:alert_camera"; } else if (audioActive) { - msg.text = Strings.browser.GetStringFromName("getUserMedia.sharingMicrophone.message2"); - msg.smallicon = "drawable:alert_mic"; + notificationOptions.message = Strings.browser.GetStringFromName("getUserMedia.sharingMicrophone.message2"); + notificationOptions.icon = "drawable:alert_mic"; } else { // somethings wrong. lets throw throw "Couldn't find any cameras or microphones being used" } + if (this._notificationId) + Notifications.update(this._notificationId, notificationOptions); + else + this._notificationId = Notifications.create(notificationOptions); if (count > 1) msg.count = count; } - - sendMessageToJava(msg); }, handleRequest: function handleRequest(aSubject, aTopic, aData) { diff --git a/mobile/android/modules/Notifications.jsm b/mobile/android/modules/Notifications.jsm index 1da8eca7585..686fc974c49 100644 --- a/mobile/android/modules/Notifications.jsm +++ b/mobile/android/modules/Notifications.jsm @@ -79,6 +79,11 @@ Notification.prototype = { this._cookie = aOptions.cookie; else this._cookie = null; + + if ("light" in aOptions && aOptions.light != null) + this._light = aOptions.light; + else + this._light = null; }, show: function() { @@ -116,6 +121,9 @@ Notification.prototype = { } } + if (this._light) + msg.light = this._light; + Services.androidBridge.handleGeckoMessage(JSON.stringify(msg)); return this; }, From 5afecb0baeac11f0140b7c023733a7121f27d6cb Mon Sep 17 00:00:00 2001 From: Wes Johnston Date: Tue, 5 Nov 2013 22:08:15 -0800 Subject: [PATCH 46/53] Bug 932816 - Added a 'persistent' flag to the api in order to avoid to clear downloads notifications; r=wesj --- mobile/android/base/GeckoApp.java | 1 + mobile/android/base/NotificationHelper.java | 25 +++++++++++++++------ mobile/android/chrome/content/downloads.js | 1 + mobile/android/modules/Notifications.jsm | 9 ++++---- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index 44d2767e972..4be136f1054 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -2053,6 +2053,7 @@ abstract public class GeckoApp mPromptService.destroy(); if (mTextSelection != null) mTextSelection.destroy(); + NotificationHelper.destroy(); if (SmsManager.getInstance() != null) { SmsManager.getInstance().stop(); diff --git a/mobile/android/base/NotificationHelper.java b/mobile/android/base/NotificationHelper.java index a933a24ceba..97454ea61f4 100644 --- a/mobile/android/base/NotificationHelper.java +++ b/mobile/android/base/NotificationHelper.java @@ -51,6 +51,7 @@ public final class NotificationHelper implements GeckoEventListener { private static final String ACTION_ID_ATTR = "buttonId"; private static final String ACTION_TITLE_ATTR = "title"; private static final String ACTION_ICON_ATTR = "icon"; + private static final String PERSISTENT_ATTR = "persistent"; private static final String NOTIFICATION_SCHEME = "moz-notification"; @@ -60,7 +61,7 @@ public final class NotificationHelper implements GeckoEventListener { private static final String CLOSED_EVENT = "notification-closed"; private static Context mContext; - private static Set mShowing; + private static Set mClearableNotifications; private static BroadcastReceiver mReceiver; private static NotificationHelper mInstance; @@ -73,7 +74,7 @@ public final class NotificationHelper implements GeckoEventListener { } mInstance = new NotificationHelper(); mContext = context; - mShowing = new HashSet(); + mClearableNotifications = new HashSet(); registerEventListener("Notification:Show"); registerEventListener("Notification:Hide"); registerReceiver(context); @@ -126,7 +127,7 @@ public final class NotificationHelper implements GeckoEventListener { // In case the user swiped out the notification, we empty the id // set. if (CLEARED_EVENT.equals(notificationType)) { - mShowing.remove(id); + mClearableNotifications.remove(id); } if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { @@ -283,8 +284,12 @@ public final class NotificationHelper implements GeckoEventListener { builder.setDeleteIntent(deletePendingIntent); GeckoAppShell.sNotificationClient.add(id.hashCode(), builder.build()); - if (!mShowing.contains(id)) { - mShowing.add(id); + + boolean persistent = message.optBoolean(PERSISTENT_ATTR); + // We add only not persistent notifications to the list since we want to purge only + // them when geckoapp is destroyed. + if (!persistent && !mClearableNotifications.contains(id)) { + mClearableNotifications.add(id); } } @@ -316,13 +321,19 @@ public final class NotificationHelper implements GeckoEventListener { public void hideNotification(String id) { GeckoAppShell.sNotificationClient.remove(id.hashCode()); - mShowing.remove(id); + mClearableNotifications.remove(id); sendNotificationWasClosed(id); } private void clearAll() { - for (String id : mShowing) { + for (String id : mClearableNotifications) { hideNotification(id); } } + + public static void destroy() { + if (mInstance != null) { + mInstance.clearAll(); + } + } } diff --git a/mobile/android/chrome/content/downloads.js b/mobile/android/chrome/content/downloads.js index 60c8d615fae..51c6f04d7bc 100644 --- a/mobile/android/chrome/content/downloads.js +++ b/mobile/android/chrome/content/downloads.js @@ -208,6 +208,7 @@ function DownloadNotifOptions (aDownload, aTitle, aMessage) { this.message = aMessage; this.buttons = null; this.cookie = aDownload.guid; + this.persistent = true; } function DownloadProgressNotifOptions (aDownload, aButtons) { diff --git a/mobile/android/modules/Notifications.jsm b/mobile/android/modules/Notifications.jsm index 686fc974c49..64d1f0e3270 100644 --- a/mobile/android/modules/Notifications.jsm +++ b/mobile/android/modules/Notifications.jsm @@ -80,10 +80,10 @@ Notification.prototype = { else this._cookie = null; - if ("light" in aOptions && aOptions.light != null) - this._light = aOptions.light; + if ("persistent" in aOptions && aOptions.persistent != null) + this._persistent = aOptions.persistent; else - this._light = null; + this._persistent = false; }, show: function() { @@ -93,7 +93,8 @@ Notification.prototype = { title: this._title, smallIcon: this._icon, ongoing: this._ongoing, - when: this._when + when: this._when, + persistent: this._persistent }; if (this._message) From 3d08ce3b7aab35462b31a37ca11066da319a03b0 Mon Sep 17 00:00:00 2001 From: Mark Capella Date: Tue, 5 Nov 2013 22:10:30 -0800 Subject: [PATCH 47/53] Bug 840144 - Make about:config prettier on Android. r=wesj --- .../robocop/FennecNativeActions.java.in | 2 + .../base/tests/testSystemPages.java.in | 2 +- mobile/android/chrome/content/config.js | 664 ++++++++++++++++++ mobile/android/chrome/content/config.xhtml | 349 ++------- mobile/android/chrome/jar.mn | 1 + .../android/locales/en-US/chrome/config.dtd | 20 +- .../locales/en-US/chrome/config.properties | 18 +- mobile/android/themes/core/config.css | 330 ++++++++- .../android/themes/core/images/arrowup-16.png | Bin 0 -> 262 bytes mobile/android/themes/core/images/lock.png | Bin 0 -> 636 bytes mobile/android/themes/core/images/search.png | Bin 0 -> 858 bytes .../android/themes/core/images/textfield.png | Bin 0 -> 166 bytes mobile/android/themes/core/jar.mn | 5 + 13 files changed, 1063 insertions(+), 328 deletions(-) create mode 100644 mobile/android/chrome/content/config.js create mode 100644 mobile/android/themes/core/images/arrowup-16.png create mode 100644 mobile/android/themes/core/images/lock.png create mode 100644 mobile/android/themes/core/images/search.png create mode 100644 mobile/android/themes/core/images/textfield.png diff --git a/build/mobile/robocop/FennecNativeActions.java.in b/build/mobile/robocop/FennecNativeActions.java.in index 607ea389925..7b2492fb0a9 100644 --- a/build/mobile/robocop/FennecNativeActions.java.in +++ b/build/mobile/robocop/FennecNativeActions.java.in @@ -421,7 +421,9 @@ public class FennecNativeActions implements Actions { // success break; } + // we got a notify() before we could wait long enough, so we need to start over + // Note, moving the goal post might have us race against a "drawFinished" flood startTime = endTime; } } diff --git a/mobile/android/base/tests/testSystemPages.java.in b/mobile/android/base/tests/testSystemPages.java.in index 87b0635cd35..b48b47a67eb 100644 --- a/mobile/android/base/tests/testSystemPages.java.in +++ b/mobile/android/base/tests/testSystemPages.java.in @@ -32,7 +32,7 @@ public class testSystemPages extends PixelTest { /* Verify that the search field is not in the focus by pressing back. That will load the previous about: page if there is no the keyboard to dismiss, meaning that the search field was not in focus */ - loadAndPaint("about:config"); + loadAndPaint("about:about"); // Press back to verify if the keyboard is dismissed or the previous about: page loads mActions.sendSpecialKey(Actions.SpecialKey.BACK); diff --git a/mobile/android/chrome/content/config.js b/mobile/android/chrome/content/config.js new file mode 100644 index 00000000000..b1bda76a661 --- /dev/null +++ b/mobile/android/chrome/content/config.js @@ -0,0 +1,664 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +"use strict"; + +const {classes: Cc, interfaces: Ci, manager: Cm, utils: Cu} = Components; +Cu.import("resource://gre/modules/Services.jsm"); + +const VKB_ENTER_KEY = 13; // User press of VKB enter key +const INITIAL_PAGE_DELAY = 500; // Initial pause on program start for scroll alignment +const PREFS_BUFFER_MAX = 30; // Max prefs buffer size for getPrefsBuffer() +const PAGE_SCROLL_TRIGGER = 200; // Triggers additional getPrefsBuffer() on user scroll-to-bottom +const FILTER_CHANGE_TRIGGER = 200; // Delay between responses to filterInput changes +const INNERHTML_VALUE_DELAY = 100; // Delay before providing prefs innerHTML value + +let gStringBundle = Services.strings.createBundle("chrome://browser/locale/config.properties"); +let gClipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper); + + +/* ============================== NewPrefDialog ============================== + * + * New Preference Dialog Object and methods + * + * Implements User Interfaces for creation of a single(new) Preference setting + * + */ +var NewPrefDialog = { + + _prefsShield: null, + + _newPrefsDialog: null, + _newPrefItem: null, + _prefNameInputElt: null, + _prefTypeSelectElt: null, + + _booleanValue: null, + _booleanToggle: null, + _stringValue: null, + _intValue: null, + + _positiveButton: null, + + get type() { + return this._prefTypeSelectElt.value; + }, + + set type(aType) { + this._prefTypeSelectElt.value = aType; + switch(this._prefTypeSelectElt.value) { + case "boolean": + this._prefTypeSelectElt.selectedIndex = 0; + break; + case "string": + this._prefTypeSelectElt.selectedIndex = 1; + break; + case "int": + this._prefTypeSelectElt.selectedIndex = 2; + break; + } + + this._newPrefItem.setAttribute("typestyle", aType); + }, + + // Init the NewPrefDialog + init: function AC_init() { + this._prefsShield = document.getElementById("prefs-shield"); + + this._newPrefsDialog = document.getElementById("new-pref-container"); + this._newPrefItem = document.getElementById("new-pref-item"); + this._prefNameInputElt = document.getElementById("new-pref-name"); + this._prefTypeSelectElt = document.getElementById("new-pref-type"); + + this._booleanValue = document.getElementById("new-pref-value-boolean"); + this._stringValue = document.getElementById("new-pref-value-string"); + this._intValue = document.getElementById("new-pref-value-int"); + + this._positiveButton = document.getElementById("positive-button"); + }, + + // Called to update positive button to display text ("Create"/"Change), and enabled/disabled status + // As new pref name is initially displayed, re-focused, or modifed during user input + _updatePositiveButton: function AC_updatePositiveButton(aPrefName) { + this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.createButton"); + this._positiveButton.setAttribute("disabled", true); + if (aPrefName == "") { + return; + } + + // Avoid "private" preferences + if (/^capability\./.test(aPrefName)) { + this._positiveButton.textContent = "Private"; + return; + } + + // If item already in list, it's being changed, else added + let item = document.querySelector(".pref-item[name=" + aPrefName.quote() + "]"); + if (item) { + this._positiveButton.textContent = gStringBundle.GetStringFromName("newPref.changeButton"); + } else { + this._positiveButton.removeAttribute("disabled"); + } + }, + + // When we want to cancel/hide an existing, or show a new pref dialog + toggleShowHide: function AC_toggleShowHide() { + if (this._newPrefsDialog.classList.contains("show")) { + this.hide(); + } else { + this._show(); + } + }, + + // When we want to show the new pref dialog / shield the prefs list + _show: function AC_show() { + this._newPrefsDialog.classList.add("show"); + this._prefsShield.setAttribute("shown", true); + + // Initial default field values + this._prefNameInputElt.value = ""; + this._updatePositiveButton(this._prefNameInputElt.value); + + this.type = "boolean"; + this._booleanValue.value = "false"; + this._stringValue.value = ""; + this._intValue.value = ""; + + this._prefNameInputElt.focus(); + + window.addEventListener("keypress", this.handleKeypress, false); + }, + + // When we want to cancel/hide the new pref dialog / un-shield the prefs list + hide: function AC_hide() { + this._newPrefsDialog.classList.remove("show"); + this._prefsShield.removeAttribute("shown"); + + window.removeEventListener("keypress", this.handleKeypress, false); + }, + + // Watch user key input so we can provide Enter key action, commit input values + handleKeypress: function AC_handleKeypress(aEvent) { + // Close our VKB on new pref enter key press + if (aEvent.keyCode == VKB_ENTER_KEY) + aEvent.target.blur(); + }, + + // New prefs create dialog only allows creating a non-existing preference, doesn't allow for + // Changing an existing one on-the-fly, tap existing/displayed line item pref for that + create: function AC_create(aEvent) { + if (this._positiveButton.getAttribute("disabled") == "true") { + return; + } + + switch(this.type) { + case "boolean": + Services.prefs.setBoolPref(this._prefNameInputElt.value, (this._booleanValue.value == "true") ? true : false); + break; + case "string": + Services.prefs.setCharPref(this._prefNameInputElt.value, this._stringValue.value); + break; + case "int": + Services.prefs.setIntPref(this._prefNameInputElt.value, this._intValue.value); + break; + } + + this.hide(); + }, + + // Display proper positive button text/state on new prefs name input focus + focusName: function AC_focusName(aEvent) { + this._updatePositiveButton(aEvent.target.value); + }, + + // Display proper positive button text/state as user changes new prefs name + updateName: function AC_updateName(aEvent) { + this._updatePositiveButton(aEvent.target.value); + }, + + // In new prefs dialog, bool prefs are , as they aren't yet tied to an + // Actual Services.prefs.*etBoolPref() + toggleBoolValue: function AC_toggleBoolValue() { + this._booleanValue.value = (this._booleanValue.value == "true" ? "false" : "true"); + } +} + + +/* ============================== AboutConfig ============================== + * + * Main AboutConfig object and methods + * + * Implements User Interfaces for maintenance of a list of Preference settings + * + */ +var AboutConfig = { + + contextMenuLINode: null, + filterInput: null, + _filterPrevInput: null, + _filterChangeTimer: null, + _prefsContainer: null, + _loadingContainer: null, + _list: null, + + // Init the main AboutConfig dialog + init: function AC_init() { + this.filterInput = document.getElementById("filter-input"); + this._prefsContainer = document.getElementById("prefs-container"); + this._loadingContainer = document.getElementById("loading-container"); + + let list = Services.prefs.getChildList("", {}).filter(function(aElement) { + // Avoid "private" preferences + return !(/^capability\./.test(aElement)); + }); + this._list = list.sort().map( function AC_getMapPref(aPref) { + return new Pref(aPref); + }, this); + + // Display the current prefs list (retains searchFilter value) + this.bufferFilterInput(); + + // Setup the prefs observers + Services.prefs.addObserver("", this, false); + }, + + // Uninit the main AboutConfig dialog + uninit: function AC_uninit() { + // Remove the prefs observer + Services.prefs.removeObserver("", this); + }, + + // Clear the filterInput value, to display the entire list + clearFilterInput: function AC_clearFilterInput() { + this.filterInput.value = ""; + this.bufferFilterInput(); + }, + + // Buffer down rapid changes in filterInput value from keyboard + bufferFilterInput: function AC_bufferFilterInput() { + if (this._filterChangeTimer) { + clearTimeout(this._filterChangeTimer); + } + + this._filterChangeTimer = setTimeout((function() { + this._filterChangeTimer = null; + // Display updated prefs list when filterInput value settles + this._displayNewList(); + }).bind(this), FILTER_CHANGE_TRIGGER); + }, + + // Update displayed list when filterInput value changes + _displayNewList: function AC_displayNewList() { + // This survives the search filter value past a page refresh + this.filterInput.setAttribute("value", this.filterInput.value); + + // Don't start new filter search if same as last + if (this.filterInput.value == this._filterPrevInput) { + return; + } + this._filterPrevInput = this.filterInput.value; + + // Clear list item selection / context menu, prefs list, get first buffer, set scrolling on + this.selected = ""; + this._clearPrefsContainer(); + this._addMorePrefsToContainer(); + window.onscroll = this.onScroll.bind(this); + + // Pause for screen to settle, then ensure at top + setTimeout((function() { + window.scrollTo(0, 0); + }).bind(this), INITIAL_PAGE_DELAY); + }, + + // Clear the displayed preferences list + _clearPrefsContainer: function AC_clearPrefsContainer() { + // Quick clear the prefsContainer list + let empty = this._prefsContainer.cloneNode(false); + this._prefsContainer.parentNode.replaceChild(empty, this._prefsContainer); + this._prefsContainer = empty; + + // Quick clear the prefs li.HTML list + this._list.forEach(function(item) { + delete item.li; + }); + }, + + // Get a small manageable block of prefs items, and add them to the displayed list + _addMorePrefsToContainer: function AC_addMorePrefsToContainer() { + // Create filter regex + let filterExp = this.filterInput.value ? + new RegExp(this.filterInput.value, "i") : null; + + // Get a new block for the display list + let prefsBuffer = []; + for (let i = 0; i < this._list.length && prefsBuffer.length < PREFS_BUFFER_MAX; i++) { + if (!this._list[i].li && this._list[i].test(filterExp)) { + prefsBuffer.push(this._list[i]); + } + } + + // Add the new block to the displayed list + for (let i = 0; i < prefsBuffer.length; i++) { + this._prefsContainer.appendChild(prefsBuffer[i].getOrCreateNewLINode()); + } + + // Determine if anything left to add later by scrolling + let anotherPrefsBufferRemains = false; + for (let i = 0; i < this._list.length; i++) { + if (!this._list[i].li && this._list[i].test(filterExp)) { + anotherPrefsBufferRemains = true; + break; + } + } + + if (anotherPrefsBufferRemains) { + // If still more could be displayed, show the throbber + this._loadingContainer.style.display = "block"; + } else { + // If no more could be displayed, hide the throbber, and stop noticing scroll events + this._loadingContainer.style.display = "none"; + window.onscroll = null; + } + }, + + // If scrolling at the bottom, maybe add some more entries + onScroll: function AC_onScroll(aEvent) { + if (this._prefsContainer.scrollHeight - (window.pageYOffset + window.innerHeight) < PAGE_SCROLL_TRIGGER) { + if (!this._filterChangeTimer) { + this._addMorePrefsToContainer(); + } + } + }, + + + // Return currently selected list item node + get selected() { + return document.querySelector(".pref-item.selected"); + }, + + // Set list item node as selected + set selected(aSelection) { + let currentSelection = this.selected; + if (aSelection == currentSelection) { + return; + } + + // Clear any previous selection + if (currentSelection) { + currentSelection.classList.remove("selected"); + currentSelection.removeEventListener("keypress", this.handleKeypress, false); + } + + // Set any current selection + if (aSelection) { + aSelection.classList.add("selected"); + aSelection.addEventListener("keypress", this.handleKeypress, false); + } + }, + + // Watch user key input so we can provide Enter key action, commit input values + handleKeypress: function AC_handleKeypress(aEvent) { + if (aEvent.keyCode == VKB_ENTER_KEY) + aEvent.target.blur(); + }, + + // Return the target list item node of an action event + getLINodeForEvent: function AC_getLINodeForEvent(aEvent) { + let node = aEvent.target; + while (node && node.nodeName != "li") { + node = node.parentNode; + } + + return node; + }, + + // Return a pref of a list item node + _getPrefForNode: function AC_getPrefForNode(aNode) { + let pref = aNode.getAttribute("name"); + + return new Pref(pref); + }, + + // When list item name or value are tapped + selectOrToggleBoolPref: function AC_selectOrToggleBoolPref(aEvent) { + let node = this.getLINodeForEvent(aEvent); + + // If not already selected, just do so + if (this.selected != node) { + this.selected = node; + return; + } + + // If already selected, and value is boolean, toggle it + let pref = this._getPrefForNode(node); + if (pref.type != Services.prefs.PREF_BOOL) { + return; + } + + this.toggleBoolPref(aEvent); + }, + + // When finalizing list input values due to blur + setIntOrStringPref: function AC_setIntOrStringPref(aEvent) { + let node = this.getLINodeForEvent(aEvent); + + // Skip if locked + let pref = this._getPrefForNode(node); + if (pref.locked) { + return; + } + + // Boolean inputs blur to remove focus from "button" + if (pref.type == Services.prefs.PREF_BOOL) { + return; + } + + // String and Int inputs change / commit on blur + pref.value = aEvent.target.value; + }, + + // When we reset a pref to it's default value (note resetting a user created pref will delete it) + resetDefaultPref: function AC_resetDefaultPref(aEvent) { + let node = this.getLINodeForEvent(aEvent); + + // If not already selected, do so + if (this.selected != node) { + this.selected = node; + } + + // Reset will handle any locked condition + let pref = this._getPrefForNode(node); + pref.reset(); + }, + + // When we want to toggle a bool pref + toggleBoolPref: function AC_toggleBoolPref(aEvent) { + let node = this.getLINodeForEvent(aEvent); + + // Skip if locked, or not boolean + let pref = this._getPrefForNode(node); + if (pref.locked) { + return; + } + + // Toggle, and blur to remove field focus + pref.value = !pref.value; + aEvent.target.blur(); + }, + + // When Int inputs have their Up or Down arrows toggled + incrOrDecrIntPref: function AC_incrOrDecrIntPref(aEvent, aInt) { + let node = this.getLINodeForEvent(aEvent); + + // Skip if locked + let pref = this._getPrefForNode(node); + if (pref.locked) { + return; + } + + pref.value += aInt; + }, + + // Observe preference changes + observe: function AC_observe(aSubject, aTopic, aPrefName) { + let pref = new Pref(aPrefName); + + // Ignore uninteresting changes, and avoid "private" preferences + if ((aTopic != "nsPref:changed") || /^capability\./.test(pref.name)) { + return; + } + + // If pref type invalid, refresh display as user reset/removed an item from the list + if (pref.type == Services.prefs.PREF_INVALID) { + document.location.reload(); + return; + } + + // If pref not already in list, refresh display as it's being added + let item = document.querySelector(".pref-item[name=" + pref.name.quote() + "]"); + if (!item) { + document.location.reload(); + return; + } + + // Else we're modifying a pref + item.setAttribute("value", pref.value); + let input = item.querySelector("input"); + input.setAttribute("value", pref.value); + input.value = pref.value; + + pref.default ? + item.querySelector(".reset").setAttribute("disabled", "true") : + item.querySelector(".reset").removeAttribute("disabled"); + }, + + // Quick context menu helpers for about:config + clipboardCopy: function AC_clipboardCopy(aField) { + let pref = this._getPrefForNode(this.contextMenuLINode); + if (aField == 'name') { + gClipboardHelper.copyString(pref.name); + } else { + gClipboardHelper.copyString(pref.value); + } + } +} + + +/* ============================== Pref ============================== + * + * Individual Preference object / methods + * + * Defines a Pref object, a document list item tied to Preferences Services + * And the methods by which they interact. + * + */ +function Pref(aName) { + this.name = aName; +} + +Pref.prototype = { + get type() { + return Services.prefs.getPrefType(this.name); + }, + + get value() { + switch (this.type) { + case Services.prefs.PREF_BOOL: + return Services.prefs.getBoolPref(this.name); + case Services.prefs.PREF_INT: + return Services.prefs.getIntPref(this.name); + case Services.prefs.PREF_STRING: + default: + return Services.prefs.getCharPref(this.name); + } + + }, + set value(aPrefValue) { + switch (this.type) { + case Services.prefs.PREF_BOOL: + Services.prefs.setBoolPref(this.name, aPrefValue); + break; + case Services.prefs.PREF_INT: + Services.prefs.setIntPref(this.name, aPrefValue); + break; + case Services.prefs.PREF_STRING: + default: + Services.prefs.setCharPref(this.name, aPrefValue); + } + }, + + get default() { + return !Services.prefs.prefHasUserValue(this.name); + }, + + get locked() { + return Services.prefs.prefIsLocked(this.name); + }, + + reset: function AC_reset() { + Services.prefs.clearUserPref(this.name); + }, + + test: function AC_test(aValue) { + return aValue ? aValue.test(this.name) : true; + }, + + // Get existing or create new LI node for the pref + getOrCreateNewLINode: function AC_getOrCreateNewLINode() { + if (!this.li) { + this.li = document.createElement("li"); + + this.li.className = "pref-item"; + this.li.setAttribute("name", this.name); + + // Click callback to ensure list item selected even on no-action tap events + this.li.addEventListener("click", + function(aEvent) { + AboutConfig.selected = AboutConfig.getLINodeForEvent(aEvent); + }, + false + ); + + // Contextmenu callback to identify selected list item + this.li.addEventListener("contextmenu", + function(aEvent) { + AboutConfig.contextMenuLINode = AboutConfig.getLINodeForEvent(aEvent); + }, + false + ); + + this.li.setAttribute("contextmenu", "prefs-context-menu"); + + // Create list item outline, bind to object actions + this.li.innerHTML = + "
" + + this.name + + "
" + + "
" + + "" + + "" + + "
" + + gStringBundle.GetStringFromName("pref.resetButton") + + "
" + + "
" + + gStringBundle.GetStringFromName("pref.toggleButton") + + "
" + + "
" + + "
" + + "
" + + "
" + + "
"; + + // Delay providing the list item values, until the LI is returned and added to the document + setTimeout(this._valueSetup.bind(this), INNERHTML_VALUE_DELAY); + } + + return this.li; + }, + + // Initialize list item object values + _valueSetup: function AC_valueSetup() { + + this.li.setAttribute("type", this.type); + this.li.setAttribute("value", this.value); + + let valDiv = this.li.querySelector(".pref-value"); + valDiv.value = this.value; + + switch(this.type) { + case Services.prefs.PREF_BOOL: + valDiv.setAttribute("type", "button"); + this.li.querySelector(".up").setAttribute("disabled", true); + this.li.querySelector(".down").setAttribute("disabled", true); + break; + case Services.prefs.PREF_STRING: + valDiv.setAttribute("type", "text"); + this.li.querySelector(".up").setAttribute("disabled", true); + this.li.querySelector(".down").setAttribute("disabled", true); + this.li.querySelector(".toggle").setAttribute("disabled", true); + break; + case Services.prefs.PREF_INT: + valDiv.setAttribute("type", "number"); + this.li.querySelector(".toggle").setAttribute("disabled", true); + break; + } + + this.li.setAttribute("default", this.default); + if (this.default) { + this.li.querySelector(".reset").setAttribute("disabled", true); + } + + if (this.locked) { + valDiv.setAttribute("disabled", this.locked); + this.li.querySelector(".pref-name").setAttribute("locked", true); + } + } +} + diff --git a/mobile/android/chrome/content/config.xhtml b/mobile/android/chrome/content/config.xhtml index 28ec6dcff99..fd40bb51731 100644 --- a/mobile/android/chrome/content/config.xhtml +++ b/mobile/android/chrome/content/config.xhtml @@ -1,5 +1,9 @@ + + @@ -8,314 +12,75 @@ %configDTD; ]> - - + - - + + + + - + -
- - -
+
+
+
-
- -
+
+
+ +
+
+
+
-
+
- diff --git a/mobile/android/chrome/jar.mn b/mobile/android/chrome/jar.mn index 058ace4e474..cb3a78f61fe 100644 --- a/mobile/android/chrome/jar.mn +++ b/mobile/android/chrome/jar.mn @@ -9,6 +9,7 @@ chrome.jar: * content/about.xhtml (content/about.xhtml) content/config.xhtml (content/config.xhtml) + content/config.js (content/config.js) content/aboutAddons.xhtml (content/aboutAddons.xhtml) content/aboutAddons.js (content/aboutAddons.js) content/aboutCertError.xhtml (content/aboutCertError.xhtml) diff --git a/mobile/android/locales/en-US/chrome/config.dtd b/mobile/android/locales/en-US/chrome/config.dtd index 1786c7f5c02..95502af40e4 100644 --- a/mobile/android/locales/en-US/chrome/config.dtd +++ b/mobile/android/locales/en-US/chrome/config.dtd @@ -2,6 +2,20 @@ - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - - - + + + + + + + + + + + + + + + + + diff --git a/mobile/android/locales/en-US/chrome/config.properties b/mobile/android/locales/en-US/chrome/config.properties index 7a65278667a..61fdf73b329 100644 --- a/mobile/android/locales/en-US/chrome/config.properties +++ b/mobile/android/locales/en-US/chrome/config.properties @@ -2,18 +2,8 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -addPref.title=Add -addPref.selectType=Select type: -addPref.type.string=String -addPref.type.integer=Integer -addPref.type.boolean=Boolean -addPref.enterName=Enter name: +newPref.createButton=Create +newPref.changeButton=Change -togglePref.label=Toggle -modifyPref.label=Modify -modifyPref.selectText=Select value for %1$S: -modifyPref.promptText=Enter value for %1$S: -modifyPref.numberErrorTitle=Invalid Value -modifyPref.numberErrorText=The text you entered was not a number - -resetPref.label=Reset +pref.toggleButton=Toggle +pref.resetButton=Reset diff --git a/mobile/android/themes/core/config.css b/mobile/android/themes/core/config.css index 1caaf4b8790..dd25c26ba79 100644 --- a/mobile/android/themes/core/config.css +++ b/mobile/android/themes/core/config.css @@ -2,38 +2,332 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -html { - font-size: 24px; +html, +body { + margin: 0; + padding: 0; + background-color: #ced7de; + -moz-user-select: none; + font-family: "Open Sans", sans-serif; + -moz-text-size-adjust: none; } -input, -button { - font-size: 28px; - padding: 5px; +.toolbar { + width: 100%; + height: 3em; + position: fixed; + top: 0; + left: 0; + z-index: 10; + box-shadow: 0 0 3px #444; + background-color: #ced7de; + color: #000000; + font-weight: bold; + border-bottom: 2px solid; + -moz-border-bottom-colors: #ff9100 #f27900; +} + +.toolbar-container { + max-width: 40em; + margin-left: auto; + margin-right: auto; } #filter-container { - display: -moz-box; - -moz-box-align: center; + margin-top: 0.5em; + margin-bottom: 0.5em; + margin-right: 0.5em; + height: 2em; + border: 1px solid transparent; + border-image-source: url("chrome://browser/skin/images/textfield.png"); + border-image-slice: 1 1 3 1; + border-image-width: 1px 1px 3px 1px; + overflow: hidden; + display: flex; + flex-direction: row; +} + +#filter-input { + -moz-appearance: none; + border: none; + background-image: none; + background-color: transparent; + display: inline-block; + width: 12em; + min-width: 0; + color: #000000; + opacity: 1; + flex: 1 1 auto; +} + +#filter-input:-moz-placeholder { + color: rgba(255,255,255,0.5); +} + +.toolbar input { + display: inline-block; + height: 100%; + min-width: 3em; + -moz-box-sizing: border-box; + opacity: 0.75; +} + +#new-pref-toggle-button { + background-position: center center; + background-image: url("chrome://browser/skin/images/reader-plus-icon-xhdpi.png"); + background-size: 48px 48px; + height: 48px; + width: 48px; + display: inline-block; + outline-style: none; +} + +#filter-search-button { + background-image: url("chrome://browser/skin/images/search.png"); + background-size: 32px 32px; + height: 32px; + width: 32px; + display: inline-block; + outline-style: none; +} + +#filter-input-clear-button { + background-image: url("chrome://browser/skin/images/search-clear-30.png"); + background-size: 32px 32px; + height: 32px; + width: 32px; + display: inline-block; + outline-style: none; +} + +#filter-input[value=""] + #filter-input-clear-button { + display: none; +} + +.toolbar-item { + display: inline-block; + height: 3em; + min-width: 3em; + float: right; +} + +#content { + position: relative; + margin: 0; + margin-left: auto; + margin-right: auto; + padding-top: 3em; + padding-left: 0; + padding-right: 0; + min-height: 100%; + max-width: 40em; +} + +ul { + list-style-position: inside; + border: 1px solid #808080; + background-color: #ffffff; + min-height: 100%; + width: 100%; + padding-top: 0; + margin: 0; + padding-left: 0; + -moz-box-sizing: border-box; + box-shadow: 0 0 5px #000000; + overflow-x: hidden; } #new-pref-container { - margin: 10px 0; + width: 100%; + margin: 0; + background-color: #ffffff; + -moz-box-sizing: border-box; + box-shadow: 0 0 5px #000000; + overflow-x: hidden; + max-width: 40em; + max-height: 100%; + position: fixed; + top: 3em; + left: auto; + display: none; + z-index: 5; } -.pref-item { - padding-top: 10px; - border-top: 1px solid #ccc; +#new-pref-container input, +#new-pref-container select { + border: none; + background-image: none; } -.pref-item[default="false"] { - font-weight: bold; +#new-pref-container.show { + display: block; } -.pref-item > * { - margin-bottom: 10px; +li { + list-style-type: none; + border-bottom: 1px solid #d3d3d3; + opacity: 1; + background-color: #ffffff; + cursor: pointer; } -.modify-pref-button { - margin-right: 10px; +#new-pref-line-boolean, +#new-pref-value-string, +#new-pref-value-int { + display: none; +} +#new-pref-item[typestyle="boolean"] #new-pref-line-boolean, +#new-pref-item[typestyle="string"] #new-pref-value-string, +#new-pref-item[typestyle="int"] #new-pref-value-int { + display: block; +} + +.pref-name, +.pref-value { + padding: 15px 10px; + text-align: left; + text-overflow: ellipsis; + overflow: hidden; + background-image: none; +} + +.pref-value { + color: rgba(0,0,0,0.5); + flex: 1 1 auto; + border: none; + -moz-appearance: none; + background-image: none; + background-color: transparent; +} + +.pref-name[locked] { + padding-right: 20px; + background-image: url("chrome://browser/skin/images/lock.png"); + background-repeat: no-repeat; + background-position: right 50%; + background-size: auto 60%; +} + +#new-pref-name { + width: 30em; +} + +#new-pref-type { + display: inline-block !important; + border-left: 1px solid #d3d3d3; + width: 10em; + text-align: right; +} + +.pref-item-line { + border-top: 1px solid rgba(0,0,0,0.05); + color: rgba(0,0,0,0.5); + display: flex; + flex-direction: row; +} + +#new-pref-value-boolean { + flex: 1 1 auto; +} + +#new-pref-container .pref-button.toggle { + display: inline-block; + opacity: 1; + flex: 0 1 auto; + float: right; +} + +#new-pref-container .pref-button.cancel, +#new-pref-container .pref-button.create { + display: inline-block; + opacity: 1; + flex: 1 1 auto; +} + +.pref-item-line { + pointer-events: none; +} + +#new-pref-container .pref-item-line, +.pref-item.selected .pref-item-line, +.pref-item:not(.selected) .pref-button.reset { + pointer-events: auto; +} + +#new-pref-container .pref-button.create[disabled] { + color: #d3d3d3; +} + +.pref-item.selected { + background-color: rgba(0,0,255,0.05); +} + +.pref-button { + display: inline-block; + -moz-box-sizing: border-box; + text-align: center; + padding: 10px 1em; + border-left: 1px solid rgba(0,0,0,0.1); + opacity: 0; + transition-property: opacity; + transition-duration: 500ms; +} + +.pref-item.selected .pref-item-line .pref-button { + opacity: 1; +} + +.pref-item:not(.selected) .pref-item-line .pref-button:not(.reset) { + display: none; +} + +.pref-item:not(.selected) .pref-button.reset { + opacity: 1; +} + +.pref-button:active { + background-color: rgba(0,0,255,0.2); +} + +.pref-button[disabled] { + display: none; +} + +.pref-button.up { + background-image: url("chrome://browser/skin/images/arrowup-16.png"); + background-position: center center; + background-repeat: no-repeat; +} + +.pref-button.down { + background-image: url("chrome://browser/skin/images/arrowdown-16.png"); + background-position: center center; + background-repeat: no-repeat; +} + +#prefs-shield { + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.5); + position: fixed; + top: 0; + left: 0; + opacity: 0; + transition-property: opacity; + transition-duration: 500ms; + display: none; +} + +#prefs-shield[shown] { + display: block; + opacity: 1; +} + +#loading-container > li { + background-image: url(chrome://browser/skin/images/throbber.png); + background-position: center center; + background-repeat: no-repeat; + padding-left: 40px; + height: 3em; + width: 100%; } diff --git a/mobile/android/themes/core/images/arrowup-16.png b/mobile/android/themes/core/images/arrowup-16.png new file mode 100644 index 0000000000000000000000000000000000000000..16bb47b66f4e1067f50df4e46cb56f8d81b0fdd6 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4%caKYZ?lYt_f1s;*b z3=G`DAk4@xYmNj^kiEpy*OmP)6Q2+p?|CI%b)e8>PZ!4!i_>=}Zsa|zAmBRRw!@aW zH+Dx-W5u$bl=lvdQ^OU6D_Tq@F!edVTvWr!Df|7NqU@iNX{ED)Xv@67MtKL8q+Q*T zB0n@vReyN*hU?PwWT;RRJe6Mu=KEq3r()l{Xfw>y3Oe&TS9Uw(0L4=u6{1-oD!Mk4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE&~H&i>HfYh{y4}S2yNe4iI5`@cx!xRA+|^kAb4$ zb51RZNF$NXx$F-ZjTAPPuL-&K#ZVx~TrF-v@HD?fCytfgft@+VH@3RiXDY`(i3b9ce{L;pX$*O{_58Zt zf+y9h%??$+@7Y^;@!O*8#{p?du4$K6%AQ!#7Rb3^#nkqw;@fw!l#b>#oNB(XC;!@^ zGP7-`zW4oSSYUnR?BC1LcR4SVC0bX-ykL6rL${aViQC=Z3a@MaTblCLfRZmHW3GXah!!YKdz^NlIc#s#S7PDv)9@GB7mMH89aN zGz>AYv@$fZGPTq-Ft;)=sC@s^5=BF9eoAIqC2kEIn;ct#8YDqB1m~xflqVLYGB~E> hC#5QQ<|d}62BjvZR2H60wE-$(@O1TaS?83{1OQG10{;L2 literal 0 HcmV?d00001 diff --git a/mobile/android/themes/core/images/search.png b/mobile/android/themes/core/images/search.png new file mode 100644 index 0000000000000000000000000000000000000000..2369d03f336bb909b9c6d19d39b114737bdca59a GIT binary patch literal 858 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UOiAAEE)4(M`_JqL@;D1TB8!2v z2N=7Z%(epwmK8Xr18D^?ZvQoBE=ZfFi(`n#@v~RYuMQ0rVgGRc-tW6?pWJwT3{8~R za;!Dyc)F^Q!;w`m$mB|+;7t_^3-385oR-X@SLz=rempZV>Pxe@N3%dZYt!U{2{SG& zIJo!u8@A^$_h0U-o_{`Y-N~EjbNB9heY|{a>5u)YK0#u0i+`#x9Q6=qm2?a{tD+@fdexKd_#F@XvD469Yw_e3fzi^jQOUVTp zul63(y=eCRYltrQ$phN!ejS}B8l*A%dG);VGqtwNTXk0Re!25y>)m@PK~f(BS@txu z@@P&~&KKQxFj{Tf-4z|CX1iaXe|KESC@=Z-6Q#1q6-)l_DgT+NG?VSZwFlF-nwd0; zdEXU`et$iTL1UJ~`Nzs&?1B00++uhCwQeH3U;e(C^LLTWtVy1| zB3HltI9U3A_uaDkkk_-fpR=2;T50KWI>&L^ox;QFcBZfOnKy6yeaUlkletcXh6&$q zvE#}wcrMQgE<4GzDdApW`k9?8i!O>k?(FF=4&sd4e%*W1YrS8x(lzPb3niD=-n%O? zS==kET+GYqZFn)86ZgfN{Bz&MZCT+zO?9RG@4%dur{lH;PYWrFcpaVS#BzCw>d!6b zc~qTk<1MvTp4u2TFYVrz%Zce{C02d7WhAxy^rC++o;8)0&G^{w{4XQyoEC$Xz{Se* zKW-mPvo^iEp-alfONHaDNsFqKd~~zht+NwUJ#*?z!%iQHu$;~?U+Aa!l^6RqaP4BB z2uyaWC9V-ADTyViR>?)FK#IZ0z|c_Fz);u7BE-nZ%Ea8t)L7TR!pgv4iC@u46b-rg zDVb@NxHViAK2-|TAPKS|I6tkVJh3R1!7(L2DOJHUH!(dmC^a#qvhZZ84Nwt-r>mdK II;Vst0AcfT3IG5A literal 0 HcmV?d00001 diff --git a/mobile/android/themes/core/images/textfield.png b/mobile/android/themes/core/images/textfield.png new file mode 100644 index 0000000000000000000000000000000000000000..436853fa1ea73eb25a3b42f2bd1744fe7f523a17 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^%s|Y-!3HF~bz9j%oMI=>5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt;-)E{-7_ zGks5N&{{ literal 0 HcmV?d00001 diff --git a/mobile/android/themes/core/jar.mn b/mobile/android/themes/core/jar.mn index 08d13f7c259..b92d9cc4817 100644 --- a/mobile/android/themes/core/jar.mn +++ b/mobile/android/themes/core/jar.mn @@ -31,12 +31,17 @@ chrome.jar: % override chrome://global/skin/media/videocontrols.css chrome://browser/skin/touchcontrols.css % override chrome://global/skin/netError.css chrome://browser/skin/netError.css + skin/images/search.png (images/search.png) + skin/images/lock.png (images/lock.png) + skin/images/textfield.png (images/textfield.png) + skin/images/5stars.png (images/5stars.png) skin/images/addons-32.png (images/addons-32.png) skin/images/amo-logo.png (images/amo-logo.png) skin/images/arrowleft-16.png (images/arrowleft-16.png) skin/images/arrowright-16.png (images/arrowright-16.png) skin/images/arrowdown-16.png (images/arrowdown-16.png) + skin/images/arrowup-16.png (images/arrowup-16.png) skin/images/blocked-warning.png (images/blocked-warning.png) skin/images/checkbox_checked.png (images/checkbox_checked.png) skin/images/checkbox_checked_disabled.png (images/checkbox_checked_disabled.png) From 637fba4ee3efac3d8c53381a5f6f28a03a683779 Mon Sep 17 00:00:00 2001 From: Phil Ringnalda Date: Tue, 5 Nov 2013 22:19:28 -0800 Subject: [PATCH 48/53] Back out 5b70e599577c (bug 930141) for test_loader_paths.html bustage --- .../test/browser_dbg_pretty-print-08.js | 3 +- .../test/browser_dbg_pretty-print-09.js | 3 +- browser/devtools/scratchpad/scratchpad.js | 68 +- browser/devtools/scratchpad/test/browser.ini | 5 +- .../test/browser_scratchpad_pprint-02.js | 22 +- .../test/browser_scratchpad_pprint.js | 11 +- toolkit/devtools/Loader.jsm | 13 +- toolkit/devtools/acorn/moz.build | 2 +- .../acorn/tests/unit/test_import_acorn.js | 4 +- .../acorn/tests/unit/test_lenient_parser.js | 2 +- .../acorn/tests/unit/test_same_ast.js | 2 +- toolkit/devtools/escodegen/LICENSE.BSD | 19 + toolkit/devtools/escodegen/UPGRADING.md | 54 + toolkit/devtools/escodegen/escodegen.js | 2065 ++++++ .../devtools/escodegen/escodegen.worker.js | 5539 +++++++++++++++++ toolkit/devtools/escodegen/estraverse.js | 678 ++ .../{pretty-fast => escodegen}/moz.build | 7 +- toolkit/devtools/escodegen/package.json.js | 57 + .../tests/unit/head_escodegen.js} | 7 +- .../tests/unit/test_generate_source_maps.js | 71 + .../tests/unit/test_import_escodegen.js | 11 + .../escodegen/tests/unit/test_same_ast.js | 76 + .../escodegen/tests/unit/xpcshell.ini | 7 + toolkit/devtools/moz.build | 4 +- toolkit/devtools/pretty-fast/UPGRADING.md | 7 - toolkit/devtools/pretty-fast/pretty-fast.js | 781 --- .../devtools/pretty-fast/tests/unit/test.js | 470 -- .../pretty-fast/tests/unit/xpcshell.ini | 5 - .../server/actors/pretty-print-worker.js | 27 +- toolkit/devtools/server/actors/script.js | 16 +- toolkit/devtools/server/main.js | 1 + toolkit/devtools/sourcemap/Makefile.in | 1 - toolkit/devtools/sourcemap/source-map.js | 1929 ------ 33 files changed, 8656 insertions(+), 3311 deletions(-) create mode 100644 toolkit/devtools/escodegen/LICENSE.BSD create mode 100644 toolkit/devtools/escodegen/UPGRADING.md create mode 100644 toolkit/devtools/escodegen/escodegen.js create mode 100644 toolkit/devtools/escodegen/escodegen.worker.js create mode 100644 toolkit/devtools/escodegen/estraverse.js rename toolkit/devtools/{pretty-fast => escodegen}/moz.build (73%) create mode 100644 toolkit/devtools/escodegen/package.json.js rename toolkit/devtools/{pretty-fast/tests/unit/head_pretty-fast.js => escodegen/tests/unit/head_escodegen.js} (82%) create mode 100644 toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js create mode 100644 toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js create mode 100644 toolkit/devtools/escodegen/tests/unit/test_same_ast.js create mode 100644 toolkit/devtools/escodegen/tests/unit/xpcshell.ini delete mode 100644 toolkit/devtools/pretty-fast/UPGRADING.md delete mode 100644 toolkit/devtools/pretty-fast/pretty-fast.js delete mode 100644 toolkit/devtools/pretty-fast/tests/unit/test.js delete mode 100644 toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini delete mode 100644 toolkit/devtools/sourcemap/source-map.js diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js index 8466ddf6f79..6985c72615a 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js @@ -80,9 +80,10 @@ function testStepping() { function testHitBreakpoint() { gClient.addOneTimeListener("paused", (event, { why, frame }) => { is(why.type, "breakpoint"); - const { url, line } = frame.where; + const { url, line, column } = frame.where; is(url, CODE_URL); is(line, BP_LOCATION.line); + is(column, BP_LOCATION.column); resumeDebuggerThenCloseAndFinish(gPanel); }); diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js index 952f8a92f05..07bdeb2fa81 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js @@ -55,9 +55,10 @@ function runCode({ error }) { function testDbgStatement(event, { frame, why }) { is(why.type, "debuggerStatement"); - const { url, line } = frame.where; + const { url, line, column } = frame.where; is(url, B_URL); is(line, 2); + is(column, 2); disablePrettyPrint(); } diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index c139c362007..48780058ece 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -34,6 +34,7 @@ const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesV const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const promise = require("sdk/core/promise"); const Telemetry = require("devtools/shared/telemetry"); +const escodegen = require("escodegen/escodegen"); const Editor = require("devtools/sourceeditor/editor"); const TargetFactory = require("devtools/framework/target").TargetFactory; @@ -515,61 +516,25 @@ var Scratchpad = { return deferred.promise; }, - _prettyPrintWorker: null, - - /** - * Get or create the worker that handles pretty printing. - */ - get prettyPrintWorker() { - if (!this._prettyPrintWorker) { - this._prettyPrintWorker = new ChromeWorker( - "resource://gre/modules/devtools/server/actors/pretty-print-worker.js"); - - this._prettyPrintWorker.addEventListener("error", ({ message, filename, lineno }) => { - DevToolsUtils.reportException(message + " @ " + filename + ":" + lineno); - }, false); - } - return this._prettyPrintWorker; - }, - /** * Pretty print the source text inside the scratchpad. - * - * @return Promise - * A promise resolved with the pretty printed code, or rejected with - * an error. */ prettyPrint: function SP_prettyPrint() { const uglyText = this.getText(); const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); - const id = Math.random(); - const deferred = promise.defer(); - - const onReply = ({ data }) => { - if (data.id !== id) { - return; - } - this.prettyPrintWorker.removeEventListener("message", onReply, false); - - if (data.error) { - let errorString = DevToolsUtils.safeErrorString(data.error); - this.writeAsErrorComment(errorString); - deferred.reject(errorString); - } else { - this.editor.setText(data.code); - deferred.resolve(data.code); - } - }; - - this.prettyPrintWorker.addEventListener("message", onReply, false); - this.prettyPrintWorker.postMessage({ - id: id, - url: "(scratchpad)", - indent: tabsize, - source: uglyText - }); - - return deferred.promise; + try { + const ast = Reflect.parse(uglyText); + const prettyText = escodegen.generate(ast, { + format: { + indent: { + style: " ".repeat(tabsize) + } + } + }); + this.editor.setText(prettyText); + } catch (e) { + this.writeAsErrorComment(DevToolsUtils.safeErrorString(e)); + } }, /** @@ -1410,11 +1375,6 @@ var Scratchpad = { this._sidebar = null; } - if (this._prettyPrintWorker) { - this._prettyPrintWorker.terminate(); - this._prettyPrintWorker = null; - } - scratchpadTargets = null; this.webConsoleClient = null; this.debuggerClient = null; diff --git a/browser/devtools/scratchpad/test/browser.ini b/browser/devtools/scratchpad/test/browser.ini index 57e39157a35..f1b27427250 100644 --- a/browser/devtools/scratchpad/test/browser.ini +++ b/browser/devtools/scratchpad/test/browser.ini @@ -28,9 +28,10 @@ support-files = head.js [browser_scratchpad_long_string.js] [browser_scratchpad_open.js] [browser_scratchpad_open_error_console.js] +# Disabled, as escodegen is being replaced - bug 930141 +# [browser_scratchpad_pprint-02.js] +# [browser_scratchpad_pprint.js] [browser_scratchpad_throw_output.js] -[browser_scratchpad_pprint-02.js] -[browser_scratchpad_pprint.js] [browser_scratchpad_restore.js] [browser_scratchpad_tab_switch.js] [browser_scratchpad_ui.js] diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js b/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js index 13a6e91c1cc..8deffdda943 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js @@ -15,26 +15,18 @@ function test() content.location = "data:text/html;charset=utf8,test Scratchpad pretty print."; } -let gTabsize; - function runTests(sw) { - gTabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); + const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); Services.prefs.setIntPref("devtools.editor.tabsize", 6); const space = " ".repeat(6); const sp = sw.Scratchpad; sp.setText("function main() { console.log(5); }"); - sp.prettyPrint().then(() => { - const prettyText = sp.getText(); - ok(prettyText.contains(space)); - finish(); - }).then(null, error => { - ok(false, error); - }); -} + sp.prettyPrint(); + const prettyText = sp.getText(); + ok(prettyText.contains(space)); -registerCleanupFunction(function () { - Services.prefs.setIntPref("devtools.editor.tabsize", gTabsize); - gTabsize = null; -}); + Services.prefs.setIntPref("devtools.editor.tabsize", tabsize); + finish(); +} diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js b/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js index d8ff7039d41..9b5a6b3d243 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js @@ -19,11 +19,8 @@ function runTests(sw) { const sp = sw.Scratchpad; sp.setText("function main() { console.log(5); }"); - sp.prettyPrint().then(() => { - const prettyText = sp.getText(); - ok(prettyText.contains("\n")); - finish(); - }).then(null, error => { - ok(false, error); - }); + sp.prettyPrint(); + const prettyText = sp.getText(); + ok(prettyText.contains("\n")); + finish(); } diff --git a/toolkit/devtools/Loader.jsm b/toolkit/devtools/Loader.jsm index a8fbef92a96..6b68aeae508 100644 --- a/toolkit/devtools/Loader.jsm +++ b/toolkit/devtools/Loader.jsm @@ -64,10 +64,10 @@ var BuiltinProvider = { "devtools/output-parser": "resource://gre/modules/devtools/output-parser", "devtools/touch-events": "resource://gre/modules/devtools/touch-events", "devtools/client": "resource://gre/modules/devtools/client", - "devtools/pretty-fast": "resource://gre/modules/devtools/pretty-fast.js", - "acorn": "resource://gre/modules/devtools/acorn.js", - "acorn_loose": "resource://gre/modules/devtools/acorn_loose.js", + "acorn": "resource://gre/modules/devtools/acorn", + "escodegen": "resource://gre/modules/devtools/escodegen", + "estraverse": "resource://gre/modules/devtools/escodegen/estraverse", // Allow access to xpcshell test items from the loader. "xpcshell-test": "resource://test" @@ -109,8 +109,9 @@ var SrcdirProvider = { let outputParserURI = this.fileURI(OS.Path.join(toolkitDir, "output-parser")); let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events")); let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client")); - let prettyFastURI = this.fileURI(OS.Path.join(toolkitDir), "pretty-fast.js"); let acornURI = this.fileURI(OS.Path.join(toolkitDir, "acorn")); + let escodegenURI = this.fileURI(OS.Path.join(toolkitDir, "escodegen")); + let estraverseURI = this.fileURI(OS.Path.join(toolkitDir, "escodegen", "estraverse")); this.loader = new loader.Loader({ modules: { "toolkit/loader": loader, @@ -128,9 +129,9 @@ var SrcdirProvider = { "devtools/output-parser": outputParserURI, "devtools/touch-events": touchEventsURI, "devtools/client": clientURI, - "devtools/pretty-fast": prettyFastURI, - "acorn": acornURI, + "escodegen": escodegenURI, + "estraverse": estraverseURI }, globals: loaderGlobals }); diff --git a/toolkit/devtools/acorn/moz.build b/toolkit/devtools/acorn/moz.build index 8f3524f7d23..1eafb9bc925 100644 --- a/toolkit/devtools/acorn/moz.build +++ b/toolkit/devtools/acorn/moz.build @@ -6,7 +6,7 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] -JS_MODULES_PATH = 'modules/devtools' +JS_MODULES_PATH = 'modules/devtools/acorn' EXTRA_JS_MODULES += [ 'acorn.js', diff --git a/toolkit/devtools/acorn/tests/unit/test_import_acorn.js b/toolkit/devtools/acorn/tests/unit/test_import_acorn.js index 969893f36c2..d9d72ef2684 100644 --- a/toolkit/devtools/acorn/tests/unit/test_import_acorn.js +++ b/toolkit/devtools/acorn/tests/unit/test_import_acorn.js @@ -6,8 +6,8 @@ */ function run_test() { - const acorn = require("acorn"); - const acorn_loose = require("acorn_loose"); + const acorn = require("acorn/acorn"); + const acorn_loose = require("acorn/acorn_loose"); do_check_true(isObject(acorn)); do_check_true(isObject(acorn_loose)); do_check_eq(typeof acorn.parse, "function"); diff --git a/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js b/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js index e72aac0f5c3..794918b6357 100644 --- a/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js +++ b/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js @@ -5,7 +5,7 @@ * Test that acorn's lenient parser gives something usable. */ -const acorn_loose = require("acorn_loose"); +const acorn_loose = require("acorn/acorn_loose"); function run_test() { let actualAST = acorn_loose.parse_dammit("let x = 10"); diff --git a/toolkit/devtools/acorn/tests/unit/test_same_ast.js b/toolkit/devtools/acorn/tests/unit/test_same_ast.js index d01916d7abb..ce2de6076d7 100644 --- a/toolkit/devtools/acorn/tests/unit/test_same_ast.js +++ b/toolkit/devtools/acorn/tests/unit/test_same_ast.js @@ -5,7 +5,7 @@ * Test that Reflect and acorn create the same AST for ES5. */ -const acorn = require("acorn"); +const acorn = require("acorn/acorn"); Cu.import("resource://gre/modules/reflect.jsm"); const testCode = "" + function main () { diff --git a/toolkit/devtools/escodegen/LICENSE.BSD b/toolkit/devtools/escodegen/LICENSE.BSD new file mode 100644 index 00000000000..3e580c355a9 --- /dev/null +++ b/toolkit/devtools/escodegen/LICENSE.BSD @@ -0,0 +1,19 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/toolkit/devtools/escodegen/UPGRADING.md b/toolkit/devtools/escodegen/UPGRADING.md new file mode 100644 index 00000000000..bf8d2882d67 --- /dev/null +++ b/toolkit/devtools/escodegen/UPGRADING.md @@ -0,0 +1,54 @@ +Assuming that escodegen's dependencies have not changed, to upgrade our tree's +escodegen to a new version: + +1. Clone the escodegen repository, and check out the version you want to upgrade +to: + + $ git clone https://github.com/Constellation/escodegen.git + $ cd escodegen + $ git checkout + +2. Make sure that all tests pass: + + $ npm install . + $ npm test + + If there are any test failures, do not upgrade to that version of escodegen! + +3. Copy escodegen.js to our tree: + + $ cp escodegen.js /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.js + +4. Copy the package.json to our tree, and append ".js" to make it work with our +loader: + + $ cp package.json /path/to/mozilla-central/toolkit/devtools/escodegen/package.json.js + +5. Prepend `module.exports = ` to the package.json file contents, so that the +JSON data is exported, and we can load package.json as a module. + + Bug 933482: Note, this is a workaround for Bug 910594, which will allow the SDK loader to require JSON files. To remove ambiguity, comment out the `require('./package.json').version` line in `escodegen.js` so that when Bug 910594 is uplifted into central, it does not attempt to look for `package.json`, rather than `package.json.js`. This is a temporary workaround, and once Bug 933500 is solved, either `package.json` or `package.json.js` will work. + +6. Copy the estraverse.js that escodegen depends on into our tree: + + $ cp node_modules/estraverse/estraverse.js /path/to/mozilla-central/devtools/escodegen/estraverse.js + +7. Build the version of the escodegen that we can use in workers: + + First we need to alias `self` as `window`: + + $ echo 'let window = self;' >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js + + Then we need to add the browser build of the source map library: + + $ git clone https://github.com/mozilla/source-map + $ cd source-map + $ git co + $ npm run-script build + $ cat dist/source-map.js >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js + + Then we need to build the browser version of escodegen: + + $ cd /path/to/escodegen + $ npm run-script build + $ cat escodegen.browser.js >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js diff --git a/toolkit/devtools/escodegen/escodegen.js b/toolkit/devtools/escodegen/escodegen.js new file mode 100644 index 00000000000..41b32286431 --- /dev/null +++ b/toolkit/devtools/escodegen/escodegen.js @@ -0,0 +1,2065 @@ +/* + Copyright (C) 2012-2013 Yusuke Suzuki + Copyright (C) 2012-2013 Michael Ficarra + Copyright (C) 2012-2013 Mathias Bynens + Copyright (C) 2013 Irakli Gozalishvili + Copyright (C) 2012 Robert Gust-Bardon + Copyright (C) 2012 John Freeman + Copyright (C) 2011-2012 Ariya Hidayat + Copyright (C) 2012 Joost-Wim Boekesteijn + Copyright (C) 2012 Kris Kowal + Copyright (C) 2012 Arpad Borsos + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*jslint bitwise:true */ +/*global exports:true, generateStatement:true, generateExpression:true, require:true, global:true*/ +(function () { + 'use strict'; + + var Syntax, + Precedence, + BinaryPrecedence, + Regex, + SourceNode, + estraverse, + isArray, + base, + indent, + json, + renumber, + hexadecimal, + quotes, + escapeless, + newline, + space, + parentheses, + semicolons, + safeConcatenation, + directive, + extra, + parse, + sourceMap, + FORMAT_MINIFY, + FORMAT_DEFAULTS; + + estraverse = require('estraverse'); + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ComprehensionBlock: 'ComprehensionBlock', + ComprehensionExpression: 'ComprehensionExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + + }; + + Precedence = { + Sequence: 0, + Assignment: 1, + Conditional: 2, + LogicalOR: 3, + LogicalAND: 4, + BitwiseOR: 5, + BitwiseXOR: 6, + BitwiseAND: 7, + Equality: 8, + Relational: 9, + BitwiseSHIFT: 10, + Additive: 11, + Multiplicative: 12, + Unary: 13, + Postfix: 14, + Call: 15, + New: 16, + Member: 17, + Primary: 18 + }; + + BinaryPrecedence = { + '||': Precedence.LogicalOR, + '&&': Precedence.LogicalAND, + '|': Precedence.BitwiseOR, + '^': Precedence.BitwiseXOR, + '&': Precedence.BitwiseAND, + '==': Precedence.Equality, + '!=': Precedence.Equality, + '===': Precedence.Equality, + '!==': Precedence.Equality, + 'is': Precedence.Equality, + 'isnt': Precedence.Equality, + '<': Precedence.Relational, + '>': Precedence.Relational, + '<=': Precedence.Relational, + '>=': Precedence.Relational, + 'in': Precedence.Relational, + 'instanceof': Precedence.Relational, + '<<': Precedence.BitwiseSHIFT, + '>>': Precedence.BitwiseSHIFT, + '>>>': Precedence.BitwiseSHIFT, + '+': Precedence.Additive, + '-': Precedence.Additive, + '*': Precedence.Multiplicative, + '%': Precedence.Multiplicative, + '/': Precedence.Multiplicative + }; + + Regex = { + 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]') + }; + + function getDefaultOptions() { + // default options + return { + indent: null, + base: null, + parse: null, + comment: false, + format: { + indent: { + style: ' ', + base: 0, + adjustMultilineComment: false + }, + json: false, + renumber: false, + hexadecimal: false, + quotes: 'single', + escapeless: false, + compact: false, + parentheses: true, + semicolons: true, + safeConcatenation: false + }, + moz: { + starlessGenerator: false, + parenthesizedComprehensionBlock: false + }, + sourceMap: null, + sourceMapRoot: null, + sourceMapWithCode: false, + directive: false, + verbatim: null + }; + } + + function stringToArray(str) { + var length = str.length, + result = [], + i; + for (i = 0; i < length; i += 1) { + result[i] = str.charAt(i); + } + return result; + } + + function stringRepeat(str, num) { + var result = ''; + + for (num |= 0; num > 0; num >>>= 1, str += str) { + if (num & 1) { + result += str; + } + } + + return result; + } + + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + + // Fallback for the non SourceMap environment + function SourceNodeMock(line, column, filename, chunk) { + var result = []; + + function flatten(input) { + var i, iz; + if (isArray(input)) { + for (i = 0, iz = input.length; i < iz; ++i) { + flatten(input[i]); + } + } else if (input instanceof SourceNodeMock) { + result.push(input); + } else if (typeof input === 'string' && input) { + result.push(input); + } + } + + flatten(chunk); + this.children = result; + } + + SourceNodeMock.prototype.toString = function toString() { + var res = '', i, iz, node; + for (i = 0, iz = this.children.length; i < iz; ++i) { + node = this.children[i]; + if (node instanceof SourceNodeMock) { + res += node.toString(); + } else { + res += node; + } + } + return res; + }; + + SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) { + var last = this.children[this.children.length - 1]; + if (last instanceof SourceNodeMock) { + last.replaceRight(pattern, replacement); + } else if (typeof last === 'string') { + this.children[this.children.length - 1] = last.replace(pattern, replacement); + } else { + this.children.push(''.replace(pattern, replacement)); + } + return this; + }; + + SourceNodeMock.prototype.join = function join(sep) { + var i, iz, result; + result = []; + iz = this.children.length; + if (iz > 0) { + for (i = 0, iz -= 1; i < iz; ++i) { + result.push(this.children[i], sep); + } + result.push(this.children[iz]); + this.children = result; + } + return this; + }; + + function hasLineTerminator(str) { + return (/[\r\n]/g).test(str); + } + + function endsWithLineTerminator(str) { + var ch = str.charAt(str.length - 1); + return ch === '\r' || ch === '\n'; + } + + function updateDeeply(target, override) { + var key, val; + + function isHashObject(target) { + return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); + } + + for (key in override) { + if (override.hasOwnProperty(key)) { + val = override[key]; + if (isHashObject(val)) { + if (isHashObject(target[key])) { + updateDeeply(target[key], val); + } else { + target[key] = updateDeeply({}, val); + } + } else { + target[key] = val; + } + } + } + return target; + } + + function generateNumber(value) { + var result, point, temp, exponent, pos; + + if (value !== value) { + throw new Error('Numeric literal whose value is NaN'); + } + if (value < 0 || (value === 0 && 1 / value < 0)) { + throw new Error('Numeric literal whose value is negative'); + } + + if (value === 1 / 0) { + return json ? 'null' : renumber ? '1e400' : '1e+400'; + } + + result = '' + value; + if (!renumber || result.length < 3) { + return result; + } + + point = result.indexOf('.'); + if (!json && result.charAt(0) === '0' && point === 1) { + point = 0; + result = result.slice(1); + } + temp = result; + result = result.replace('e+', 'e'); + exponent = 0; + if ((pos = temp.indexOf('e')) > 0) { + exponent = +temp.slice(pos + 1); + temp = temp.slice(0, pos); + } + if (point >= 0) { + exponent -= temp.length - point - 1; + temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; + } + pos = 0; + while (temp.charAt(temp.length + pos - 1) === '0') { + pos -= 1; + } + if (pos !== 0) { + exponent -= pos; + temp = temp.slice(0, pos); + } + if (exponent !== 0) { + temp += 'e' + exponent; + } + if ((temp.length < result.length || + (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) && + +temp === value) { + result = temp; + } + + return result; + } + + // Generate valid RegExp expression. + // This function is based on https://github.com/Constellation/iv Engine + + function escapeRegExpCharacter(ch, previousIsBackslash) { + // not handling '\' and handling \u2028 or \u2029 to unicode escape sequence + if ((ch & ~1) === 0x2028) { + return (previousIsBackslash ? 'u' : '\\u') + ((ch === 0x2028) ? '2028' : '2029'); + } else if (ch === 10 || ch === 13) { // \n, \r + return (previousIsBackslash ? '' : '\\') + ((ch === 10) ? 'n' : 'r'); + } + return String.fromCharCode(ch); + } + + function generateRegExp(reg) { + var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash; + + result = reg.toString(); + + if (reg.source) { + // extract flag from toString result + match = result.match(/\/([^/]*)$/); + if (!match) { + return result; + } + + flags = match[1]; + result = ''; + + characterInBrack = false; + previousIsBackslash = false; + for (i = 0, iz = reg.source.length; i < iz; ++i) { + ch = reg.source.charCodeAt(i); + + if (!previousIsBackslash) { + if (characterInBrack) { + if (ch === 93) { // ] + characterInBrack = false; + } + } else { + if (ch === 47) { // / + result += '\\'; + } else if (ch === 91) { // [ + characterInBrack = true; + } + } + result += escapeRegExpCharacter(ch, previousIsBackslash); + previousIsBackslash = ch === 92; // \ + } else { + // if new RegExp("\\\n') is provided, create /\n/ + result += escapeRegExpCharacter(ch, previousIsBackslash); + // prevent like /\\[/]/ + previousIsBackslash = false; + } + } + + return '/' + result + '/' + flags; + } + + return result; + } + + function escapeAllowedCharacter(ch, next) { + var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; + + switch (ch) { + case '\b': + result += 'b'; + break; + case '\f': + result += 'f'; + break; + case '\t': + result += 't'; + break; + default: + if (json || code > 0xff) { + result += 'u' + '0000'.slice(hex.length) + hex; + } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) { + result += '0'; + } else if (ch === '\x0B') { // '\v' + result += 'x0B'; + } else { + result += 'x' + '00'.slice(hex.length) + hex; + } + break; + } + + return result; + } + + function escapeDisallowedCharacter(ch) { + var result = '\\'; + switch (ch) { + case '\\': + result += '\\'; + break; + case '\n': + result += 'n'; + break; + case '\r': + result += 'r'; + break; + case '\u2028': + result += 'u2028'; + break; + case '\u2029': + result += 'u2029'; + break; + default: + throw new Error('Incorrectly classified character'); + } + + return result; + } + + function escapeDirective(str) { + var i, iz, ch, buf, quote; + + buf = str; + if (typeof buf[0] === 'undefined') { + buf = stringToArray(buf); + } + + quote = quotes === 'double' ? '"' : '\''; + for (i = 0, iz = buf.length; i < iz; i += 1) { + ch = buf[i]; + if (ch === '\'') { + quote = '"'; + break; + } else if (ch === '"') { + quote = '\''; + break; + } else if (ch === '\\') { + i += 1; + } + } + + return quote + str + quote; + } + + function escapeString(str) { + var result = '', i, len, ch, singleQuotes = 0, doubleQuotes = 0, single; + + if (typeof str[0] === 'undefined') { + str = stringToArray(str); + } + + for (i = 0, len = str.length; i < len; i += 1) { + ch = str[i]; + if (ch === '\'') { + singleQuotes += 1; + } else if (ch === '"') { + doubleQuotes += 1; + } else if (ch === '/' && json) { + result += '\\'; + } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { + result += escapeDisallowedCharacter(ch); + continue; + } else if ((json && ch < ' ') || !(json || escapeless || (ch >= ' ' && ch <= '~'))) { + result += escapeAllowedCharacter(ch, str[i + 1]); + continue; + } + result += ch; + } + + single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes)); + str = result; + result = single ? '\'' : '"'; + + if (typeof str[0] === 'undefined') { + str = stringToArray(str); + } + + for (i = 0, len = str.length; i < len; i += 1) { + ch = str[i]; + if ((ch === '\'' && single) || (ch === '"' && !single)) { + result += '\\'; + } + result += ch; + } + + return result + (single ? '\'' : '"'); + } + + function isWhiteSpace(ch) { + // Use `\x0B` instead of `\v` for IE < 9 compatibility + return '\t\x0B\f \xa0'.indexOf(ch) >= 0 || (ch.charCodeAt(0) >= 0x1680 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0); + } + + function isLineTerminator(ch) { + return '\n\r\u2028\u2029'.indexOf(ch) >= 0; + } + + 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)); + } + + function toSourceNode(generated, node) { + if (node == null) { + if (generated instanceof SourceNode) { + return generated; + } else { + node = {}; + } + } + if (node.loc == null) { + return new SourceNode(null, null, sourceMap, generated, node.name || null); + } + return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated, node.name || null); + } + + function join(left, right) { + var leftSource = toSourceNode(left).toString(), + rightSource = toSourceNode(right).toString(), + leftChar = leftSource.charAt(leftSource.length - 1), + rightChar = rightSource.charAt(0); + + if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) { + return [left, ' ', right]; + } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { + return [left, right]; + } + return [left, space, right]; + } + + function addIndent(stmt) { + return [base, stmt]; + } + + function withIndent(fn) { + var previousBase, result; + previousBase = base; + base += indent; + result = fn.call(this, base); + base = previousBase; + return result; + } + + function calculateSpaces(str) { + var i; + for (i = str.length - 1; i >= 0; i -= 1) { + if (isLineTerminator(str.charAt(i))) { + break; + } + } + return (str.length - 1) - i; + } + + function adjustMultilineComment(value, specialBase) { + var array, i, len, line, j, spaces, previousBase; + + array = value.split(/\r\n|[\r\n]/); + spaces = Number.MAX_VALUE; + + // first line doesn't have indentation + for (i = 1, len = array.length; i < len; i += 1) { + line = array[i]; + j = 0; + while (j < line.length && isWhiteSpace(line[j])) { + j += 1; + } + if (spaces > j) { + spaces = j; + } + } + + if (typeof specialBase !== 'undefined') { + // pattern like + // { + // var t = 20; /* + // * this is comment + // */ + // } + previousBase = base; + if (array[1][spaces] === '*') { + specialBase += ' '; + } + base = specialBase; + } else { + if (spaces & 1) { + // /* + // * + // */ + // If spaces are odd number, above pattern is considered. + // We waste 1 space. + spaces -= 1; + } + previousBase = base; + } + + for (i = 1, len = array.length; i < len; i += 1) { + array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join(''); + } + + base = previousBase; + + return array.join('\n'); + } + + function generateComment(comment, specialBase) { + if (comment.type === 'Line') { + if (endsWithLineTerminator(comment.value)) { + return '//' + comment.value; + } else { + // Always use LineTerminator + return '//' + comment.value + '\n'; + } + } + if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { + return adjustMultilineComment('/*' + comment.value + '*/', specialBase); + } + return '/*' + comment.value + '*/'; + } + + function addCommentsToStatement(stmt, result) { + var i, len, comment, save, tailingToStatement, specialBase, fragment; + + if (stmt.leadingComments && stmt.leadingComments.length > 0) { + save = result; + + comment = stmt.leadingComments[0]; + result = []; + if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { + result.push('\n'); + } + result.push(generateComment(comment)); + if (!endsWithLineTerminator(toSourceNode(result).toString())) { + result.push('\n'); + } + + for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { + comment = stmt.leadingComments[i]; + fragment = [generateComment(comment)]; + if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { + fragment.push('\n'); + } + result.push(addIndent(fragment)); + } + + result.push(addIndent(save)); + } + + if (stmt.trailingComments) { + tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString()); + specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([base, result, indent]).toString())); + for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { + comment = stmt.trailingComments[i]; + if (tailingToStatement) { + // We assume target like following script + // + // var t = 20; /** + // * This is comment of t + // */ + if (i === 0) { + // first case + result = [result, indent]; + } else { + result = [result, specialBase]; + } + result.push(generateComment(comment, specialBase)); + } else { + result = [result, addIndent(generateComment(comment))]; + } + if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) { + result = [result, '\n']; + } + } + } + + return result; + } + + function parenthesize(text, current, should) { + if (current < should) { + return ['(', text, ')']; + } + return text; + } + + function maybeBlock(stmt, semicolonOptional, functionBody) { + var result, noLeadingComment; + + noLeadingComment = !extra.comment || !stmt.leadingComments; + + if (stmt.type === Syntax.BlockStatement && noLeadingComment) { + return [space, generateStatement(stmt, { functionBody: functionBody })]; + } + + if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { + return ';'; + } + + withIndent(function () { + result = [newline, addIndent(generateStatement(stmt, { semicolonOptional: semicolonOptional, functionBody: functionBody }))]; + }); + + return result; + } + + function maybeBlockSuffix(stmt, result) { + var ends = endsWithLineTerminator(toSourceNode(result).toString()); + if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) { + return [result, space]; + } + if (ends) { + return [result, base]; + } + return [result, newline, base]; + } + + function generateVerbatim(expr, option) { + var i, result; + result = expr[extra.verbatim].split(/\r\n|\n/); + for (i = 1; i < result.length; i++) { + result[i] = newline + base + result[i]; + } + + result = parenthesize(result, Precedence.Sequence, option.precedence); + return toSourceNode(result, expr); + } + + function generateIdentifier(node) { + return toSourceNode(node.name, node); + } + + function generateFunctionBody(node) { + var result, i, len, expr; + result = ['(']; + for (i = 0, len = node.params.length; i < len; i += 1) { + result.push(generateIdentifier(node.params[i])); + if (i + 1 < len) { + result.push(',' + space); + } + } + result.push(')'); + + if (node.expression) { + result.push(space); + expr = generateExpression(node.body, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }); + if (expr.toString().charAt(0) === '{') { + expr = ['(', expr, ')']; + } + result.push(expr); + } else { + result.push(maybeBlock(node.body, false, true)); + } + return result; + } + + function generateExpression(expr, option) { + var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, allowIn, allowCall, allowUnparenthesizedNew, property; + + precedence = option.precedence; + allowIn = option.allowIn; + allowCall = option.allowCall; + type = expr.type || option.type; + + if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { + return generateVerbatim(expr, option); + } + + switch (type) { + case Syntax.SequenceExpression: + result = []; + allowIn |= (Precedence.Sequence < precedence); + for (i = 0, len = expr.expressions.length; i < len; i += 1) { + result.push(generateExpression(expr.expressions[i], { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + space); + } + } + result = parenthesize(result, Precedence.Sequence, precedence); + break; + + case Syntax.AssignmentExpression: + allowIn |= (Precedence.Assignment < precedence); + result = parenthesize( + [ + generateExpression(expr.left, { + precedence: Precedence.Call, + allowIn: allowIn, + allowCall: true + }), + space + expr.operator + space, + generateExpression(expr.right, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }) + ], + Precedence.Assignment, + precedence + ); + break; + + case Syntax.ConditionalExpression: + allowIn |= (Precedence.Conditional < precedence); + result = parenthesize( + [ + generateExpression(expr.test, { + precedence: Precedence.LogicalOR, + allowIn: allowIn, + allowCall: true + }), + space + '?' + space, + generateExpression(expr.consequent, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }), + space + ':' + space, + generateExpression(expr.alternate, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }) + ], + Precedence.Conditional, + precedence + ); + break; + + case Syntax.LogicalExpression: + case Syntax.BinaryExpression: + currentPrecedence = BinaryPrecedence[expr.operator]; + + allowIn |= (currentPrecedence < precedence); + + fragment = generateExpression(expr.left, { + precedence: currentPrecedence, + allowIn: allowIn, + allowCall: true + }); + + leftSource = fragment.toString(); + + if (leftSource.charAt(leftSource.length - 1) === '/' && isIdentifierPart(expr.operator.charAt(0))) { + result = [fragment, ' ', expr.operator]; + } else { + result = join(fragment, expr.operator); + } + + fragment = generateExpression(expr.right, { + precedence: currentPrecedence + 1, + allowIn: allowIn, + allowCall: true + }); + + if (expr.operator === '/' && fragment.toString().charAt(0) === '/') { + // If '/' concats with '/', it is interpreted as comment start + result.push(' ', fragment); + } else { + result = join(result, fragment); + } + + if (expr.operator === 'in' && !allowIn) { + result = ['(', result, ')']; + } else { + result = parenthesize(result, currentPrecedence, precedence); + } + + break; + + case Syntax.CallExpression: + result = [generateExpression(expr.callee, { + precedence: Precedence.Call, + allowIn: true, + allowCall: true, + allowUnparenthesizedNew: false + })]; + + result.push('('); + for (i = 0, len = expr['arguments'].length; i < len; i += 1) { + result.push(generateExpression(expr['arguments'][i], { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + space); + } + } + result.push(')'); + + if (!allowCall) { + result = ['(', result, ')']; + } else { + result = parenthesize(result, Precedence.Call, precedence); + } + break; + + case Syntax.NewExpression: + len = expr['arguments'].length; + allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; + + result = join( + 'new', + generateExpression(expr.callee, { + precedence: Precedence.New, + allowIn: true, + allowCall: false, + allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 + }) + ); + + if (!allowUnparenthesizedNew || parentheses || len > 0) { + result.push('('); + for (i = 0; i < len; i += 1) { + result.push(generateExpression(expr['arguments'][i], { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + space); + } + } + result.push(')'); + } + + result = parenthesize(result, Precedence.New, precedence); + break; + + case Syntax.MemberExpression: + result = [generateExpression(expr.object, { + precedence: Precedence.Call, + allowIn: true, + allowCall: allowCall, + allowUnparenthesizedNew: false + })]; + + if (expr.computed) { + result.push('[', generateExpression(expr.property, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: allowCall + }), ']'); + } else { + if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { + fragment = toSourceNode(result).toString(); + if (fragment.indexOf('.') < 0) { + if (!/[eExX]/.test(fragment) && + !(fragment.length >= 2 && fragment.charCodeAt(0) === 48)) { // '0' + result.push('.'); + } + } + } + result.push('.', generateIdentifier(expr.property)); + } + + result = parenthesize(result, Precedence.Member, precedence); + break; + + case Syntax.UnaryExpression: + fragment = generateExpression(expr.argument, { + precedence: Precedence.Unary, + allowIn: true, + allowCall: true + }); + + if (space === '') { + result = join(expr.operator, fragment); + } else { + result = [expr.operator]; + if (expr.operator.length > 2) { + // delete, void, typeof + // get `typeof []`, not `typeof[]` + result = join(result, fragment); + } else { + // Prevent inserting spaces between operator and argument if it is unnecessary + // like, `!cond` + leftSource = toSourceNode(result).toString(); + leftChar = leftSource.charAt(leftSource.length - 1); + rightChar = fragment.toString().charAt(0); + + if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) { + result.push(' ', fragment); + } else { + result.push(fragment); + } + } + } + result = parenthesize(result, Precedence.Unary, precedence); + break; + + case Syntax.YieldExpression: + if (expr.delegate) { + result = 'yield*'; + } else { + result = 'yield'; + } + if (expr.argument) { + result = join( + result, + generateExpression(expr.argument, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }) + ); + } + break; + + case Syntax.UpdateExpression: + if (expr.prefix) { + result = parenthesize( + [ + expr.operator, + generateExpression(expr.argument, { + precedence: Precedence.Unary, + allowIn: true, + allowCall: true + }) + ], + Precedence.Unary, + precedence + ); + } else { + result = parenthesize( + [ + generateExpression(expr.argument, { + precedence: Precedence.Postfix, + allowIn: true, + allowCall: true + }), + expr.operator + ], + Precedence.Postfix, + precedence + ); + } + break; + + case Syntax.FunctionExpression: + result = 'function'; + + if (expr.id) { + result = [result + ' ', + generateIdentifier(expr.id), + generateFunctionBody(expr)]; + } else { + result = [result + space, generateFunctionBody(expr)]; + } + + break; + + case Syntax.ArrayPattern: + case Syntax.ArrayExpression: + if (!expr.elements.length) { + result = '[]'; + break; + } + multiline = expr.elements.length > 1; + result = ['[', multiline ? newline : '']; + withIndent(function (indent) { + for (i = 0, len = expr.elements.length; i < len; i += 1) { + if (!expr.elements[i]) { + if (multiline) { + result.push(indent); + } + if (i + 1 === len) { + result.push(','); + } + } else { + result.push(multiline ? indent : '', generateExpression(expr.elements[i], { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + } + if (i + 1 < len) { + result.push(',' + (multiline ? newline : space)); + } + } + }); + if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + result.push(multiline ? base : '', ']'); + break; + + case Syntax.Property: + if (expr.kind === 'get' || expr.kind === 'set') { + result = [ + expr.kind + ' ', + generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + generateFunctionBody(expr.value) + ]; + } else { + if (expr.shorthand) { + result = generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + } else if (expr.method) { + result = []; + if (expr.value.generator) { + result.push('*'); + } + result.push(generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), generateFunctionBody(expr.value)); + } else { + result = [ + generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ':' + space, + generateExpression(expr.value, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }) + ]; + } + } + break; + + case Syntax.ObjectExpression: + if (!expr.properties.length) { + result = '{}'; + break; + } + multiline = expr.properties.length > 1; + + withIndent(function () { + fragment = generateExpression(expr.properties[0], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true, + type: Syntax.Property + }); + }); + + if (!multiline) { + // issues 4 + // Do not transform from + // dejavu.Class.declare({ + // method2: function () {} + // }); + // to + // dejavu.Class.declare({method2: function () { + // }}); + if (!hasLineTerminator(toSourceNode(fragment).toString())) { + result = [ '{', space, fragment, space, '}' ]; + break; + } + } + + withIndent(function (indent) { + result = [ '{', newline, indent, fragment ]; + + if (multiline) { + result.push(',' + newline); + for (i = 1, len = expr.properties.length; i < len; i += 1) { + result.push(indent, generateExpression(expr.properties[i], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true, + type: Syntax.Property + })); + if (i + 1 < len) { + result.push(',' + newline); + } + } + } + }); + + if (!endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + result.push(base, '}'); + break; + + case Syntax.ObjectPattern: + if (!expr.properties.length) { + result = '{}'; + break; + } + + multiline = false; + if (expr.properties.length === 1) { + property = expr.properties[0]; + if (property.value.type !== Syntax.Identifier) { + multiline = true; + } + } else { + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (!property.shorthand) { + multiline = true; + break; + } + } + } + result = ['{', multiline ? newline : '' ]; + + withIndent(function (indent) { + for (i = 0, len = expr.properties.length; i < len; i += 1) { + result.push(multiline ? indent : '', generateExpression(expr.properties[i], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + (multiline ? newline : space)); + } + } + }); + + if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + result.push(multiline ? base : '', '}'); + break; + + case Syntax.ThisExpression: + result = 'this'; + break; + + case Syntax.Identifier: + result = generateIdentifier(expr); + break; + + case Syntax.Literal: + if (expr.hasOwnProperty('raw') && parse) { + try { + raw = parse(expr.raw).body[0].expression; + if (raw.type === Syntax.Literal) { + if (raw.value === expr.value) { + result = expr.raw; + break; + } + } + } catch (e) { + // not use raw property + } + } + + if (expr.value === null) { + result = 'null'; + break; + } + + if (typeof expr.value === 'string') { + result = escapeString(expr.value); + break; + } + + if (typeof expr.value === 'number') { + result = generateNumber(expr.value); + break; + } + + if (typeof expr.value === 'boolean') { + result = expr.value ? 'true' : 'false'; + break; + } + + result = generateRegExp(expr.value); + break; + + case Syntax.ComprehensionExpression: + result = [ + '[', + generateExpression(expr.body, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }) + ]; + + if (expr.blocks) { + for (i = 0, len = expr.blocks.length; i < len; i += 1) { + fragment = generateExpression(expr.blocks[i], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + result = join(result, fragment); + } + } + + if (expr.filter) { + result = join(result, 'if' + space); + fragment = generateExpression(expr.filter, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + if (extra.moz.parenthesizedComprehensionBlock) { + result = join(result, [ '(', fragment, ')' ]); + } else { + result = join(result, fragment); + } + } + result.push(']'); + break; + + case Syntax.ComprehensionBlock: + if (expr.left.type === Syntax.VariableDeclaration) { + fragment = [ + expr.left.kind + ' ', + generateStatement(expr.left.declarations[0], { + allowIn: false + }) + ]; + } else { + fragment = generateExpression(expr.left, { + precedence: Precedence.Call, + allowIn: true, + allowCall: true + }); + } + + fragment = join(fragment, expr.of ? 'of' : 'in'); + fragment = join(fragment, generateExpression(expr.right, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })); + + if (extra.moz.parenthesizedComprehensionBlock) { + result = [ 'for' + space + '(', fragment, ')' ]; + } else { + result = join('for' + space, fragment); + } + break; + + default: + throw new Error('Unknown expression type: ' + expr.type); + } + + return toSourceNode(result, expr); + } + + function generateStatement(stmt, option) { + var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon; + + allowIn = true; + semicolon = ';'; + functionBody = false; + directiveContext = false; + if (option) { + allowIn = option.allowIn === undefined || option.allowIn; + if (!semicolons && option.semicolonOptional === true) { + semicolon = ''; + } + functionBody = option.functionBody; + directiveContext = option.directiveContext; + } + + switch (stmt.type) { + case Syntax.BlockStatement: + result = ['{', newline]; + + withIndent(function () { + for (i = 0, len = stmt.body.length; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.body[i], { + semicolonOptional: i === len - 1, + directiveContext: functionBody + })); + result.push(fragment); + if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + }); + + result.push(addIndent('}')); + break; + + case Syntax.BreakStatement: + if (stmt.label) { + result = 'break ' + stmt.label.name + semicolon; + } else { + result = 'break' + semicolon; + } + break; + + case Syntax.ContinueStatement: + if (stmt.label) { + result = 'continue ' + stmt.label.name + semicolon; + } else { + result = 'continue' + semicolon; + } + break; + + case Syntax.DirectiveStatement: + if (stmt.raw) { + result = stmt.raw + semicolon; + } else { + result = escapeDirective(stmt.directive) + semicolon; + } + break; + + case Syntax.DoWhileStatement: + // Because `do 42 while (cond)` is Syntax Error. We need semicolon. + result = join('do', maybeBlock(stmt.body)); + result = maybeBlockSuffix(stmt.body, result); + result = join(result, [ + 'while' + space + '(', + generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + semicolon + ]); + break; + + case Syntax.CatchClause: + withIndent(function () { + result = [ + 'catch' + space + '(', + generateExpression(stmt.param, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + result.push(maybeBlock(stmt.body)); + break; + + case Syntax.DebuggerStatement: + result = 'debugger' + semicolon; + break; + + case Syntax.EmptyStatement: + result = ';'; + break; + + case Syntax.ExpressionStatement: + result = [generateExpression(stmt.expression, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })]; + // 12.4 '{', 'function' is not allowed in this position. + // wrap expression with parentheses + fragment = toSourceNode(result).toString(); + if (fragment.charAt(0) === '{' || (fragment.slice(0, 8) === 'function' && ' ('.indexOf(fragment.charAt(8)) >= 0) || (directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) { + result = ['(', result, ')' + semicolon]; + } else { + result.push(semicolon); + } + break; + + case Syntax.VariableDeclarator: + if (stmt.init) { + result = [ + generateExpression(stmt.id, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }), + space, + '=', + space, + generateExpression(stmt.init, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }) + ]; + } else { + result = generateIdentifier(stmt.id); + } + break; + + case Syntax.VariableDeclaration: + result = [stmt.kind]; + // special path for + // var x = function () { + // }; + if (stmt.declarations.length === 1 && stmt.declarations[0].init && + stmt.declarations[0].init.type === Syntax.FunctionExpression) { + result.push(' ', generateStatement(stmt.declarations[0], { + allowIn: allowIn + })); + } else { + // VariableDeclarator is typed as Statement, + // but joined with comma (not LineTerminator). + // So if comment is attached to target node, we should specialize. + withIndent(function () { + node = stmt.declarations[0]; + if (extra.comment && node.leadingComments) { + result.push('\n', addIndent(generateStatement(node, { + allowIn: allowIn + }))); + } else { + result.push(' ', generateStatement(node, { + allowIn: allowIn + })); + } + + for (i = 1, len = stmt.declarations.length; i < len; i += 1) { + node = stmt.declarations[i]; + if (extra.comment && node.leadingComments) { + result.push(',' + newline, addIndent(generateStatement(node, { + allowIn: allowIn + }))); + } else { + result.push(',' + space, generateStatement(node, { + allowIn: allowIn + })); + } + } + }); + } + result.push(semicolon); + break; + + case Syntax.ThrowStatement: + result = [join( + 'throw', + generateExpression(stmt.argument, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }) + ), semicolon]; + break; + + case Syntax.TryStatement: + result = ['try', maybeBlock(stmt.block)]; + result = maybeBlockSuffix(stmt.block, result); + if (stmt.handlers) { + // old interface + for (i = 0, len = stmt.handlers.length; i < len; i += 1) { + result = join(result, generateStatement(stmt.handlers[i])); + if (stmt.finalizer || i + 1 !== len) { + result = maybeBlockSuffix(stmt.handlers[i].body, result); + } + } + } else { + // new interface + if (stmt.handler) { + result = join(result, generateStatement(stmt.handler)); + if (stmt.finalizer || stmt.guardedHandlers.length > 0) { + result = maybeBlockSuffix(stmt.handler.body, result); + } + } + + for (i = 0, len = stmt.guardedHandlers.length; i < len; i += 1) { + result = join(result, generateStatement(stmt.guardedHandlers[i])); + if (stmt.finalizer || i + 1 !== len) { + result = maybeBlockSuffix(stmt.guardedHandlers[i].body, result); + } + } + } + if (stmt.finalizer) { + result = join(result, ['finally', maybeBlock(stmt.finalizer)]); + } + break; + + case Syntax.SwitchStatement: + withIndent(function () { + result = [ + 'switch' + space + '(', + generateExpression(stmt.discriminant, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + space + '{' + newline + ]; + }); + if (stmt.cases) { + for (i = 0, len = stmt.cases.length; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.cases[i], {semicolonOptional: i === len - 1})); + result.push(fragment); + if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + } + result.push(addIndent('}')); + break; + + case Syntax.SwitchCase: + withIndent(function () { + if (stmt.test) { + result = [ + join('case', generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })), + ':' + ]; + } else { + result = ['default:']; + } + + i = 0; + len = stmt.consequent.length; + if (len && stmt.consequent[0].type === Syntax.BlockStatement) { + fragment = maybeBlock(stmt.consequent[0]); + result.push(fragment); + i = 1; + } + + if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + + for (; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.consequent[i], {semicolonOptional: i === len - 1 && semicolon === ''})); + result.push(fragment); + if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + }); + break; + + case Syntax.IfStatement: + withIndent(function () { + result = [ + 'if' + space + '(', + generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + if (stmt.alternate) { + result.push(maybeBlock(stmt.consequent)); + result = maybeBlockSuffix(stmt.consequent, result); + if (stmt.alternate.type === Syntax.IfStatement) { + result = join(result, ['else ', generateStatement(stmt.alternate, {semicolonOptional: semicolon === ''})]); + } else { + result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === ''))); + } + } else { + result.push(maybeBlock(stmt.consequent, semicolon === '')); + } + break; + + case Syntax.ForStatement: + withIndent(function () { + result = ['for' + space + '(']; + if (stmt.init) { + if (stmt.init.type === Syntax.VariableDeclaration) { + result.push(generateStatement(stmt.init, {allowIn: false})); + } else { + result.push(generateExpression(stmt.init, { + precedence: Precedence.Sequence, + allowIn: false, + allowCall: true + }), ';'); + } + } else { + result.push(';'); + } + + if (stmt.test) { + result.push(space, generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), ';'); + } else { + result.push(';'); + } + + if (stmt.update) { + result.push(space, generateExpression(stmt.update, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), ')'); + } else { + result.push(')'); + } + }); + + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + + case Syntax.ForInStatement: + result = ['for' + space + '(']; + withIndent(function () { + if (stmt.left.type === Syntax.VariableDeclaration) { + withIndent(function () { + result.push(stmt.left.kind + ' ', generateStatement(stmt.left.declarations[0], { + allowIn: false + })); + }); + } else { + result.push(generateExpression(stmt.left, { + precedence: Precedence.Call, + allowIn: true, + allowCall: true + })); + } + + result = join(result, 'in'); + result = [join( + result, + generateExpression(stmt.right, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }) + ), ')']; + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + + case Syntax.LabeledStatement: + result = [stmt.label.name + ':', maybeBlock(stmt.body, semicolon === '')]; + break; + + case Syntax.Program: + len = stmt.body.length; + result = [safeConcatenation && len > 0 ? '\n' : '']; + for (i = 0; i < len; i += 1) { + fragment = addIndent( + generateStatement(stmt.body[i], { + semicolonOptional: !safeConcatenation && i === len - 1, + directiveContext: true + }) + ); + result.push(fragment); + if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + break; + + case Syntax.FunctionDeclaration: + result = [(stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function '), + generateIdentifier(stmt.id), + generateFunctionBody(stmt)]; + break; + + case Syntax.ReturnStatement: + if (stmt.argument) { + result = [join( + 'return', + generateExpression(stmt.argument, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }) + ), semicolon]; + } else { + result = ['return' + semicolon]; + } + break; + + case Syntax.WhileStatement: + withIndent(function () { + result = [ + 'while' + space + '(', + generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + + case Syntax.WithStatement: + withIndent(function () { + result = [ + 'with' + space + '(', + generateExpression(stmt.object, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + + default: + throw new Error('Unknown statement type: ' + stmt.type); + } + + // Attach comments + + if (extra.comment) { + result = addCommentsToStatement(stmt, result); + } + + fragment = toSourceNode(result).toString(); + if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') { + result = toSourceNode(result).replaceRight(/\s+$/, ''); + } + + return toSourceNode(result, stmt); + } + + function generate(node, options) { + var defaultOptions = getDefaultOptions(), result, pair; + + if (options != null) { + // Obsolete options + // + // `options.indent` + // `options.base` + // + // Instead of them, we can use `option.format.indent`. + if (typeof options.indent === 'string') { + defaultOptions.format.indent.style = options.indent; + } + if (typeof options.base === 'number') { + defaultOptions.format.indent.base = options.base; + } + options = updateDeeply(defaultOptions, options); + indent = options.format.indent.style; + if (typeof options.base === 'string') { + base = options.base; + } else { + base = stringRepeat(indent, options.format.indent.base); + } + } else { + options = defaultOptions; + indent = options.format.indent.style; + base = stringRepeat(indent, options.format.indent.base); + } + json = options.format.json; + renumber = options.format.renumber; + hexadecimal = json ? false : options.format.hexadecimal; + quotes = json ? 'double' : options.format.quotes; + escapeless = options.format.escapeless; + if (options.format.compact) { + newline = space = indent = base = ''; + } else { + newline = '\n'; + space = ' '; + } + parentheses = options.format.parentheses; + semicolons = options.format.semicolons; + safeConcatenation = options.format.safeConcatenation; + directive = options.directive; + parse = json ? null : options.parse; + sourceMap = options.sourceMap; + extra = options; + + if (sourceMap) { + if (!exports.browser) { + // We assume environment is node.js + // And prevent from including source-map by browserify + SourceNode = require('source-map').SourceNode; + } else { + SourceNode = global.sourceMap.SourceNode; + } + } else { + SourceNode = SourceNodeMock; + } + + switch (node.type) { + case Syntax.BlockStatement: + case Syntax.BreakStatement: + case Syntax.CatchClause: + case Syntax.ContinueStatement: + case Syntax.DirectiveStatement: + case Syntax.DoWhileStatement: + case Syntax.DebuggerStatement: + case Syntax.EmptyStatement: + case Syntax.ExpressionStatement: + case Syntax.ForStatement: + case Syntax.ForInStatement: + case Syntax.FunctionDeclaration: + case Syntax.IfStatement: + case Syntax.LabeledStatement: + case Syntax.Program: + case Syntax.ReturnStatement: + case Syntax.SwitchStatement: + case Syntax.SwitchCase: + case Syntax.ThrowStatement: + case Syntax.TryStatement: + case Syntax.VariableDeclaration: + case Syntax.VariableDeclarator: + case Syntax.WhileStatement: + case Syntax.WithStatement: + result = generateStatement(node); + break; + + case Syntax.AssignmentExpression: + case Syntax.ArrayExpression: + case Syntax.ArrayPattern: + case Syntax.BinaryExpression: + case Syntax.CallExpression: + case Syntax.ConditionalExpression: + case Syntax.FunctionExpression: + case Syntax.Identifier: + case Syntax.Literal: + case Syntax.LogicalExpression: + case Syntax.MemberExpression: + case Syntax.NewExpression: + case Syntax.ObjectExpression: + case Syntax.ObjectPattern: + case Syntax.Property: + case Syntax.SequenceExpression: + case Syntax.ThisExpression: + case Syntax.UnaryExpression: + case Syntax.UpdateExpression: + case Syntax.YieldExpression: + + result = generateExpression(node, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + break; + + default: + throw new Error('Unknown node type: ' + node.type); + } + + if (!sourceMap) { + return result.toString(); + } + + pair = result.toStringWithSourceMap({ + file: options.file, + sourceRoot: options.sourceMapRoot + }); + + if (options.sourceMapWithCode) { + return pair; + } + return pair.map.toString(); + } + + FORMAT_MINIFY = { + indent: { + style: '', + base: 0 + }, + renumber: true, + hexadecimal: true, + quotes: 'auto', + escapeless: true, + compact: true, + parentheses: false, + semicolons: false + }; + + FORMAT_DEFAULTS = getDefaultOptions().format; + + // exports.version = require('./package.json').version; + exports.generate = generate; + exports.attachComments = estraverse.attachComments; + exports.browser = false; + exports.FORMAT_MINIFY = FORMAT_MINIFY; + exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS; +}()); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/toolkit/devtools/escodegen/escodegen.worker.js b/toolkit/devtools/escodegen/escodegen.worker.js new file mode 100644 index 00000000000..16aaa2901d3 --- /dev/null +++ b/toolkit/devtools/escodegen/escodegen.worker.js @@ -0,0 +1,5539 @@ +let window = self; +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/** + * Define a module along with a payload. + * @param {string} moduleName Name for the payload + * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec + * @param {function} payload Function with (require, exports, module) params + */ +function define(moduleName, deps, payload) { + if (typeof moduleName != "string") { + throw new TypeError('Expected string, got: ' + moduleName); + } + + if (arguments.length == 2) { + payload = deps; + } + + if (moduleName in define.modules) { + throw new Error("Module already defined: " + moduleName); + } + define.modules[moduleName] = payload; +}; + +/** + * The global store of un-instantiated modules + */ +define.modules = {}; + + +/** + * We invoke require() in the context of a Domain so we can have multiple + * sets of modules running separate from each other. + * This contrasts with JSMs which are singletons, Domains allows us to + * optionally load a CommonJS module twice with separate data each time. + * Perhaps you want 2 command lines with a different set of commands in each, + * for example. + */ +function Domain() { + this.modules = {}; + this._currentModule = null; +} + +(function () { + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * There are 2 ways to call this, either with an array of dependencies and a + * callback to call when the dependencies are found (which can happen + * asynchronously in an in-page context) or with a single string an no callback + * where the dependency is resolved synchronously and returned. + * The API is designed to be compatible with the CommonJS AMD spec and + * RequireJS. + * @param {string[]|string} deps A name, or names for the payload + * @param {function|undefined} callback Function to call when the dependencies + * are resolved + * @return {undefined|object} The module required or undefined for + * array/callback method + */ + Domain.prototype.require = function(deps, callback) { + if (Array.isArray(deps)) { + var params = deps.map(function(dep) { + return this.lookup(dep); + }, this); + if (callback) { + callback.apply(null, params); + } + return undefined; + } + else { + return this.lookup(deps); + } + }; + + function normalize(path) { + var bits = path.split('/'); + var i = 1; + while (i < bits.length) { + if (bits[i] === '..') { + bits.splice(i-1, 1); + } else if (bits[i] === '.') { + bits.splice(i, 1); + } else { + i++; + } + } + return bits.join('/'); + } + + function join(a, b) { + a = a.trim(); + b = b.trim(); + if (/^\//.test(b)) { + return b; + } else { + return a.replace(/\/*$/, '/') + b; + } + } + + function dirname(path) { + var bits = path.split('/'); + bits.pop(); + return bits.join('/'); + } + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * @param {string} moduleName A name for the payload to lookup + * @return {object} The module specified by aModuleName or null if not found. + */ + Domain.prototype.lookup = function(moduleName) { + if (/^\./.test(moduleName)) { + moduleName = normalize(join(dirname(this._currentModule), moduleName)); + } + + if (moduleName in this.modules) { + var module = this.modules[moduleName]; + return module; + } + + if (!(moduleName in define.modules)) { + throw new Error("Module not defined: " + moduleName); + } + + var module = define.modules[moduleName]; + + if (typeof module == "function") { + var exports = {}; + var previousModule = this._currentModule; + this._currentModule = moduleName; + module(this.require.bind(this), exports, { id: moduleName, uri: "" }); + this._currentModule = previousModule; + module = exports; + } + + // cache the resulting module object for next time + this.modules[moduleName] = module; + + return module; + }; + +}()); + +define.Domain = Domain; +define.globalDomain = new Domain(); +var require = define.globalDomain.require.bind(define.globalDomain); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-map-generator', ['require', 'exports', 'module' , 'source-map/base64-vlq', 'source-map/util', 'source-map/array-set'], function(require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + 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 + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); + } + }; + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guaranteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(util.compareByGeneratedPositions); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; + + 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.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; + + result += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + 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. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/base64'], function(require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/base64', ['require', 'exports', 'module' , ], function(require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + + 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; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + 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; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'source-map/util', 'source-map/binary-search', 'source-map/array-set', 'source-map/base64-vlq'], function(require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + var names = util.getArg(sourceMap, 'names'); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } + + // 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; + + // `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); + } + + /** + * 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. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + /** + * Parse the mappings in a string in to a data structure which we can easily + * query (an ordered list in this._generatedMappings). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this._generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this._originalMappings.push(mapping); + } + } + } + + this._originalMappings.sort(util.compareByOriginalPositions); + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + 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.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/binary-search', ['require', 'exports', 'module' , ], function(require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + 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]]); + } + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + 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) { + 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({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +window.sourceMap = { + SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, + SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, + SourceNode: require('source-map/source-node').SourceNode +}; +// Generated by CommonJS Everywhere 0.8.1 +(function (global) { + function require(file, parentModule) { + if ({}.hasOwnProperty.call(require.cache, file)) + return require.cache[file]; + var resolved = require.resolve(file); + if (!resolved) + throw new Error('Failed to resolve module ' + file); + var module$ = { + id: file, + require: require, + filename: file, + exports: {}, + loaded: false, + parent: parentModule, + children: [] + }; + if (parentModule) + parentModule.children.push(module$); + var dirname = file.slice(0, file.lastIndexOf('/') + 1); + require.cache[file] = module$.exports; + resolved.call(module$.exports, module$, module$.exports, dirname, file); + module$.loaded = true; + return require.cache[file] = module$.exports; + } + require.modules = {}; + require.cache = {}; + require.resolve = function (file) { + return {}.hasOwnProperty.call(require.modules, file) ? require.modules[file] : void 0; + }; + require.define = function (file, fn) { + require.modules[file] = fn; + }; + var process = function () { + var cwd = '/'; + return { + title: 'browser', + version: 'v0.10.5', + browser: true, + env: {}, + argv: [], + nextTick: global.setImmediate || function (fn) { + setTimeout(fn, 0); + }, + cwd: function () { + return cwd; + }, + chdir: function (dir) { + cwd = dir; + } + }; + }(); + require.define('/tools/entry-point.js', function (module, exports, __dirname, __filename) { + (function () { + 'use strict'; + global.escodegen = require('/escodegen.js', module); + escodegen.browser = true; + }()); + }); + require.define('/escodegen.js', function (module, exports, __dirname, __filename) { + (function () { + 'use strict'; + var Syntax, Precedence, BinaryPrecedence, Regex, SourceNode, estraverse, isArray, base, indent, json, renumber, hexadecimal, quotes, escapeless, newline, space, parentheses, semicolons, safeConcatenation, directive, extra, parse, sourceMap, FORMAT_MINIFY, FORMAT_DEFAULTS; + estraverse = require('/node_modules/estraverse/estraverse.js', module); + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + ArrayPattern: 'ArrayPattern', + ArrowFunctionExpression: 'ArrowFunctionExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ComprehensionBlock: 'ComprehensionBlock', + ComprehensionExpression: 'ComprehensionExpression', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + DebuggerStatement: 'DebuggerStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + ObjectPattern: 'ObjectPattern', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + Precedence = { + Sequence: 0, + Assignment: 1, + Conditional: 2, + ArrowFunction: 2, + LogicalOR: 3, + LogicalAND: 4, + BitwiseOR: 5, + BitwiseXOR: 6, + BitwiseAND: 7, + Equality: 8, + Relational: 9, + BitwiseSHIFT: 10, + Additive: 11, + Multiplicative: 12, + Unary: 13, + Postfix: 14, + Call: 15, + New: 16, + Member: 17, + Primary: 18 + }; + BinaryPrecedence = { + '||': Precedence.LogicalOR, + '&&': Precedence.LogicalAND, + '|': Precedence.BitwiseOR, + '^': Precedence.BitwiseXOR, + '&': Precedence.BitwiseAND, + '==': Precedence.Equality, + '!=': Precedence.Equality, + '===': Precedence.Equality, + '!==': Precedence.Equality, + 'is': Precedence.Equality, + 'isnt': Precedence.Equality, + '<': Precedence.Relational, + '>': Precedence.Relational, + '<=': Precedence.Relational, + '>=': Precedence.Relational, + 'in': Precedence.Relational, + 'instanceof': Precedence.Relational, + '<<': Precedence.BitwiseSHIFT, + '>>': Precedence.BitwiseSHIFT, + '>>>': Precedence.BitwiseSHIFT, + '+': Precedence.Additive, + '-': Precedence.Additive, + '*': Precedence.Multiplicative, + '%': Precedence.Multiplicative, + '/': Precedence.Multiplicative + }; + Regex = { 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]') }; + function getDefaultOptions() { + return { + indent: null, + base: null, + parse: null, + comment: false, + format: { + indent: { + style: ' ', + base: 0, + adjustMultilineComment: false + }, + newline: '\n', + space: ' ', + json: false, + renumber: false, + hexadecimal: false, + quotes: 'single', + escapeless: false, + compact: false, + parentheses: true, + semicolons: true, + safeConcatenation: false + }, + moz: { + starlessGenerator: false, + parenthesizedComprehensionBlock: false + }, + sourceMap: null, + sourceMapRoot: null, + sourceMapWithCode: false, + directive: false, + verbatim: null + }; + } + function stringToArray(str) { + var length = str.length, result = [], i; + for (i = 0; i < length; i += 1) { + result[i] = str.charAt(i); + } + return result; + } + function stringRepeat(str, num) { + var result = ''; + for (num |= 0; num > 0; num >>>= 1, str += str) { + if (num & 1) { + result += str; + } + } + return result; + } + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + function SourceNodeMock(line, column, filename, chunk) { + var result = []; + function flatten(input) { + var i, iz; + if (isArray(input)) { + for (i = 0, iz = input.length; i < iz; ++i) { + flatten(input[i]); + } + } else if (input instanceof SourceNodeMock) { + result.push(input); + } else if (typeof input === 'string' && input) { + result.push(input); + } + } + flatten(chunk); + this.children = result; + } + SourceNodeMock.prototype.toString = function toString() { + var res = '', i, iz, node; + for (i = 0, iz = this.children.length; i < iz; ++i) { + node = this.children[i]; + if (node instanceof SourceNodeMock) { + res += node.toString(); + } else { + res += node; + } + } + return res; + }; + SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) { + var last = this.children[this.children.length - 1]; + if (last instanceof SourceNodeMock) { + last.replaceRight(pattern, replacement); + } else if (typeof last === 'string') { + this.children[this.children.length - 1] = last.replace(pattern, replacement); + } else { + this.children.push(''.replace(pattern, replacement)); + } + return this; + }; + SourceNodeMock.prototype.join = function join(sep) { + var i, iz, result; + result = []; + iz = this.children.length; + if (iz > 0) { + for (i = 0, iz -= 1; i < iz; ++i) { + result.push(this.children[i], sep); + } + result.push(this.children[iz]); + this.children = result; + } + return this; + }; + function hasLineTerminator(str) { + return /[\r\n]/g.test(str); + } + function endsWithLineTerminator(str) { + var ch = str.charAt(str.length - 1); + return ch === '\r' || ch === '\n'; + } + function updateDeeply(target, override) { + var key, val; + function isHashObject(target) { + return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); + } + for (key in override) { + if (override.hasOwnProperty(key)) { + val = override[key]; + if (isHashObject(val)) { + if (isHashObject(target[key])) { + updateDeeply(target[key], val); + } else { + target[key] = updateDeeply({}, val); + } + } else { + target[key] = val; + } + } + } + return target; + } + function generateNumber(value) { + var result, point, temp, exponent, pos; + if (value !== value) { + throw new Error('Numeric literal whose value is NaN'); + } + if (value < 0 || value === 0 && 1 / value < 0) { + throw new Error('Numeric literal whose value is negative'); + } + if (value === 1 / 0) { + return json ? 'null' : renumber ? '1e400' : '1e+400'; + } + result = '' + value; + if (!renumber || result.length < 3) { + return result; + } + point = result.indexOf('.'); + if (!json && result.charAt(0) === '0' && point === 1) { + point = 0; + result = result.slice(1); + } + temp = result; + result = result.replace('e+', 'e'); + exponent = 0; + if ((pos = temp.indexOf('e')) > 0) { + exponent = +temp.slice(pos + 1); + temp = temp.slice(0, pos); + } + if (point >= 0) { + exponent -= temp.length - point - 1; + temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; + } + pos = 0; + while (temp.charAt(temp.length + pos - 1) === '0') { + pos -= 1; + } + if (pos !== 0) { + exponent -= pos; + temp = temp.slice(0, pos); + } + if (exponent !== 0) { + temp += 'e' + exponent; + } + if ((temp.length < result.length || hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length) && +temp === value) { + result = temp; + } + return result; + } + function escapeRegExpCharacter(ch, previousIsBackslash) { + if ((ch & ~1) === 8232) { + return (previousIsBackslash ? 'u' : '\\u') + (ch === 8232 ? '2028' : '2029'); + } else if (ch === 10 || ch === 13) { + return (previousIsBackslash ? '' : '\\') + (ch === 10 ? 'n' : 'r'); + } + return String.fromCharCode(ch); + } + function generateRegExp(reg) { + var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash; + result = reg.toString(); + if (reg.source) { + match = result.match(/\/([^/]*)$/); + if (!match) { + return result; + } + flags = match[1]; + result = ''; + characterInBrack = false; + previousIsBackslash = false; + for (i = 0, iz = reg.source.length; i < iz; ++i) { + ch = reg.source.charCodeAt(i); + if (!previousIsBackslash) { + if (characterInBrack) { + if (ch === 93) { + characterInBrack = false; + } + } else { + if (ch === 47) { + result += '\\'; + } else if (ch === 91) { + characterInBrack = true; + } + } + result += escapeRegExpCharacter(ch, previousIsBackslash); + previousIsBackslash = ch === 92; + } else { + result += escapeRegExpCharacter(ch, previousIsBackslash); + previousIsBackslash = false; + } + } + return '/' + result + '/' + flags; + } + return result; + } + function escapeAllowedCharacter(ch, next) { + var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; + switch (ch) { + case '\b': + result += 'b'; + break; + case '\f': + result += 'f'; + break; + case '\t': + result += 't'; + break; + default: + if (json || code > 255) { + result += 'u' + '0000'.slice(hex.length) + hex; + } else if (ch === '\0' && '0123456789'.indexOf(next) < 0) { + result += '0'; + } else if (ch === '\x0B') { + result += 'x0B'; + } else { + result += 'x' + '00'.slice(hex.length) + hex; + } + break; + } + return result; + } + function escapeDisallowedCharacter(ch) { + var result = '\\'; + switch (ch) { + case '\\': + result += '\\'; + break; + case '\n': + result += 'n'; + break; + case '\r': + result += 'r'; + break; + case '\u2028': + result += 'u2028'; + break; + case '\u2029': + result += 'u2029'; + break; + default: + throw new Error('Incorrectly classified character'); + } + return result; + } + function escapeDirective(str) { + var i, iz, ch, buf, quote; + buf = str; + if (typeof buf[0] === 'undefined') { + buf = stringToArray(buf); + } + quote = quotes === 'double' ? '"' : "'"; + for (i = 0, iz = buf.length; i < iz; i += 1) { + ch = buf[i]; + if (ch === "'") { + quote = '"'; + break; + } else if (ch === '"') { + quote = "'"; + break; + } else if (ch === '\\') { + i += 1; + } + } + return quote + str + quote; + } + function escapeString(str) { + var result = '', i, len, ch, singleQuotes = 0, doubleQuotes = 0, single; + if (typeof str[0] === 'undefined') { + str = stringToArray(str); + } + for (i = 0, len = str.length; i < len; i += 1) { + ch = str[i]; + if (ch === "'") { + singleQuotes += 1; + } else if (ch === '"') { + doubleQuotes += 1; + } else if (ch === '/' && json) { + result += '\\'; + } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { + result += escapeDisallowedCharacter(ch); + continue; + } else if (json && ch < ' ' || !(json || escapeless || ch >= ' ' && ch <= '~')) { + result += escapeAllowedCharacter(ch, str[i + 1]); + continue; + } + result += ch; + } + single = !(quotes === 'double' || quotes === 'auto' && doubleQuotes < singleQuotes); + str = result; + result = single ? "'" : '"'; + if (typeof str[0] === 'undefined') { + str = stringToArray(str); + } + for (i = 0, len = str.length; i < len; i += 1) { + ch = str[i]; + if (ch === "'" && single || ch === '"' && !single) { + result += '\\'; + } + result += ch; + } + return result + (single ? "'" : '"'); + } + function isWhiteSpace(ch) { + return '\t\x0B\f \xa0'.indexOf(ch) >= 0 || ch.charCodeAt(0) >= 5760 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0; + } + function isLineTerminator(ch) { + return '\n\r\u2028\u2029'.indexOf(ch) >= 0; + } + function isIdentifierPart(ch) { + return ch === '$' || ch === '_' || ch === '\\' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch.charCodeAt(0) >= 128 && Regex.NonAsciiIdentifierPart.test(ch); + } + function isDecimalDigit(ch) { + return ch >= 48 && ch <= 57; + } + function toSourceNode(generated, node) { + if (node == null) { + if (generated instanceof SourceNode) { + return generated; + } else { + node = {}; + } + } + if (node.loc == null) { + return new SourceNode(null, null, sourceMap, generated, node.name || null); + } + return new SourceNode(node.loc.start.line, node.loc.start.column, sourceMap === true ? node.loc.source || null : sourceMap, generated, node.name || null); + } + function noEmptySpace() { + return space ? space : ' '; + } + function join(left, right) { + var leftSource = toSourceNode(left).toString(), rightSource = toSourceNode(right).toString(), leftChar = leftSource.charAt(leftSource.length - 1), rightChar = rightSource.charAt(0); + if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar) || leftChar === '/' && rightChar === 'i') { + return [ + left, + noEmptySpace(), + right + ]; + } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { + return [ + left, + right + ]; + } + return [ + left, + space, + right + ]; + } + function addIndent(stmt) { + return [ + base, + stmt + ]; + } + function withIndent(fn) { + var previousBase, result; + previousBase = base; + base += indent; + result = fn.call(this, base); + base = previousBase; + return result; + } + function calculateSpaces(str) { + var i; + for (i = str.length - 1; i >= 0; i -= 1) { + if (isLineTerminator(str.charAt(i))) { + break; + } + } + return str.length - 1 - i; + } + function adjustMultilineComment(value, specialBase) { + var array, i, len, line, j, spaces, previousBase; + array = value.split(/\r\n|[\r\n]/); + spaces = Number.MAX_VALUE; + for (i = 1, len = array.length; i < len; i += 1) { + line = array[i]; + j = 0; + while (j < line.length && isWhiteSpace(line[j])) { + j += 1; + } + if (spaces > j) { + spaces = j; + } + } + if (typeof specialBase !== 'undefined') { + previousBase = base; + if (array[1][spaces] === '*') { + specialBase += ' '; + } + base = specialBase; + } else { + if (spaces & 1) { + spaces -= 1; + } + previousBase = base; + } + for (i = 1, len = array.length; i < len; i += 1) { + array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join(''); + } + base = previousBase; + return array.join('\n'); + } + function generateComment(comment, specialBase) { + if (comment.type === 'Line') { + if (endsWithLineTerminator(comment.value)) { + return '//' + comment.value; + } else { + return '//' + comment.value + '\n'; + } + } + if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { + return adjustMultilineComment('/*' + comment.value + '*/', specialBase); + } + return '/*' + comment.value + '*/'; + } + function addCommentsToStatement(stmt, result) { + var i, len, comment, save, tailingToStatement, specialBase, fragment; + if (stmt.leadingComments && stmt.leadingComments.length > 0) { + save = result; + comment = stmt.leadingComments[0]; + result = []; + if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { + result.push('\n'); + } + result.push(generateComment(comment)); + if (!endsWithLineTerminator(toSourceNode(result).toString())) { + result.push('\n'); + } + for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { + comment = stmt.leadingComments[i]; + fragment = [generateComment(comment)]; + if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { + fragment.push('\n'); + } + result.push(addIndent(fragment)); + } + result.push(addIndent(save)); + } + if (stmt.trailingComments) { + tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString()); + specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([ + base, + result, + indent + ]).toString())); + for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { + comment = stmt.trailingComments[i]; + if (tailingToStatement) { + if (i === 0) { + result = [ + result, + indent + ]; + } else { + result = [ + result, + specialBase + ]; + } + result.push(generateComment(comment, specialBase)); + } else { + result = [ + result, + addIndent(generateComment(comment)) + ]; + } + if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) { + result = [ + result, + '\n' + ]; + } + } + } + return result; + } + function parenthesize(text, current, should) { + if (current < should) { + return [ + '(', + text, + ')' + ]; + } + return text; + } + function maybeBlock(stmt, semicolonOptional, functionBody) { + var result, noLeadingComment; + noLeadingComment = !extra.comment || !stmt.leadingComments; + if (stmt.type === Syntax.BlockStatement && noLeadingComment) { + return [ + space, + generateStatement(stmt, { functionBody: functionBody }) + ]; + } + if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { + return ';'; + } + withIndent(function () { + result = [ + newline, + addIndent(generateStatement(stmt, { + semicolonOptional: semicolonOptional, + functionBody: functionBody + })) + ]; + }); + return result; + } + function maybeBlockSuffix(stmt, result) { + var ends = endsWithLineTerminator(toSourceNode(result).toString()); + if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) { + return [ + result, + space + ]; + } + if (ends) { + return [ + result, + base + ]; + } + return [ + result, + newline, + base + ]; + } + function generateVerbatim(expr, option) { + var i, result; + result = expr[extra.verbatim].split(/\r\n|\n/); + for (i = 1; i < result.length; i++) { + result[i] = newline + base + result[i]; + } + result = parenthesize(result, Precedence.Sequence, option.precedence); + return toSourceNode(result, expr); + } + function generateIdentifier(node) { + return toSourceNode(node.name, node); + } + function generateFunctionBody(node) { + var result, i, len, expr, arrow; + arrow = node.type === Syntax.ArrowFunctionExpression; + if (arrow && node.params.length === 1 && node.params[0].type === Syntax.Identifier) { + result = [generateIdentifier(node.params[0])]; + } else { + result = ['(']; + for (i = 0, len = node.params.length; i < len; i += 1) { + result.push(generateIdentifier(node.params[i])); + if (i + 1 < len) { + result.push(',' + space); + } + } + result.push(')'); + } + if (arrow) { + result.push(space, '=>'); + } + if (node.expression) { + result.push(space); + expr = generateExpression(node.body, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }); + if (expr.toString().charAt(0) === '{') { + expr = [ + '(', + expr, + ')' + ]; + } + result.push(expr); + } else { + result.push(maybeBlock(node.body, false, true)); + } + return result; + } + function generateExpression(expr, option) { + var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, allowIn, allowCall, allowUnparenthesizedNew, property; + precedence = option.precedence; + allowIn = option.allowIn; + allowCall = option.allowCall; + type = expr.type || option.type; + if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { + return generateVerbatim(expr, option); + } + switch (type) { + case Syntax.SequenceExpression: + result = []; + allowIn |= Precedence.Sequence < precedence; + for (i = 0, len = expr.expressions.length; i < len; i += 1) { + result.push(generateExpression(expr.expressions[i], { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + space); + } + } + result = parenthesize(result, Precedence.Sequence, precedence); + break; + case Syntax.AssignmentExpression: + allowIn |= Precedence.Assignment < precedence; + result = parenthesize([ + generateExpression(expr.left, { + precedence: Precedence.Call, + allowIn: allowIn, + allowCall: true + }), + space + expr.operator + space, + generateExpression(expr.right, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }) + ], Precedence.Assignment, precedence); + break; + case Syntax.ArrowFunctionExpression: + allowIn |= Precedence.ArrowFunction < precedence; + result = parenthesize(generateFunctionBody(expr), Precedence.ArrowFunction, precedence); + break; + case Syntax.ConditionalExpression: + allowIn |= Precedence.Conditional < precedence; + result = parenthesize([ + generateExpression(expr.test, { + precedence: Precedence.LogicalOR, + allowIn: allowIn, + allowCall: true + }), + space + '?' + space, + generateExpression(expr.consequent, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }), + space + ':' + space, + generateExpression(expr.alternate, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }) + ], Precedence.Conditional, precedence); + break; + case Syntax.LogicalExpression: + case Syntax.BinaryExpression: + currentPrecedence = BinaryPrecedence[expr.operator]; + allowIn |= currentPrecedence < precedence; + fragment = generateExpression(expr.left, { + precedence: currentPrecedence, + allowIn: allowIn, + allowCall: true + }); + leftSource = fragment.toString(); + if (leftSource.charAt(leftSource.length - 1) === '/' && isIdentifierPart(expr.operator.charAt(0))) { + result = [ + fragment, + noEmptySpace(), + expr.operator + ]; + } else { + result = join(fragment, expr.operator); + } + fragment = generateExpression(expr.right, { + precedence: currentPrecedence + 1, + allowIn: allowIn, + allowCall: true + }); + if (expr.operator === '/' && fragment.toString().charAt(0) === '/' || expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') { + result.push(noEmptySpace(), fragment); + } else { + result = join(result, fragment); + } + if (expr.operator === 'in' && !allowIn) { + result = [ + '(', + result, + ')' + ]; + } else { + result = parenthesize(result, currentPrecedence, precedence); + } + break; + case Syntax.CallExpression: + result = [generateExpression(expr.callee, { + precedence: Precedence.Call, + allowIn: true, + allowCall: true, + allowUnparenthesizedNew: false + })]; + result.push('('); + for (i = 0, len = expr['arguments'].length; i < len; i += 1) { + result.push(generateExpression(expr['arguments'][i], { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + space); + } + } + result.push(')'); + if (!allowCall) { + result = [ + '(', + result, + ')' + ]; + } else { + result = parenthesize(result, Precedence.Call, precedence); + } + break; + case Syntax.NewExpression: + len = expr['arguments'].length; + allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; + result = join('new', generateExpression(expr.callee, { + precedence: Precedence.New, + allowIn: true, + allowCall: false, + allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 + })); + if (!allowUnparenthesizedNew || parentheses || len > 0) { + result.push('('); + for (i = 0; i < len; i += 1) { + result.push(generateExpression(expr['arguments'][i], { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + space); + } + } + result.push(')'); + } + result = parenthesize(result, Precedence.New, precedence); + break; + case Syntax.MemberExpression: + result = [generateExpression(expr.object, { + precedence: Precedence.Call, + allowIn: true, + allowCall: allowCall, + allowUnparenthesizedNew: false + })]; + if (expr.computed) { + result.push('[', generateExpression(expr.property, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: allowCall + }), ']'); + } else { + if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { + fragment = toSourceNode(result).toString(); + if (fragment.indexOf('.') < 0 && !/[eExX]/.test(fragment) && isDecimalDigit(fragment.charCodeAt(fragment.length - 1)) && !(fragment.length >= 2 && fragment.charCodeAt(0) === 48)) { + result.push('.'); + } + } + result.push('.', generateIdentifier(expr.property)); + } + result = parenthesize(result, Precedence.Member, precedence); + break; + case Syntax.UnaryExpression: + fragment = generateExpression(expr.argument, { + precedence: Precedence.Unary, + allowIn: true, + allowCall: true + }); + if (space === '') { + result = join(expr.operator, fragment); + } else { + result = [expr.operator]; + if (expr.operator.length > 2) { + result = join(result, fragment); + } else { + leftSource = toSourceNode(result).toString(); + leftChar = leftSource.charAt(leftSource.length - 1); + rightChar = fragment.toString().charAt(0); + if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar)) { + result.push(noEmptySpace(), fragment); + } else { + result.push(fragment); + } + } + } + result = parenthesize(result, Precedence.Unary, precedence); + break; + case Syntax.YieldExpression: + if (expr.delegate) { + result = 'yield*'; + } else { + result = 'yield'; + } + if (expr.argument) { + result = join(result, generateExpression(expr.argument, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + } + break; + case Syntax.UpdateExpression: + if (expr.prefix) { + result = parenthesize([ + expr.operator, + generateExpression(expr.argument, { + precedence: Precedence.Unary, + allowIn: true, + allowCall: true + }) + ], Precedence.Unary, precedence); + } else { + result = parenthesize([ + generateExpression(expr.argument, { + precedence: Precedence.Postfix, + allowIn: true, + allowCall: true + }), + expr.operator + ], Precedence.Postfix, precedence); + } + break; + case Syntax.FunctionExpression: + result = 'function'; + if (expr.id) { + result = [ + result, + noEmptySpace(), + generateIdentifier(expr.id), + generateFunctionBody(expr) + ]; + } else { + result = [ + result + space, + generateFunctionBody(expr) + ]; + } + break; + case Syntax.ArrayPattern: + case Syntax.ArrayExpression: + if (!expr.elements.length) { + result = '[]'; + break; + } + multiline = expr.elements.length > 1; + result = [ + '[', + multiline ? newline : '' + ]; + withIndent(function (indent) { + for (i = 0, len = expr.elements.length; i < len; i += 1) { + if (!expr.elements[i]) { + if (multiline) { + result.push(indent); + } + if (i + 1 === len) { + result.push(','); + } + } else { + result.push(multiline ? indent : '', generateExpression(expr.elements[i], { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + })); + } + if (i + 1 < len) { + result.push(',' + (multiline ? newline : space)); + } + } + }); + if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + result.push(multiline ? base : '', ']'); + break; + case Syntax.Property: + if (expr.kind === 'get' || expr.kind === 'set') { + result = [ + expr.kind, + noEmptySpace(), + generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + generateFunctionBody(expr.value) + ]; + } else { + if (expr.shorthand) { + result = generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + } else if (expr.method) { + result = []; + if (expr.value.generator) { + result.push('*'); + } + result.push(generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), generateFunctionBody(expr.value)); + } else { + result = [ + generateExpression(expr.key, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ':' + space, + generateExpression(expr.value, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }) + ]; + } + } + break; + case Syntax.ObjectExpression: + if (!expr.properties.length) { + result = '{}'; + break; + } + multiline = expr.properties.length > 1; + withIndent(function () { + fragment = generateExpression(expr.properties[0], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true, + type: Syntax.Property + }); + }); + if (!multiline) { + if (!hasLineTerminator(toSourceNode(fragment).toString())) { + result = [ + '{', + space, + fragment, + space, + '}' + ]; + break; + } + } + withIndent(function (indent) { + result = [ + '{', + newline, + indent, + fragment + ]; + if (multiline) { + result.push(',' + newline); + for (i = 1, len = expr.properties.length; i < len; i += 1) { + result.push(indent, generateExpression(expr.properties[i], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true, + type: Syntax.Property + })); + if (i + 1 < len) { + result.push(',' + newline); + } + } + } + }); + if (!endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + result.push(base, '}'); + break; + case Syntax.ObjectPattern: + if (!expr.properties.length) { + result = '{}'; + break; + } + multiline = false; + if (expr.properties.length === 1) { + property = expr.properties[0]; + if (property.value.type !== Syntax.Identifier) { + multiline = true; + } + } else { + for (i = 0, len = expr.properties.length; i < len; i += 1) { + property = expr.properties[i]; + if (!property.shorthand) { + multiline = true; + break; + } + } + } + result = [ + '{', + multiline ? newline : '' + ]; + withIndent(function (indent) { + for (i = 0, len = expr.properties.length; i < len; i += 1) { + result.push(multiline ? indent : '', generateExpression(expr.properties[i], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })); + if (i + 1 < len) { + result.push(',' + (multiline ? newline : space)); + } + } + }); + if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + result.push(multiline ? base : '', '}'); + break; + case Syntax.ThisExpression: + result = 'this'; + break; + case Syntax.Identifier: + result = generateIdentifier(expr); + break; + case Syntax.Literal: + if (expr.hasOwnProperty('raw') && parse) { + try { + raw = parse(expr.raw).body[0].expression; + if (raw.type === Syntax.Literal) { + if (raw.value === expr.value) { + result = expr.raw; + break; + } + } + } catch (e) { + } + } + if (expr.value === null) { + result = 'null'; + break; + } + if (typeof expr.value === 'string') { + result = escapeString(expr.value); + break; + } + if (typeof expr.value === 'number') { + result = generateNumber(expr.value); + break; + } + if (typeof expr.value === 'boolean') { + result = expr.value ? 'true' : 'false'; + break; + } + result = generateRegExp(expr.value); + break; + case Syntax.ComprehensionExpression: + result = [ + '[', + generateExpression(expr.body, { + precedence: Precedence.Assignment, + allowIn: true, + allowCall: true + }) + ]; + if (expr.blocks) { + for (i = 0, len = expr.blocks.length; i < len; i += 1) { + fragment = generateExpression(expr.blocks[i], { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + result = join(result, fragment); + } + } + if (expr.filter) { + result = join(result, 'if' + space); + fragment = generateExpression(expr.filter, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + if (extra.moz.parenthesizedComprehensionBlock) { + result = join(result, [ + '(', + fragment, + ')' + ]); + } else { + result = join(result, fragment); + } + } + result.push(']'); + break; + case Syntax.ComprehensionBlock: + if (expr.left.type === Syntax.VariableDeclaration) { + fragment = [ + expr.left.kind, + noEmptySpace(), + generateStatement(expr.left.declarations[0], { allowIn: false }) + ]; + } else { + fragment = generateExpression(expr.left, { + precedence: Precedence.Call, + allowIn: true, + allowCall: true + }); + } + fragment = join(fragment, expr.of ? 'of' : 'in'); + fragment = join(fragment, generateExpression(expr.right, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })); + if (extra.moz.parenthesizedComprehensionBlock) { + result = [ + 'for' + space + '(', + fragment, + ')' + ]; + } else { + result = join('for' + space, fragment); + } + break; + default: + throw new Error('Unknown expression type: ' + expr.type); + } + return toSourceNode(result, expr); + } + function generateStatement(stmt, option) { + var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon; + allowIn = true; + semicolon = ';'; + functionBody = false; + directiveContext = false; + if (option) { + allowIn = option.allowIn === undefined || option.allowIn; + if (!semicolons && option.semicolonOptional === true) { + semicolon = ''; + } + functionBody = option.functionBody; + directiveContext = option.directiveContext; + } + switch (stmt.type) { + case Syntax.BlockStatement: + result = [ + '{', + newline + ]; + withIndent(function () { + for (i = 0, len = stmt.body.length; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.body[i], { + semicolonOptional: i === len - 1, + directiveContext: functionBody + })); + result.push(fragment); + if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + }); + result.push(addIndent('}')); + break; + case Syntax.BreakStatement: + if (stmt.label) { + result = 'break ' + stmt.label.name + semicolon; + } else { + result = 'break' + semicolon; + } + break; + case Syntax.ContinueStatement: + if (stmt.label) { + result = 'continue ' + stmt.label.name + semicolon; + } else { + result = 'continue' + semicolon; + } + break; + case Syntax.DirectiveStatement: + if (stmt.raw) { + result = stmt.raw + semicolon; + } else { + result = escapeDirective(stmt.directive) + semicolon; + } + break; + case Syntax.DoWhileStatement: + result = join('do', maybeBlock(stmt.body)); + result = maybeBlockSuffix(stmt.body, result); + result = join(result, [ + 'while' + space + '(', + generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + semicolon + ]); + break; + case Syntax.CatchClause: + withIndent(function () { + result = [ + 'catch' + space + '(', + generateExpression(stmt.param, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + result.push(maybeBlock(stmt.body)); + break; + case Syntax.DebuggerStatement: + result = 'debugger' + semicolon; + break; + case Syntax.EmptyStatement: + result = ';'; + break; + case Syntax.ExpressionStatement: + result = [generateExpression(stmt.expression, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })]; + fragment = toSourceNode(result).toString(); + if (fragment.charAt(0) === '{' || fragment.slice(0, 8) === 'function' && ' ('.indexOf(fragment.charAt(8)) >= 0 || directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string') { + result = [ + '(', + result, + ')' + semicolon + ]; + } else { + result.push(semicolon); + } + break; + case Syntax.VariableDeclarator: + if (stmt.init) { + result = [ + generateExpression(stmt.id, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }), + space, + '=', + space, + generateExpression(stmt.init, { + precedence: Precedence.Assignment, + allowIn: allowIn, + allowCall: true + }) + ]; + } else { + result = generateIdentifier(stmt.id); + } + break; + case Syntax.VariableDeclaration: + result = [stmt.kind]; + if (stmt.declarations.length === 1 && stmt.declarations[0].init && stmt.declarations[0].init.type === Syntax.FunctionExpression) { + result.push(noEmptySpace(), generateStatement(stmt.declarations[0], { allowIn: allowIn })); + } else { + withIndent(function () { + node = stmt.declarations[0]; + if (extra.comment && node.leadingComments) { + result.push('\n', addIndent(generateStatement(node, { allowIn: allowIn }))); + } else { + result.push(noEmptySpace(), generateStatement(node, { allowIn: allowIn })); + } + for (i = 1, len = stmt.declarations.length; i < len; i += 1) { + node = stmt.declarations[i]; + if (extra.comment && node.leadingComments) { + result.push(',' + newline, addIndent(generateStatement(node, { allowIn: allowIn }))); + } else { + result.push(',' + space, generateStatement(node, { allowIn: allowIn })); + } + } + }); + } + result.push(semicolon); + break; + case Syntax.ThrowStatement: + result = [ + join('throw', generateExpression(stmt.argument, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })), + semicolon + ]; + break; + case Syntax.TryStatement: + result = [ + 'try', + maybeBlock(stmt.block) + ]; + result = maybeBlockSuffix(stmt.block, result); + if (stmt.handlers) { + for (i = 0, len = stmt.handlers.length; i < len; i += 1) { + result = join(result, generateStatement(stmt.handlers[i])); + if (stmt.finalizer || i + 1 !== len) { + result = maybeBlockSuffix(stmt.handlers[i].body, result); + } + } + } else { + if (stmt.handler) { + result = join(result, generateStatement(stmt.handler)); + if (stmt.finalizer || stmt.guardedHandlers.length > 0) { + result = maybeBlockSuffix(stmt.handler.body, result); + } + } + for (i = 0, len = stmt.guardedHandlers.length; i < len; i += 1) { + result = join(result, generateStatement(stmt.guardedHandlers[i])); + if (stmt.finalizer || i + 1 !== len) { + result = maybeBlockSuffix(stmt.guardedHandlers[i].body, result); + } + } + } + if (stmt.finalizer) { + result = join(result, [ + 'finally', + maybeBlock(stmt.finalizer) + ]); + } + break; + case Syntax.SwitchStatement: + withIndent(function () { + result = [ + 'switch' + space + '(', + generateExpression(stmt.discriminant, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + space + '{' + newline + ]; + }); + if (stmt.cases) { + for (i = 0, len = stmt.cases.length; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.cases[i], { semicolonOptional: i === len - 1 })); + result.push(fragment); + if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + } + result.push(addIndent('}')); + break; + case Syntax.SwitchCase: + withIndent(function () { + if (stmt.test) { + result = [ + join('case', generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })), + ':' + ]; + } else { + result = ['default:']; + } + i = 0; + len = stmt.consequent.length; + if (len && stmt.consequent[0].type === Syntax.BlockStatement) { + fragment = maybeBlock(stmt.consequent[0]); + result.push(fragment); + i = 1; + } + if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) { + result.push(newline); + } + for (; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.consequent[i], { semicolonOptional: i === len - 1 && semicolon === '' })); + result.push(fragment); + if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + }); + break; + case Syntax.IfStatement: + withIndent(function () { + result = [ + 'if' + space + '(', + generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + if (stmt.alternate) { + result.push(maybeBlock(stmt.consequent)); + result = maybeBlockSuffix(stmt.consequent, result); + if (stmt.alternate.type === Syntax.IfStatement) { + result = join(result, [ + 'else ', + generateStatement(stmt.alternate, { semicolonOptional: semicolon === '' }) + ]); + } else { + result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === ''))); + } + } else { + result.push(maybeBlock(stmt.consequent, semicolon === '')); + } + break; + case Syntax.ForStatement: + withIndent(function () { + result = ['for' + space + '(']; + if (stmt.init) { + if (stmt.init.type === Syntax.VariableDeclaration) { + result.push(generateStatement(stmt.init, { allowIn: false })); + } else { + result.push(generateExpression(stmt.init, { + precedence: Precedence.Sequence, + allowIn: false, + allowCall: true + }), ';'); + } + } else { + result.push(';'); + } + if (stmt.test) { + result.push(space, generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), ';'); + } else { + result.push(';'); + } + if (stmt.update) { + result.push(space, generateExpression(stmt.update, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), ')'); + } else { + result.push(')'); + } + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + case Syntax.ForInStatement: + result = ['for' + space + '(']; + withIndent(function () { + if (stmt.left.type === Syntax.VariableDeclaration) { + withIndent(function () { + result.push(stmt.left.kind + noEmptySpace(), generateStatement(stmt.left.declarations[0], { allowIn: false })); + }); + } else { + result.push(generateExpression(stmt.left, { + precedence: Precedence.Call, + allowIn: true, + allowCall: true + })); + } + result = join(result, 'in'); + result = [ + join(result, generateExpression(stmt.right, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })), + ')' + ]; + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + case Syntax.LabeledStatement: + result = [ + stmt.label.name + ':', + maybeBlock(stmt.body, semicolon === '') + ]; + break; + case Syntax.Program: + len = stmt.body.length; + result = [safeConcatenation && len > 0 ? '\n' : '']; + for (i = 0; i < len; i += 1) { + fragment = addIndent(generateStatement(stmt.body[i], { + semicolonOptional: !safeConcatenation && i === len - 1, + directiveContext: true + })); + result.push(fragment); + if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { + result.push(newline); + } + } + break; + case Syntax.FunctionDeclaration: + result = [ + stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function ', + generateIdentifier(stmt.id), + generateFunctionBody(stmt) + ]; + break; + case Syntax.ReturnStatement: + if (stmt.argument) { + result = [ + join('return', generateExpression(stmt.argument, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + })), + semicolon + ]; + } else { + result = ['return' + semicolon]; + } + break; + case Syntax.WhileStatement: + withIndent(function () { + result = [ + 'while' + space + '(', + generateExpression(stmt.test, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + case Syntax.WithStatement: + withIndent(function () { + result = [ + 'with' + space + '(', + generateExpression(stmt.object, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }), + ')' + ]; + }); + result.push(maybeBlock(stmt.body, semicolon === '')); + break; + default: + throw new Error('Unknown statement type: ' + stmt.type); + } + if (extra.comment) { + result = addCommentsToStatement(stmt, result); + } + fragment = toSourceNode(result).toString(); + if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') { + result = toSourceNode(result).replaceRight(/\s+$/, ''); + } + return toSourceNode(result, stmt); + } + function generate(node, options) { + var defaultOptions = getDefaultOptions(), result, pair; + if (options != null) { + if (typeof options.indent === 'string') { + defaultOptions.format.indent.style = options.indent; + } + if (typeof options.base === 'number') { + defaultOptions.format.indent.base = options.base; + } + options = updateDeeply(defaultOptions, options); + indent = options.format.indent.style; + if (typeof options.base === 'string') { + base = options.base; + } else { + base = stringRepeat(indent, options.format.indent.base); + } + } else { + options = defaultOptions; + indent = options.format.indent.style; + base = stringRepeat(indent, options.format.indent.base); + } + json = options.format.json; + renumber = options.format.renumber; + hexadecimal = json ? false : options.format.hexadecimal; + quotes = json ? 'double' : options.format.quotes; + escapeless = options.format.escapeless; + newline = options.format.newline; + space = options.format.space; + if (options.format.compact) { + newline = space = indent = base = ''; + } + parentheses = options.format.parentheses; + semicolons = options.format.semicolons; + safeConcatenation = options.format.safeConcatenation; + directive = options.directive; + parse = json ? null : options.parse; + sourceMap = options.sourceMap; + extra = options; + if (sourceMap) { + if (!exports.browser) { + SourceNode = require('/node_modules/source-map/lib/source-map.js', module).SourceNode; + } else { + SourceNode = global.sourceMap.SourceNode; + } + } else { + SourceNode = SourceNodeMock; + } + switch (node.type) { + case Syntax.BlockStatement: + case Syntax.BreakStatement: + case Syntax.CatchClause: + case Syntax.ContinueStatement: + case Syntax.DirectiveStatement: + case Syntax.DoWhileStatement: + case Syntax.DebuggerStatement: + case Syntax.EmptyStatement: + case Syntax.ExpressionStatement: + case Syntax.ForStatement: + case Syntax.ForInStatement: + case Syntax.FunctionDeclaration: + case Syntax.IfStatement: + case Syntax.LabeledStatement: + case Syntax.Program: + case Syntax.ReturnStatement: + case Syntax.SwitchStatement: + case Syntax.SwitchCase: + case Syntax.ThrowStatement: + case Syntax.TryStatement: + case Syntax.VariableDeclaration: + case Syntax.VariableDeclarator: + case Syntax.WhileStatement: + case Syntax.WithStatement: + result = generateStatement(node); + break; + case Syntax.AssignmentExpression: + case Syntax.ArrayExpression: + case Syntax.ArrayPattern: + case Syntax.BinaryExpression: + case Syntax.CallExpression: + case Syntax.ConditionalExpression: + case Syntax.FunctionExpression: + case Syntax.Identifier: + case Syntax.Literal: + case Syntax.LogicalExpression: + case Syntax.MemberExpression: + case Syntax.NewExpression: + case Syntax.ObjectExpression: + case Syntax.ObjectPattern: + case Syntax.Property: + case Syntax.SequenceExpression: + case Syntax.ThisExpression: + case Syntax.UnaryExpression: + case Syntax.UpdateExpression: + case Syntax.YieldExpression: + result = generateExpression(node, { + precedence: Precedence.Sequence, + allowIn: true, + allowCall: true + }); + break; + default: + throw new Error('Unknown node type: ' + node.type); + } + if (!sourceMap) { + return result.toString(); + } + pair = result.toStringWithSourceMap({ + file: options.file, + sourceRoot: options.sourceMapRoot + }); + if (options.sourceMapWithCode) { + return pair; + } + return pair.map.toString(); + } + FORMAT_MINIFY = { + indent: { + style: '', + base: 0 + }, + renumber: true, + hexadecimal: true, + quotes: 'auto', + escapeless: true, + compact: true, + parentheses: false, + semicolons: false + }; + FORMAT_DEFAULTS = getDefaultOptions().format; + exports.version = require('/package.json', module).version; + exports.generate = generate; + exports.attachComments = estraverse.attachComments; + exports.browser = false; + exports.FORMAT_MINIFY = FORMAT_MINIFY; + exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS; + }()); + }); + require.define('/package.json', function (module, exports, __dirname, __filename) { + module.exports = { + 'name': 'escodegen', + 'description': 'ECMAScript code generator', + 'homepage': 'http://github.com/Constellation/escodegen.html', + 'main': 'escodegen.js', + 'bin': { + 'esgenerate': './bin/esgenerate.js', + 'escodegen': './bin/escodegen.js' + }, + 'version': '0.0.28-dev', + 'engines': { 'node': '>=0.4.0' }, + 'maintainers': [{ + 'name': 'Yusuke Suzuki', + 'email': 'utatane.tea@gmail.com', + 'web': 'http://github.com/Constellation' + }], + 'repository': { + 'type': 'git', + 'url': 'http://github.com/Constellation/escodegen.git' + }, + 'dependencies': { + 'esprima': '~1.0.2', + 'estraverse': '~1.3.0' + }, + 'optionalDependencies': { 'source-map': '>= 0.1.2' }, + 'devDependencies': { + 'esprima-moz': '*', + 'commonjs-everywhere': '~0.8.0', + 'q': '*', + 'bower': '*', + 'semver': '*', + 'chai': '~1.7.2', + 'grunt-contrib-jshint': '~0.5.0', + 'grunt-cli': '~0.1.9', + 'grunt': '~0.4.1', + 'grunt-mocha-test': '~0.6.2' + }, + 'licenses': [{ + 'type': 'BSD', + 'url': 'http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD' + }], + 'scripts': { + 'test': 'grunt travis', + 'unit-test': 'grunt test', + 'lint': 'grunt lint', + 'release': 'node tools/release.js', + 'build-min': './node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js', + 'build': './node_modules/.bin/cjsify -a path: tools/entry-point.js > escodegen.browser.js' + } + }; + }); + require.define('/node_modules/source-map/lib/source-map.js', function (module, exports, __dirname, __filename) { + exports.SourceMapGenerator = require('/node_modules/source-map/lib/source-map/source-map-generator.js', module).SourceMapGenerator; + exports.SourceMapConsumer = require('/node_modules/source-map/lib/source-map/source-map-consumer.js', module).SourceMapConsumer; + exports.SourceNode = require('/node_modules/source-map/lib/source-map/source-node.js', module).SourceNode; + }); + require.define('/node_modules/source-map/lib/source-map/source-node.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + var SourceMapGenerator = require('/node_modules/source-map/lib/source-map/source-map-generator.js', module).SourceMapGenerator; + var util = require('/node_modules/source-map/lib/source-map/util.js', module); + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) + this.add(aChunks); + } + SourceNode.fromStringWithSourceMap = function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + var node = new SourceNode; + var remainingLines = aGeneratedCode.split('\n'); + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + var lastMapping = null; + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + 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 (lastGeneratedLine < mapping.generatedLine) { + var code = ''; + do { + code += remainingLines.shift() + '\n'; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + addMappingWithCode(lastMapping, code); + } else { + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + addMappingWithCode(lastMapping, remainingLines.join('\n')); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + return node; + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, mapping.originalColumn, mapping.source, code, mapping.name)); + } + } + }; + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } else if (aChunk instanceof SourceNode || typeof aChunk === 'string') { + if (aChunk) { + this.children.push(aChunk); + } + } else { + throw new TypeError('Expected a SourceNode, string, or an array of SourceNodes and strings. Got ' + aChunk); + } + return this; + }; + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length - 1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } else if (aChunk instanceof SourceNode || typeof aChunk === 'string') { + this.children.unshift(aChunk); + } else { + throw new TypeError('Expected a SourceNode, string, or an array of SourceNodes and strings. Got ' + aChunk); + } + return this; + }; + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + this.children.forEach(function (chunk) { + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } else { + if (chunk !== '') { + aFn(chunk, { + source: this.source, + line: this.line, + column: this.column, + name: this.name + }); + } + } + }, this); + }; + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len - 1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + SourceNode.prototype.setSourceContent = function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + SourceNode.prototype.walkSourceContents = function SourceNode_walkSourceContents(aFn) { + this.children.forEach(function (chunk) { + if (chunk instanceof SourceNode) { + chunk.walkSourceContents(aFn); + } + }, this); + Object.keys(this.sourceContents).forEach(function (sourceFileKey) { + aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); + }, this); + }; + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ''; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: '', + line: 1, + column: 0 + }; + 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) { + 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({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + return { + code: generated.code, + map: map + }; + }; + exports.SourceNode = SourceNode; + }); + }); + require.define('/node_modules/source-map/lib/source-map/util.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + 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; + if (aPath.match(urlRegexp)) { + return aPath; + } + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + var url = urlParse(aRoot); + if (aPath.charAt(0) == '/' && url && url.path == '/') { + return aPath.slice(1); + } + return aPath.indexOf(aRoot + '/') === 0 ? aPath.substr(aRoot.length + 1) : aPath; + } + exports.relative = relative; + }); + }); + require.define('/node_modules/source-map/node_modules/amdefine/amdefine.js', function (module, exports, __dirname, __filename) { + 'use strict'; + function amdefine(module, requireFn) { + 'use strict'; + var defineCache = {}, loaderCache = {}, alreadyCalled = false, path = require('path', module), makeRequire, stringRequire; + 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] === '..')) { + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + function normalize(name, baseName) { + var baseParts; + if (name && name.charAt(0) === '.') { + if (baseName) { + baseParts = baseName.split('/'); + baseParts = baseParts.slice(0, baseParts.length - 1); + baseParts = baseParts.concat(name.split('/')); + trimDots(baseParts); + name = baseParts.join('/'); + } + } + return name; + } + function makeNormalize(relName) { + return function (name) { + return normalize(name, relName); + }; + } + function makeLoad(id) { + function load(value) { + loaderCache[id] = value; + } + load.fromText = function (id, text) { + throw new Error('amdefine does not implement load.fromText'); + }; + return load; + } + makeRequire = function (systemRequire, exports, module, relId) { + function amdRequire(deps, callback) { + if (typeof deps === 'string') { + return stringRequire(systemRequire, exports, module, deps, relId); + } else { + deps = deps.map(function (depName) { + return stringRequire(systemRequire, exports, module, depName, relId); + }); + process.nextTick(function () { + callback.apply(null, deps); + }); + } + } + amdRequire.toUrl = function (filePath) { + if (filePath.indexOf('.') === 0) { + return normalize(filePath, path.dirname(module.filename)); + } else { + return filePath; + } + }; + return amdRequire; + }; + requireFn = requireFn || function req() { + return module.require.apply(module, arguments); + }; + function runFactory(id, deps, factory) { + var r, e, m, result; + if (id) { + e = loaderCache[id] = {}; + m = { + id: id, + uri: __filename, + exports: e + }; + r = makeRequire(requireFn, e, m, id); + } else { + if (alreadyCalled) { + throw new Error('amdefine with no module ID cannot be called more than once per file.'); + } + alreadyCalled = true; + e = module.exports; + m = module; + r = makeRequire(requireFn, e, m, module.id); + } + if (deps) { + deps = deps.map(function (depName) { + return r(depName); + }); + } + if (typeof factory === 'function') { + result = factory.apply(m.exports, deps); + } else { + result = factory; + } + if (result !== undefined) { + m.exports = result; + if (id) { + loaderCache[id] = m.exports; + } + } + } + stringRequire = function (systemRequire, exports, module, id, relId) { + var index = id.indexOf('!'), originalId = id, prefix, plugin; + if (index === -1) { + id = normalize(id, relId); + if (id === 'require') { + return makeRequire(systemRequire, exports, module, relId); + } else if (id === 'exports') { + return exports; + } else if (id === 'module') { + return module; + } else if (loaderCache.hasOwnProperty(id)) { + return loaderCache[id]; + } else if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } else { + if (systemRequire) { + return systemRequire(originalId); + } else { + throw new Error('No module with ID: ' + id); + } + } + } else { + prefix = id.substring(0, index); + id = id.substring(index + 1, id.length); + plugin = stringRequire(systemRequire, exports, module, prefix, relId); + if (plugin.normalize) { + id = plugin.normalize(id, makeNormalize(relId)); + } else { + id = normalize(id, relId); + } + if (loaderCache[id]) { + return loaderCache[id]; + } else { + plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); + return loaderCache[id]; + } + } + }; + function define(id, deps, factory) { + if (Array.isArray(id)) { + factory = deps; + deps = id; + id = undefined; + } else if (typeof id !== 'string') { + factory = id; + id = deps = undefined; + } + if (deps && !Array.isArray(deps)) { + factory = deps; + deps = undefined; + } + if (!deps) { + deps = [ + 'require', + 'exports', + 'module' + ]; + } + if (id) { + defineCache[id] = [ + id, + deps, + factory + ]; + } else { + runFactory(id, deps, factory); + } + } + define.require = function (id) { + if (loaderCache[id]) { + return loaderCache[id]; + } + if (defineCache[id]) { + runFactory.apply(null, defineCache[id]); + return loaderCache[id]; + } + }; + define.amd = {}; + return define; + } + module.exports = amdefine; + }); + require.define('/node_modules/source-map/lib/source-map/source-map-generator.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + var base64VLQ = require('/node_modules/source-map/lib/source-map/base64-vlq.js', module); + var util = require('/node_modules/source-map/lib/source-map/util.js', module); + var ArraySet = require('/node_modules/source-map/lib/source-map/array-set.js', module).ArraySet; + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet; + this._names = new ArraySet; + this._mappings = []; + this._sourcesContents = null; + } + SourceMapGenerator.prototype._version = 3; + SourceMapGenerator.fromSourceMap = function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + if (mapping.name) { + newMapping.name = mapping.name; + } + } + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + SourceMapGenerator.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + this._validateMapping(generated, original, source, name); + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + if (name && !this._names.has(name)) { + this._names.add(name); + } + this._mappings.push({ + generated: generated, + original: original, + source: source, + name: name + }); + }; + SourceMapGenerator.prototype.setSourceContent = function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + if (aSourceContent !== null) { + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + SourceMapGenerator.prototype.applySourceMap = function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + var newSources = new ArraySet; + var newNames = new ArraySet; + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.original) { + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.original.line, + column: mapping.original.column + }); + if (original.source !== null) { + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + mapping.original.line = original.line; + mapping.original.column = original.column; + if (original.name !== null && mapping.name !== null) { + mapping.name = original.name; + } + } + } + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + }, this); + this._sources = newSources; + this._names = newNames; + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + SourceMapGenerator.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { + return; + } else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aOriginal && 'line' in aOriginal && 'column' in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { + return; + } else { + throw new Error('Invalid mapping.'); + } + }; + 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); + } + SourceMapGenerator.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + this._mappings.sort(cmpMapping); + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + if (mapping.generated.line !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generated.line !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } else { + if (i > 0) { + if (!cmpMapping(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + result += base64VLQ.encode(mapping.generated.column - previousGeneratedColumn); + previousGeneratedColumn = mapping.generated.column; + if (mapping.source && mapping.original) { + result += base64VLQ.encode(this._sources.indexOf(mapping.source) - previousSource); + previousSource = this._sources.indexOf(mapping.source); + result += base64VLQ.encode(mapping.original.line - 1 - previousOriginalLine); + previousOriginalLine = mapping.original.line - 1; + result += base64VLQ.encode(mapping.original.column - previousOriginalColumn); + previousOriginalColumn = mapping.original.column; + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + return result; + }; + SourceMapGenerator.prototype.toJSON = function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = map.sources.map(function (source) { + if (map.sourceRoot) { + source = util.relative(map.sourceRoot, source); + } + return Object.prototype.hasOwnProperty.call(this._sourcesContents, util.toSetString(source)) ? this._sourcesContents[util.toSetString(source)] : null; + }, this); + } + return map; + }; + SourceMapGenerator.prototype.toString = function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + exports.SourceMapGenerator = SourceMapGenerator; + }); + }); + require.define('/node_modules/source-map/lib/source-map/array-set.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + var util = require('/node_modules/source-map/lib/source-map/util.js', module); + function ArraySet() { + this._array = []; + this._set = {}; + } + 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], aAllowDuplicates); + } + return set; + }; + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, util.toSetString(aStr)); + }; + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + exports.ArraySet = ArraySet; + }); + }); + require.define('/node_modules/source-map/lib/source-map/base64-vlq.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + var base64 = require('/node_modules/source-map/lib/source-map/base64.js', module); + var VLQ_BASE_SHIFT = 5; + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + var VLQ_BASE_MASK = VLQ_BASE - 1; + var VLQ_CONTINUATION_BIT = VLQ_BASE; + function toVLQSigned(aValue) { + return aValue < 0 ? (-aValue << 1) + 1 : (aValue << 1) + 0; + } + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative ? -shifted : shifted; + } + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ''; + var digit; + var vlq = toVLQSigned(aValue); + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + return encoded; + }; + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + do { + if (i >= strLen) { + throw new Error('Expected more digits in base 64 VLQ value.'); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + }); + }); + require.define('/node_modules/source-map/lib/source-map/base64.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + var charToIntMap = {}; + var intToCharMap = {}; + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('').forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError('Must be between 0 and 63: ' + aNumber); + }; + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError('Not a valid base 64 digit: ' + aChar); + }; + }); + }); + require.define('/node_modules/source-map/lib/source-map/source-map-consumer.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + var util = require('/node_modules/source-map/lib/source-map/util.js', module); + var binarySearch = require('/node_modules/source-map/lib/source-map/binary-search.js', module); + var ArraySet = require('/node_modules/source-map/lib/source-map/array-set.js', module).ArraySet; + var base64VLQ = require('/node_modules/source-map/lib/source-map/base64-vlq.js', module); + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + var names = util.getArg(sourceMap, 'names'); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } + this._names = ArraySet.fromArray(names, true); + this._sources = ArraySet.fromArray(sources, true); + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this.file = file; + this._generatedMappings = []; + this._originalMappings = []; + this._parseMappings(mappings, sourceRoot); + } + SourceMapConsumer.prototype._version = 3; + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + SourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } else if (str.charAt(0) === ',') { + str = str.slice(1); + } else { + mapping = {}; + mapping.generatedLine = generatedLine; + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + this._generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this._originalMappings.push(mapping); + } + } + } + this._originalMappings.sort(this._compareOriginalPositions); + }; + 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; + } + }; + SourceMapConsumer.prototype._compareGeneratedPositions = function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { + var cmp = mappingA.generatedLine - mappingB.generatedLine; + return cmp === 0 ? mappingA.generatedColumn - mappingB.generatedColumn : cmp; + }; + SourceMapConsumer.prototype._findMapping = function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, aColumnName, aComparator) { + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + aNeedle[aColumnName]); + } + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + SourceMapConsumer.prototype.originalPositionFor = function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + var mapping = this._findMapping(needle, this._generatedMappings, 'generatedLine', 'generatedColumn', this._compareGeneratedPositions); + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + return { + source: null, + line: null, + column: null, + name: null + }; + }; + SourceMapConsumer.prototype.sourceContentFor = function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + if (this.sourceRoot) { + 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))) { + 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.'); + }; + SourceMapConsumer.prototype.generatedPositionFor = function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + var mapping = this._findMapping(needle, this._originalMappings, 'originalLine', 'originalColumn', this._compareOriginalPositions); + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + return { + line: null, + column: null + }; + }; + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + SourceMapConsumer.prototype.eachMapping = function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error('Unknown order of iteration.'); + } + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + exports.SourceMapConsumer = SourceMapConsumer; + }); + }); + require.define('/node_modules/source-map/lib/source-map/binary-search.js', function (module, exports, __dirname, __filename) { + if (typeof define !== 'function') { + var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); + } + define(function (require, exports, module) { + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid]); + if (cmp === 0) { + return aHaystack[mid]; + } else if (cmp > 0) { + if (aHigh - mid > 1) { + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + return aHaystack[mid]; + } else { + if (mid - aLow > 1) { + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + return aLow < 0 ? null : aHaystack[aLow]; + } + } + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) : null; + }; + }); + }); + require.define('/node_modules/estraverse/estraverse.js', function (module, exports, __dirname, __filename) { + (function (root, factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory(root.estraverse = {}); + } + }(this, function (exports) { + 'use strict'; + var Syntax, isArray, VisitorOption, VisitorKeys, BREAK, SKIP; + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + ArrowFunctionExpression: 'ArrowFunctionExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + function ignoreJSHintError() { + } + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + function deepCopy(obj) { + var ret = {}, key, val; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (typeof val === 'object' && val !== null) { + ret[key] = deepCopy(val); + } else { + ret[key] = val; + } + } + } + return ret; + } + function shallowCopy(obj) { + var ret = {}, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ret[key] = obj[key]; + } + } + return ret; + } + ignoreJSHintError(shallowCopy); + function upperBound(array, func) { + var diff, len, i, current; + len = array.length; + i = 0; + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + len = diff; + } else { + i = current + 1; + len -= diff + 1; + } + } + return i; + } + function lowerBound(array, func) { + var diff, len, i, current; + len = array.length; + i = 0; + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + i = current + 1; + len -= diff + 1; + } else { + len = diff; + } + } + return i; + } + ignoreJSHintError(lowerBound); + VisitorKeys = { + AssignmentExpression: [ + 'left', + 'right' + ], + ArrayExpression: ['elements'], + ArrowFunctionExpression: [ + 'params', + 'body' + ], + BlockStatement: ['body'], + BinaryExpression: [ + 'left', + 'right' + ], + BreakStatement: ['label'], + CallExpression: [ + 'callee', + 'arguments' + ], + CatchClause: [ + 'param', + 'body' + ], + ConditionalExpression: [ + 'test', + 'consequent', + 'alternate' + ], + ContinueStatement: ['label'], + DebuggerStatement: [], + DirectiveStatement: [], + DoWhileStatement: [ + 'body', + 'test' + ], + EmptyStatement: [], + ExpressionStatement: ['expression'], + ForStatement: [ + 'init', + 'test', + 'update', + 'body' + ], + ForInStatement: [ + 'left', + 'right', + 'body' + ], + FunctionDeclaration: [ + 'id', + 'params', + 'body' + ], + FunctionExpression: [ + 'id', + 'params', + 'body' + ], + Identifier: [], + IfStatement: [ + 'test', + 'consequent', + 'alternate' + ], + Literal: [], + LabeledStatement: [ + 'label', + 'body' + ], + LogicalExpression: [ + 'left', + 'right' + ], + MemberExpression: [ + 'object', + 'property' + ], + NewExpression: [ + 'callee', + 'arguments' + ], + ObjectExpression: ['properties'], + Program: ['body'], + Property: [ + 'key', + 'value' + ], + ReturnStatement: ['argument'], + SequenceExpression: ['expressions'], + SwitchStatement: [ + 'discriminant', + 'cases' + ], + SwitchCase: [ + 'test', + 'consequent' + ], + ThisExpression: [], + ThrowStatement: ['argument'], + TryStatement: [ + 'block', + 'handlers', + 'handler', + 'guardedHandlers', + 'finalizer' + ], + UnaryExpression: ['argument'], + UpdateExpression: ['argument'], + VariableDeclaration: ['declarations'], + VariableDeclarator: [ + 'id', + 'init' + ], + WhileStatement: [ + 'test', + 'body' + ], + WithStatement: [ + 'object', + 'body' + ], + YieldExpression: ['argument'] + }; + BREAK = {}; + SKIP = {}; + VisitorOption = { + Break: BREAK, + Skip: SKIP + }; + function Reference(parent, key) { + this.parent = parent; + this.key = key; + } + Reference.prototype.replace = function replace(node) { + this.parent[this.key] = node; + }; + function Element(node, path, wrap, ref) { + this.node = node; + this.path = path; + this.wrap = wrap; + this.ref = ref; + } + function Controller() { + } + Controller.prototype.path = function path() { + var i, iz, j, jz, result, element; + function addToPath(result, path) { + if (isArray(path)) { + for (j = 0, jz = path.length; j < jz; ++j) { + result.push(path[j]); + } + } else { + result.push(path); + } + } + if (!this.__current.path) { + return null; + } + result = []; + for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { + element = this.__leavelist[i]; + addToPath(result, element.path); + } + addToPath(result, this.__current.path); + return result; + }; + Controller.prototype.parents = function parents() { + var i, iz, result; + result = []; + for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { + result.push(this.__leavelist[i].node); + } + return result; + }; + Controller.prototype.current = function current() { + return this.__current.node; + }; + Controller.prototype.__execute = function __execute(callback, element) { + var previous, result; + result = undefined; + previous = this.__current; + this.__current = element; + this.__state = null; + if (callback) { + result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); + } + this.__current = previous; + return result; + }; + Controller.prototype.notify = function notify(flag) { + this.__state = flag; + }; + Controller.prototype.skip = function () { + this.notify(SKIP); + }; + Controller.prototype['break'] = function () { + this.notify(BREAK); + }; + Controller.prototype.__initialize = function (root, visitor) { + this.visitor = visitor; + this.root = root; + this.__worklist = []; + this.__leavelist = []; + this.__current = null; + this.__state = null; + }; + Controller.prototype.traverse = function traverse(root, visitor) { + var worklist, leavelist, element, node, nodeType, ret, key, current, current2, candidates, candidate, sentinel; + this.__initialize(root, visitor); + sentinel = {}; + worklist = this.__worklist; + leavelist = this.__leavelist; + worklist.push(new Element(root, null, null, null)); + leavelist.push(new Element(null, null, null, null)); + while (worklist.length) { + element = worklist.pop(); + if (element === sentinel) { + element = leavelist.pop(); + ret = this.__execute(visitor.leave, element); + if (this.__state === BREAK || ret === BREAK) { + return; + } + continue; + } + if (element.node) { + ret = this.__execute(visitor.enter, element); + if (this.__state === BREAK || ret === BREAK) { + return; + } + worklist.push(sentinel); + leavelist.push(element); + if (this.__state === SKIP || ret === SKIP) { + continue; + } + node = element.node; + nodeType = element.wrap || node.type; + candidates = VisitorKeys[nodeType]; + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + if (!isArray(candidate)) { + worklist.push(new Element(candidate, key, null, null)); + continue; + } + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { + element = new Element(candidate[current2], [ + key, + current2 + ], 'Property', null); + } else { + element = new Element(candidate[current2], [ + key, + current2 + ], null, null); + } + worklist.push(element); + } + } + } + } + }; + Controller.prototype.replace = function replace(root, visitor) { + var worklist, leavelist, node, nodeType, target, element, current, current2, candidates, candidate, sentinel, outer, key; + this.__initialize(root, visitor); + sentinel = {}; + worklist = this.__worklist; + leavelist = this.__leavelist; + outer = { root: root }; + element = new Element(root, null, null, new Reference(outer, 'root')); + worklist.push(element); + leavelist.push(element); + while (worklist.length) { + element = worklist.pop(); + if (element === sentinel) { + element = leavelist.pop(); + target = this.__execute(visitor.leave, element); + if (target !== undefined && target !== BREAK && target !== SKIP) { + element.ref.replace(target); + } + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + continue; + } + target = this.__execute(visitor.enter, element); + if (target !== undefined && target !== BREAK && target !== SKIP) { + element.ref.replace(target); + element.node = target; + } + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + node = element.node; + if (!node) { + continue; + } + worklist.push(sentinel); + leavelist.push(element); + if (this.__state === SKIP || target === SKIP) { + continue; + } + nodeType = element.wrap || node.type; + candidates = VisitorKeys[nodeType]; + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + if (!isArray(candidate)) { + worklist.push(new Element(candidate, key, null, new Reference(node, key))); + continue; + } + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { + element = new Element(candidate[current2], [ + key, + current2 + ], 'Property', new Reference(candidate, current2)); + } else { + element = new Element(candidate[current2], [ + key, + current2 + ], null, new Reference(candidate, current2)); + } + worklist.push(element); + } + } + } + return outer.root; + }; + function traverse(root, visitor) { + var controller = new Controller; + return controller.traverse(root, visitor); + } + function replace(root, visitor) { + var controller = new Controller; + return controller.replace(root, visitor); + } + function extendCommentRange(comment, tokens) { + var target, token; + target = upperBound(tokens, function search(token) { + return token.range[0] > comment.range[0]; + }); + comment.extendedRange = [ + comment.range[0], + comment.range[1] + ]; + if (target !== tokens.length) { + comment.extendedRange[1] = tokens[target].range[0]; + } + target -= 1; + if (target >= 0) { + if (target < tokens.length) { + comment.extendedRange[0] = tokens[target].range[1]; + } else if (token.length) { + comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; + } + } + return comment; + } + function attachComments(tree, providedComments, tokens) { + var comments = [], comment, len, i, cursor; + if (!tree.range) { + throw new Error('attachComments needs range information'); + } + if (!tokens.length) { + if (providedComments.length) { + for (i = 0, len = providedComments.length; i < len; i += 1) { + comment = deepCopy(providedComments[i]); + comment.extendedRange = [ + 0, + tree.range[0] + ]; + comments.push(comment); + } + tree.leadingComments = comments; + } + return tree; + } + for (i = 0, len = providedComments.length; i < len; i += 1) { + comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); + } + cursor = 0; + traverse(tree, { + enter: function (node) { + var comment; + while (cursor < comments.length) { + comment = comments[cursor]; + if (comment.extendedRange[1] > node.range[0]) { + break; + } + if (comment.extendedRange[1] === node.range[0]) { + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + if (cursor === comments.length) { + return VisitorOption.Break; + } + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + cursor = 0; + traverse(tree, { + leave: function (node) { + var comment; + while (cursor < comments.length) { + comment = comments[cursor]; + if (node.range[1] < comment.extendedRange[0]) { + break; + } + if (node.range[1] === comment.extendedRange[0]) { + if (!node.trailingComments) { + node.trailingComments = []; + } + node.trailingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + if (cursor === comments.length) { + return VisitorOption.Break; + } + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + return tree; + } + exports.version = '1.3.1'; + exports.Syntax = Syntax; + exports.traverse = traverse; + exports.replace = replace; + exports.attachComments = attachComments; + exports.VisitorKeys = VisitorKeys; + exports.VisitorOption = VisitorOption; + exports.Controller = Controller; + })); + }); + require('/tools/entry-point.js'); +}.call(this, this)); diff --git a/toolkit/devtools/escodegen/estraverse.js b/toolkit/devtools/escodegen/estraverse.js new file mode 100644 index 00000000000..211617d24ef --- /dev/null +++ b/toolkit/devtools/escodegen/estraverse.js @@ -0,0 +1,678 @@ +/* + Copyright (C) 2012-2013 Yusuke Suzuki + Copyright (C) 2012 Ariya Hidayat + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/*jslint vars:false*/ +/*jshint indent:4*/ +/*global exports:true, define:true*/ +(function (root, factory) { + 'use strict'; + + // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, + // and plain browser loading, + if (typeof define === 'function' && define.amd) { + define(['exports'], factory); + } else if (typeof exports !== 'undefined') { + factory(exports); + } else { + factory((root.estraverse = {})); + } +}(this, function (exports) { + 'use strict'; + + var Syntax, + isArray, + VisitorOption, + VisitorKeys, + BREAK, + SKIP; + + Syntax = { + AssignmentExpression: 'AssignmentExpression', + ArrayExpression: 'ArrayExpression', + BlockStatement: 'BlockStatement', + BinaryExpression: 'BinaryExpression', + BreakStatement: 'BreakStatement', + CallExpression: 'CallExpression', + CatchClause: 'CatchClause', + ConditionalExpression: 'ConditionalExpression', + ContinueStatement: 'ContinueStatement', + DebuggerStatement: 'DebuggerStatement', + DirectiveStatement: 'DirectiveStatement', + DoWhileStatement: 'DoWhileStatement', + EmptyStatement: 'EmptyStatement', + ExpressionStatement: 'ExpressionStatement', + ForStatement: 'ForStatement', + ForInStatement: 'ForInStatement', + FunctionDeclaration: 'FunctionDeclaration', + FunctionExpression: 'FunctionExpression', + Identifier: 'Identifier', + IfStatement: 'IfStatement', + Literal: 'Literal', + LabeledStatement: 'LabeledStatement', + LogicalExpression: 'LogicalExpression', + MemberExpression: 'MemberExpression', + NewExpression: 'NewExpression', + ObjectExpression: 'ObjectExpression', + Program: 'Program', + Property: 'Property', + ReturnStatement: 'ReturnStatement', + SequenceExpression: 'SequenceExpression', + SwitchStatement: 'SwitchStatement', + SwitchCase: 'SwitchCase', + ThisExpression: 'ThisExpression', + ThrowStatement: 'ThrowStatement', + TryStatement: 'TryStatement', + UnaryExpression: 'UnaryExpression', + UpdateExpression: 'UpdateExpression', + VariableDeclaration: 'VariableDeclaration', + VariableDeclarator: 'VariableDeclarator', + WhileStatement: 'WhileStatement', + WithStatement: 'WithStatement', + YieldExpression: 'YieldExpression' + }; + + function ignoreJSHintError() { } + + isArray = Array.isArray; + if (!isArray) { + isArray = function isArray(array) { + return Object.prototype.toString.call(array) === '[object Array]'; + }; + } + + function deepCopy(obj) { + var ret = {}, key, val; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (typeof val === 'object' && val !== null) { + ret[key] = deepCopy(val); + } else { + ret[key] = val; + } + } + } + return ret; + } + + function shallowCopy(obj) { + var ret = {}, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + ret[key] = obj[key]; + } + } + return ret; + } + ignoreJSHintError(shallowCopy); + + // based on LLVM libc++ upper_bound / lower_bound + // MIT License + + function upperBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + len = diff; + } else { + i = current + 1; + len -= diff + 1; + } + } + return i; + } + + function lowerBound(array, func) { + var diff, len, i, current; + + len = array.length; + i = 0; + + while (len) { + diff = len >>> 1; + current = i + diff; + if (func(array[current])) { + i = current + 1; + len -= diff + 1; + } else { + len = diff; + } + } + return i; + } + ignoreJSHintError(lowerBound); + + VisitorKeys = { + AssignmentExpression: ['left', 'right'], + ArrayExpression: ['elements'], + BlockStatement: ['body'], + BinaryExpression: ['left', 'right'], + BreakStatement: ['label'], + CallExpression: ['callee', 'arguments'], + CatchClause: ['param', 'body'], + ConditionalExpression: ['test', 'consequent', 'alternate'], + ContinueStatement: ['label'], + DebuggerStatement: [], + DirectiveStatement: [], + DoWhileStatement: ['body', 'test'], + EmptyStatement: [], + ExpressionStatement: ['expression'], + ForStatement: ['init', 'test', 'update', 'body'], + ForInStatement: ['left', 'right', 'body'], + FunctionDeclaration: ['id', 'params', 'body'], + FunctionExpression: ['id', 'params', 'body'], + Identifier: [], + IfStatement: ['test', 'consequent', 'alternate'], + Literal: [], + LabeledStatement: ['label', 'body'], + LogicalExpression: ['left', 'right'], + MemberExpression: ['object', 'property'], + NewExpression: ['callee', 'arguments'], + ObjectExpression: ['properties'], + Program: ['body'], + Property: ['key', 'value'], + ReturnStatement: ['argument'], + SequenceExpression: ['expressions'], + SwitchStatement: ['discriminant', 'cases'], + SwitchCase: ['test', 'consequent'], + ThisExpression: [], + ThrowStatement: ['argument'], + TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], + UnaryExpression: ['argument'], + UpdateExpression: ['argument'], + VariableDeclaration: ['declarations'], + VariableDeclarator: ['id', 'init'], + WhileStatement: ['test', 'body'], + WithStatement: ['object', 'body'], + YieldExpression: ['argument'] + }; + + // unique id + BREAK = {}; + SKIP = {}; + + VisitorOption = { + Break: BREAK, + Skip: SKIP + }; + + function Reference(parent, key) { + this.parent = parent; + this.key = key; + } + + Reference.prototype.replace = function replace(node) { + this.parent[this.key] = node; + }; + + function Element(node, path, wrap, ref) { + this.node = node; + this.path = path; + this.wrap = wrap; + this.ref = ref; + } + + function Controller() { } + + // API: + // return property path array from root to current node + Controller.prototype.path = function path() { + var i, iz, j, jz, result, element; + + function addToPath(result, path) { + if (isArray(path)) { + for (j = 0, jz = path.length; j < jz; ++j) { + result.push(path[j]); + } + } else { + result.push(path); + } + } + + // root node + if (!this.__current.path) { + return null; + } + + // first node is sentinel, second node is root element + result = []; + for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { + element = this.__leavelist[i]; + addToPath(result, element.path); + } + addToPath(result, this.__current.path); + return result; + }; + + // API: + // return array of parent elements + Controller.prototype.parents = function parents() { + var i, iz, result; + + // first node is sentinel + result = []; + for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { + result.push(this.__leavelist[i].node); + } + + return result; + }; + + // API: + // return current node + Controller.prototype.current = function current() { + return this.__current.node; + }; + + Controller.prototype.__execute = function __execute(callback, element) { + var previous, result; + + result = undefined; + + previous = this.__current; + this.__current = element; + this.__state = null; + if (callback) { + result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); + } + this.__current = previous; + + return result; + }; + + // API: + // notify control skip / break + Controller.prototype.notify = function notify(flag) { + this.__state = flag; + }; + + // API: + // skip child nodes of current node + Controller.prototype.skip = function () { + this.notify(SKIP); + }; + + // API: + // break traversals + Controller.prototype['break'] = function () { + this.notify(BREAK); + }; + + Controller.prototype.__initialize = function(root, visitor) { + this.visitor = visitor; + this.root = root; + this.__worklist = []; + this.__leavelist = []; + this.__current = null; + this.__state = null; + }; + + Controller.prototype.traverse = function traverse(root, visitor) { + var worklist, + leavelist, + element, + node, + nodeType, + ret, + key, + current, + current2, + candidates, + candidate, + sentinel; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + worklist.push(new Element(root, null, null, null)); + leavelist.push(new Element(null, null, null, null)); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + ret = this.__execute(visitor.leave, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + continue; + } + + if (element.node) { + + ret = this.__execute(visitor.enter, element); + + if (this.__state === BREAK || ret === BREAK) { + return; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || ret === SKIP) { + continue; + } + + node = element.node; + nodeType = element.wrap || node.type; + candidates = VisitorKeys[nodeType]; + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (!isArray(candidate)) { + worklist.push(new Element(candidate, key, null, null)); + continue; + } + + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { + element = new Element(candidate[current2], [key, current2], 'Property', null); + } else { + element = new Element(candidate[current2], [key, current2], null, null); + } + worklist.push(element); + } + } + } + } + }; + + Controller.prototype.replace = function replace(root, visitor) { + var worklist, + leavelist, + node, + nodeType, + target, + element, + current, + current2, + candidates, + candidate, + sentinel, + outer, + key; + + this.__initialize(root, visitor); + + sentinel = {}; + + // reference + worklist = this.__worklist; + leavelist = this.__leavelist; + + // initialize + outer = { + root: root + }; + element = new Element(root, null, null, new Reference(outer, 'root')); + worklist.push(element); + leavelist.push(element); + + while (worklist.length) { + element = worklist.pop(); + + if (element === sentinel) { + element = leavelist.pop(); + + target = this.__execute(visitor.leave, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP) { + // replace + element.ref.replace(target); + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + continue; + } + + target = this.__execute(visitor.enter, element); + + // node may be replaced with null, + // so distinguish between undefined and null in this place + if (target !== undefined && target !== BREAK && target !== SKIP) { + // replace + element.ref.replace(target); + element.node = target; + } + + if (this.__state === BREAK || target === BREAK) { + return outer.root; + } + + // node may be null + node = element.node; + if (!node) { + continue; + } + + worklist.push(sentinel); + leavelist.push(element); + + if (this.__state === SKIP || target === SKIP) { + continue; + } + + nodeType = element.wrap || node.type; + candidates = VisitorKeys[nodeType]; + + current = candidates.length; + while ((current -= 1) >= 0) { + key = candidates[current]; + candidate = node[key]; + if (!candidate) { + continue; + } + + if (!isArray(candidate)) { + worklist.push(new Element(candidate, key, null, new Reference(node, key))); + continue; + } + + current2 = candidate.length; + while ((current2 -= 1) >= 0) { + if (!candidate[current2]) { + continue; + } + if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { + element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); + } else { + element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); + } + worklist.push(element); + } + } + } + + return outer.root; + }; + + function traverse(root, visitor) { + var controller = new Controller(); + return controller.traverse(root, visitor); + } + + function replace(root, visitor) { + var controller = new Controller(); + return controller.replace(root, visitor); + } + + function extendCommentRange(comment, tokens) { + var target, token; + + target = upperBound(tokens, function search(token) { + return token.range[0] > comment.range[0]; + }); + + comment.extendedRange = [comment.range[0], comment.range[1]]; + + if (target !== tokens.length) { + comment.extendedRange[1] = tokens[target].range[0]; + } + + target -= 1; + if (target >= 0) { + if (target < tokens.length) { + comment.extendedRange[0] = tokens[target].range[1]; + } else if (token.length) { + comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; + } + } + + return comment; + } + + function attachComments(tree, providedComments, tokens) { + // At first, we should calculate extended comment ranges. + var comments = [], comment, len, i, cursor; + + if (!tree.range) { + throw new Error('attachComments needs range information'); + } + + // tokens array is empty, we attach comments to tree as 'leadingComments' + if (!tokens.length) { + if (providedComments.length) { + for (i = 0, len = providedComments.length; i < len; i += 1) { + comment = deepCopy(providedComments[i]); + comment.extendedRange = [0, tree.range[0]]; + comments.push(comment); + } + tree.leadingComments = comments; + } + return tree; + } + + for (i = 0, len = providedComments.length; i < len; i += 1) { + comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); + } + + // This is based on John Freeman's implementation. + cursor = 0; + traverse(tree, { + enter: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (comment.extendedRange[1] > node.range[0]) { + break; + } + + if (comment.extendedRange[1] === node.range[0]) { + if (!node.leadingComments) { + node.leadingComments = []; + } + node.leadingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + cursor = 0; + traverse(tree, { + leave: function (node) { + var comment; + + while (cursor < comments.length) { + comment = comments[cursor]; + if (node.range[1] < comment.extendedRange[0]) { + break; + } + + if (node.range[1] === comment.extendedRange[0]) { + if (!node.trailingComments) { + node.trailingComments = []; + } + node.trailingComments.push(comment); + comments.splice(cursor, 1); + } else { + cursor += 1; + } + } + + // already out of owned node + if (cursor === comments.length) { + return VisitorOption.Break; + } + + if (comments[cursor].extendedRange[0] > node.range[1]) { + return VisitorOption.Skip; + } + } + }); + + return tree; + } + + exports.version = '1.3.0'; + exports.Syntax = Syntax; + exports.traverse = traverse; + exports.replace = replace; + exports.attachComments = attachComments; + exports.VisitorKeys = VisitorKeys; + exports.VisitorOption = VisitorOption; + exports.Controller = Controller; +})); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/toolkit/devtools/pretty-fast/moz.build b/toolkit/devtools/escodegen/moz.build similarity index 73% rename from toolkit/devtools/pretty-fast/moz.build rename to toolkit/devtools/escodegen/moz.build index 1190adac810..4c70f2f5b6d 100644 --- a/toolkit/devtools/pretty-fast/moz.build +++ b/toolkit/devtools/escodegen/moz.build @@ -6,8 +6,11 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] -JS_MODULES_PATH = 'modules/devtools' +JS_MODULES_PATH = 'modules/devtools/escodegen' EXTRA_JS_MODULES += [ - 'pretty-fast.js', + 'escodegen.js', + 'escodegen.worker.js', + 'estraverse.js', + 'package.json.js', ] diff --git a/toolkit/devtools/escodegen/package.json.js b/toolkit/devtools/escodegen/package.json.js new file mode 100644 index 00000000000..84c83e733a7 --- /dev/null +++ b/toolkit/devtools/escodegen/package.json.js @@ -0,0 +1,57 @@ +module.exports = { + "name": "escodegen", + "description": "ECMAScript code generator", + "homepage": "http://github.com/Constellation/escodegen.html", + "main": "escodegen.js", + "bin": { + "esgenerate": "./bin/esgenerate.js", + "escodegen": "./bin/escodegen.js" + }, + "version": "0.0.26", + "engines": { + "node": ">=0.4.0" + }, + "maintainers": [ + { + "name": "Yusuke Suzuki", + "email": "utatane.tea@gmail.com", + "web": "http://github.com/Constellation" + } + ], + "repository": { + "type": "git", + "url": "http://github.com/Constellation/escodegen.git" + }, + "dependencies": { + "esprima": "~1.0.2", + "estraverse": "~1.3.0" + }, + "optionalDependencies": { + "source-map": ">= 0.1.2" + }, + "devDependencies": { + "esprima-moz": "*", + "commonjs-everywhere": "~0.8.0", + "q": "*", + "bower": "*", + "semver": "*", + "chai": "~1.7.2", + "grunt-contrib-jshint": "~0.5.0", + "grunt-cli": "~0.1.9", + "grunt": "~0.4.1", + "grunt-mocha-test": "~0.6.2" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD" + } + ], + "scripts": { + "test": "grunt travis", + "unit-test": "grunt test", + "lint": "grunt lint", + "release": "node tools/release.js", + "build": "./node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.js" + } +}; diff --git a/toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js b/toolkit/devtools/escodegen/tests/unit/head_escodegen.js similarity index 82% rename from toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js rename to toolkit/devtools/escodegen/tests/unit/head_escodegen.js index 0dfdca9c59e..1a51912ec72 100644 --- a/toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js +++ b/toolkit/devtools/escodegen/tests/unit/head_escodegen.js @@ -7,11 +7,6 @@ const Cr = Components.results; const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const { require } = devtools; -this.sourceMap = require("source-map"); -this.acorn = require("acorn"); -this.prettyFast = require("devtools/pretty-fast"); -const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); - // Register a console listener, so console messages don't just disappear // into the ether. let errorCount = 0; @@ -36,7 +31,7 @@ let listener = { } } - do_throw("head_pretty-fast.js got console message: " + string + "\n"); + do_throw("head_dbg.js got console message: " + string + "\n"); } }; diff --git a/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js b/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js new file mode 100644 index 00000000000..c7f6ba96bf0 --- /dev/null +++ b/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js @@ -0,0 +1,71 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Test that we can generate source maps via escodegen. + */ + +Components.utils.import("resource://gre/modules/reflect.jsm"); +Components.utils.import("resource://gre/modules/devtools/SourceMap.jsm"); +const escodegen = require("escodegen/escodegen"); + +const testCode = "" + function main() { + var a = 5 + 3; + var b = 19 * 52; + return a / b; +}; + +function run_test() { + const ast = Reflect.parse(testCode); + const { code, map } = escodegen.generate(ast, { + format: { + indent: { + // Single space indents so we are mapping different locations. + style: " " + } + }, + sourceMap: "testCode.js", + sourceMapWithCode: true + }); + const smc = new SourceMapConsumer(map.toString()); + + let mapping = smc.originalPositionFor({ + line: 2, + column: 1 + }); + do_check_eq(mapping.source, "testCode.js"); + do_check_eq(mapping.line, 2); + do_check_eq(mapping.column, 2); + + mapping = smc.originalPositionFor({ + line: 2, + column: 5 + }); + do_check_eq(mapping.source, "testCode.js"); + do_check_eq(mapping.line, 2); + do_check_eq(mapping.column, 6); + + mapping = smc.originalPositionFor({ + line: 3, + column: 1 + }); + do_check_eq(mapping.source, "testCode.js"); + do_check_eq(mapping.line, 3); + do_check_eq(mapping.column, 2); + + mapping = smc.originalPositionFor({ + line: 3, + column: 5 + }); + do_check_eq(mapping.source, "testCode.js"); + do_check_eq(mapping.line, 3); + do_check_eq(mapping.column, 6); + + mapping = smc.originalPositionFor({ + line: 4, + column: 1 + }); + do_check_eq(mapping.source, "testCode.js"); + do_check_eq(mapping.line, 4); + do_check_eq(mapping.column, 2); +}; diff --git a/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js b/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js new file mode 100644 index 00000000000..a9f76e41fed --- /dev/null +++ b/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js @@ -0,0 +1,11 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Test that we can require escodegen. + */ + +function run_test() { + const escodegen = require("escodegen/escodegen"); + do_check_eq(typeof escodegen.generate, "function"); +} diff --git a/toolkit/devtools/escodegen/tests/unit/test_same_ast.js b/toolkit/devtools/escodegen/tests/unit/test_same_ast.js new file mode 100644 index 00000000000..72b4200a05d --- /dev/null +++ b/toolkit/devtools/escodegen/tests/unit/test_same_ast.js @@ -0,0 +1,76 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Test that we can go AST -> JS -> AST via escodegen and Reflect. + */ + +const escodegen = require("escodegen/escodegen"); +Components.utils.import("resource://gre/modules/reflect.jsm"); + +const testCode = "" + function main () { + function makeAcc(n) { + return function () { + return ++n; + }; + } + + var acc = makeAcc(10); + + for (var i = 0; i < 10; i++) { + acc(); + } + + console.log(acc()); +}; + +function run_test() { + const originalAST = Reflect.parse(testCode); + const generatedCode = escodegen.generate(originalAST); + const generatedAST = Reflect.parse(generatedCode); + + do_print("Original AST:"); + do_print(JSON.stringify(originalAST, null, 2)); + do_print("Generated AST:"); + do_print(JSON.stringify(generatedAST, null, 2)); + + checkEquivalentASTs(originalAST, generatedAST); +} + +const isObject = (obj) => typeof obj === "object" && obj !== null; +const zip = (a, b) => { + let pairs = []; + for (let i = 0; i < a.length && i < b.length; i++) { + pairs.push([a[i], b[i]]); + } + return pairs; +}; +const isntLoc = k => k !== "loc"; + +function checkEquivalentASTs(expected, actual, prop = []) { + do_print("Checking: " + prop.join(" ")); + + if (!isObject(expected)) { + return void do_check_eq(expected, actual); + } + + do_check_true(isObject(actual)); + + if (Array.isArray(expected)) { + do_check_true(Array.isArray(actual)); + do_check_eq(expected.length, actual.length); + let i = 0; + for (let [e, a] of zip(expected, actual)) { + checkEquivalentASTs(a, e, prop.concat([i++])); + } + return; + } + + const expectedKeys = Object.keys(expected).filter(isntLoc).sort(); + const actualKeys = Object.keys(actual).filter(isntLoc).sort(); + do_check_eq(expectedKeys.length, actualKeys.length); + for (let [ek, ak] of zip(expectedKeys, actualKeys)) { + do_check_eq(ek, ak); + checkEquivalentASTs(expected[ek], actual[ak], prop.concat([ek])); + } +} diff --git a/toolkit/devtools/escodegen/tests/unit/xpcshell.ini b/toolkit/devtools/escodegen/tests/unit/xpcshell.ini new file mode 100644 index 00000000000..e8d9f152bae --- /dev/null +++ b/toolkit/devtools/escodegen/tests/unit/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = head_escodegen.js +tail = + +[test_import_escodegen.js] +[test_same_ast.js] +[test_generate_source_maps.js] diff --git a/toolkit/devtools/moz.build b/toolkit/devtools/moz.build index 20022d77b59..16897d5e427 100644 --- a/toolkit/devtools/moz.build +++ b/toolkit/devtools/moz.build @@ -14,6 +14,6 @@ PARALLEL_DIRS += [ 'webconsole', 'apps', 'styleinspector', - 'acorn', - 'pretty-fast' + 'escodegen', + 'acorn' ] diff --git a/toolkit/devtools/pretty-fast/UPGRADING.md b/toolkit/devtools/pretty-fast/UPGRADING.md deleted file mode 100644 index 6ad0071c896..00000000000 --- a/toolkit/devtools/pretty-fast/UPGRADING.md +++ /dev/null @@ -1,7 +0,0 @@ -# UPGRADING - -1. `git clone https://github.com/mozilla/pretty-fast.git` - -2. Copy `pretty-fast/pretty-fast.js` to `toolkit/devtools/pretty-fast/pretty-fast.js` - -3. Copy `pretty-fast/test.js` to `toolkit/devtools/pretty-fast/tests/unit/test.js` diff --git a/toolkit/devtools/pretty-fast/pretty-fast.js b/toolkit/devtools/pretty-fast/pretty-fast.js deleted file mode 100644 index 33b7f82e6e9..00000000000 --- a/toolkit/devtools/pretty-fast/pretty-fast.js +++ /dev/null @@ -1,781 +0,0 @@ -/* - * Copyright 2013 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.md or: - * http://opensource.org/licenses/BSD-2-Clause - */ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define(factory); - } else if (typeof exports === 'object') { - module.exports = factory(); - } else { - root.prettyFast = factory(); - } -}(this, function () { - "use strict"; - - var acorn = this.acorn || require("acorn"); - var sourceMap = this.sourceMap || require("source-map"); - var SourceNode = sourceMap.SourceNode; - - // If any of these tokens are seen before a "[" token, we know that "[" token - // is the start of an array literal, rather than a property access. - // - // The only exception is "}", which would need to be disambiguated by - // parsing. The majority of the time, an open bracket following a closing - // curly is going to be an array literal, so we brush the complication under - // the rug, and handle the ambiguity by always assuming that it will be an - // array literal. - var PRE_ARRAY_LITERAL_TOKENS = { - "typeof": true, - "void": true, - "delete": true, - "case": true, - "do": true, - "=": true, - "in": true, - "{": true, - "*": true, - "/": true, - "%": true, - "else": true, - ";": true, - "++": true, - "--": true, - "+": true, - "-": true, - "~": true, - "!": true, - ":": true, - "?": true, - ">>": true, - ">>>": true, - "<<": true, - "||": true, - "&&": true, - "<": true, - ">": true, - "<=": true, - ">=": true, - "instanceof": true, - "&": true, - "^": true, - "|": true, - "==": true, - "!=": true, - "===": true, - "!==": true, - ",": true, - - "}": true - }; - - /** - * Determines if we think that the given token starts an array literal. - * - * @param Object token - * The token we want to determine if it is an array literal. - * @param Object lastToken - * The last token we added to the pretty printed results. - * - * @returns Boolean - * True if we believe it is an array literal, false otherwise. - */ - function isArrayLiteral(token, lastToken) { - if (token.type.type != "[") { - return false; - } - if (!lastToken) { - return true; - } - if (lastToken.type.isAssign) { - return true; - } - return !!PRE_ARRAY_LITERAL_TOKENS[lastToken.type.keyword || lastToken.type.type]; - } - - // If any of these tokens are followed by a token on a new line, we know that - // ASI cannot happen. - var PREVENT_ASI_AFTER_TOKENS = { - // Binary operators - "*": true, - "/": true, - "%": true, - "+": true, - "-": true, - "<<": true, - ">>": true, - ">>>": true, - "<": true, - ">": true, - "<=": true, - ">=": true, - "instanceof": true, - "in": true, - "==": true, - "!=": true, - "===": true, - "!==": true, - "&": true, - "^": true, - "|": true, - "&&": true, - "||": true, - ",": true, - ".": true, - "=": true, - "*=": true, - "/=": true, - "%=": true, - "+=": true, - "-=": true, - "<<=": true, - ">>=": true, - ">>>=": true, - "&=": true, - "^=": true, - "|=": true, - // Unary operators - "delete": true, - "void": true, - "typeof": true, - "~": true, - "!": true, - "new": true, - // Function calls and grouped expressions - "(": true - }; - - // If any of these tokens are on a line after the token before it, we know - // that ASI cannot happen. - var PREVENT_ASI_BEFORE_TOKENS = { - // Binary operators - "*": true, - "/": true, - "%": true, - "<<": true, - ">>": true, - ">>>": true, - "<": true, - ">": true, - "<=": true, - ">=": true, - "instanceof": true, - "in": true, - "==": true, - "!=": true, - "===": true, - "!==": true, - "&": true, - "^": true, - "|": true, - "&&": true, - "||": true, - ",": true, - ".": true, - "=": true, - "*=": true, - "/=": true, - "%=": true, - "+=": true, - "-=": true, - "<<=": true, - ">>=": true, - ">>>=": true, - "&=": true, - "^=": true, - "|=": true, - // Function calls - "(": true - }; - - /** - * Determines if Automatic Semicolon Insertion (ASI) occurs between these - * tokens. - * - * @param Object token - * The token we want to determine if it is an array literal. - * @param Object lastToken - * The last token we added to the pretty printed results. - * - * @returns Boolean - * True if we believe ASI occurs. - */ - function isASI(token, lastToken) { - if (!lastToken) { - return false; - } - if (token.startLoc.line === lastToken.startLoc.line) { - return false; - } - if (PREVENT_ASI_AFTER_TOKENS[lastToken.type.type || lastToken.type.keyword]) { - return false; - } - if (PREVENT_ASI_BEFORE_TOKENS[token.type.type || token.type.keyword]) { - return false; - } - return true; - } - - /** - * Determine if we should add a newline after the given token. - * - * @param Object token - * The token we are looking at. - * @param Array stack - * The stack of open parens/curlies/brackets/etc. - * - * @returns Boolean - * True if we should add a newline. - */ - function isLineDelimiter(token, stack) { - if (token.isArrayLiteral) { - return true; - } - var ttt = token.type.type; - var top = stack[stack.length - 1]; - return ttt == ";" && top != "(" - || ttt == "{" - || ttt == "," && top != "(" - || ttt == ":" && (top == "case" || top == "default"); - } - - /** - * Append the necessary whitespace to the result after we have added the given - * token. - * - * @param Object token - * The token that was just added to the result. - * @param Function write - * The function to write to the pretty printed results. - * @param Array stack - * The stack of open parens/curlies/brackets/etc. - * - * @returns Boolean - * Returns true if we added a newline to result, false in all other - * cases. - */ - function appendNewline(token, write, stack) { - if (isLineDelimiter(token, stack)) { - write("\n", token.startLoc.line, token.startLoc.column); - return true; - } - return false; - } - - /** - * Determines if we need to add a space between the last token we added and - * the token we are about to add. - * - * @param Object token - * The token we are about to add to the pretty printed code. - * @param Object lastToken - * The last token added to the pretty printed code. - */ - function needsSpaceAfter(token, lastToken) { - if (lastToken) { - if (lastToken.type.isLoop) { - return true; - } - if (lastToken.type.isAssign) { - return true; - } - if (lastToken.type.binop != null) { - return true; - } - - var ltt = lastToken.type.type; - if (ltt == "?") { - return true; - } - if (ltt == ":") { - return true; - } - if (ltt == ",") { - return true; - } - if (ltt == ";") { - return true; - } - - var ltk = lastToken.type.keyword; - if (ltk != null - && ltk != "debugger" - && ltk != "null" - && ltk != "true" - && ltk != "false" - && ltk != "this" - && ltk != "break" - && ltk != "continue" - && ltk != "default") { - return true; - } - - if (ltt == ")" && (token.type.type != ")" - && token.type.type != "]" - && token.type.type != ";" - && token.type.type != ",")) { - return true; - } - } - - if (token.type.isAssign) { - return true; - } - if (token.type.binop != null) { - return true; - } - if (token.type.type == "?") { - return true; - } - - return false; - } - - /** - * Add the required whitespace before this token, whether that is a single - * space, newline, and/or the indent on fresh lines. - * - * @param Object token - * The token we are about to add to the pretty printed code. - * @param Object lastToken - * The last token we added to the pretty printed code. - * @param Boolean addedNewline - * Whether we added a newline after adding the last token to the pretty - * printed code. - * @param Function write - * The function to write pretty printed code to the result SourceNode. - * @param Object options - * The options object. - * @param Number indentLevel - * The number of indents deep we are. - * @param Array stack - * The stack of open curlies, brackets, etc. - */ - function prependWhiteSpace(token, lastToken, addedNewline, write, options, - indentLevel, stack) { - var ttk = token.type.keyword; - var ttt = token.type.type; - var newlineAdded = addedNewline; - - // Handle whitespace and newlines after "}" here instead of in - // `isLineDelimiter` because it is only a line delimiter some of the - // time. For example, we don't want to put "else if" on a new line after - // the first if's block. - if (lastToken && lastToken.type.type == "}") { - if (ttk == "while" && stack[stack.length - 1] == "do") { - write(" ", - lastToken.startLoc.line, - lastToken.startLoc.column); - } else if (ttk == "else" || - ttk == "catch" || - ttk == "finally") { - write(" ", - lastToken.startLoc.line, - lastToken.startLoc.column); - } else if (ttt != "(" && - ttt != ";" && - ttt != "," && - ttt != ")" && - ttt != ".") { - write("\n", - lastToken.startLoc.line, - lastToken.startLoc.column); - newlineAdded = true; - } - } - - if (ttt == ":" && stack[stack.length - 1] == "?") { - write(" ", - lastToken.startLoc.line, - lastToken.startLoc.column); - } - - if (lastToken && lastToken.type.type != "}" && ttk == "else") { - write(" ", - lastToken.startLoc.line, - lastToken.startLoc.column); - } - - function ensureNewline() { - if (!newlineAdded) { - write("\n", - lastToken.startLoc.line, - lastToken.startLoc.column); - newlineAdded = true; - } - } - - if (isASI(token, lastToken)) { - ensureNewline(); - } - - if (decrementsIndent(ttt, stack)) { - ensureNewline(); - } - - if (newlineAdded) { - if (ttk == "case" || ttk == "default") { - write(repeat(options.indent, indentLevel - 1), - token.startLoc.line, - token.startLoc.column); - } else { - write(repeat(options.indent, indentLevel), - token.startLoc.line, - token.startLoc.column); - } - } else if (needsSpaceAfter(token, lastToken)) { - write(" ", - lastToken.startLoc.line, - lastToken.startLoc.column); - } - } - - /** - * Repeat the `str` string `n` times. - * - * @param String str - * The string to be repeated. - * @param Number n - * The number of times to repeat the string. - * - * @returns String - * The repeated string. - */ - function repeat(str, n) { - var result = ""; - while (n > 0) { - if (n & 1) { - result += str; - } - n >>= 1; - str += str; - } - return result; - } - - /** - * Make sure that we put "\n" into the output instead of actual newlines. - */ - function sanitizeNewlines(str) { - return str.replace(/\n/g, "\\n"); - } - - /** - * Add the given token to the pretty printed results. - * - * @param Object token - * The token to add. - * @param Function write - * The function to write pretty printed code to the result SourceNode. - * @param Object options - * The options object. - */ - function addToken(token, write, options) { - if (token.type.type == "string") { - write("'" + sanitizeNewlines(token.value) + "'", - token.startLoc.line, - token.startLoc.column); - } else { - write(String(token.value != null ? token.value : token.type.type), - token.startLoc.line, - token.startLoc.column); - } - } - - /** - * Returns true if the given token type belongs on the stack. - */ - function belongsOnStack(token) { - var ttt = token.type.type; - var ttk = token.type.keyword; - return ttt == "{" - || ttt == "(" - || ttt == "[" - || ttt == "?" - || ttk == "do" - || ttk == "case" - || ttk == "default"; - } - - /** - * Returns true if the given token should cause us to pop the stack. - */ - function shouldStackPop(token, stack) { - var ttt = token.type.type; - var ttk = token.type.keyword; - var top = stack[stack.length - 1]; - return ttt == "]" - || ttt == ")" - || ttt == "}" - || (ttt == ":" && (top == "case" || top == "default" || top == "?")) - || (ttk == "while" && top == "do"); - } - - /** - * Returns true if the given token type should cause us to decrement the - * indent level. - */ - function decrementsIndent(tokenType, stack) { - return tokenType == "}" - || (tokenType == "]" && stack[stack.length - 1] == "[\n") - } - - /** - * Returns true if the given token should cause us to increment the indent - * level. - */ - function incrementsIndent(token) { - return token.type.type == "{" || token.isArrayLiteral; - } - - /** - * Add a comment to the pretty printed code. - * - * @param Function write - * The function to write pretty printed code to the result SourceNode. - * @param Number indentLevel - * The number of indents deep we are. - * @param Object options - * The options object. - * @param Boolean block - * True if the comment is a multiline block style comment. - * @param String text - * The text of the comment. - * @param Number line - * The line number to comment appeared on. - * @param Number column - * The column number the comment appeared on. - */ - function addComment(write, indentLevel, options, block, text, line, column) { - var indentString = repeat(options.indent, indentLevel); - - write(indentString, line, column); - if (block) { - write("/*"); - write(text - .split(new RegExp("/\n" + indentString + "/", "g")) - .join("\n" + indentString)); - write("*/"); - } else { - write("//"); - write(text); - } - write("\n"); - } - - /** - * The main function. - * - * @param String input - * The ugly JS code we want to pretty print. - * @param Object options - * The options object. Provides configurability of the pretty - * printing. Properties: - * - url: The URL string of the ugly JS code. - * - indent: The string to indent code by. - * - * @returns Object - * An object with the following properties: - * - code: The pretty printed code string. - * - map: A SourceMapGenerator instance. - */ - return function prettyFast(input, options) { - // The level of indents deep we are. - var indentLevel = 0; - - // We will accumulate the pretty printed code in this SourceNode. - var result = new SourceNode(); - - /** - * Write a pretty printed string to the result SourceNode. - * - * We buffer our writes so that we only create one mapping for each line in - * the source map. This enhances performance by avoiding extraneous mapping - * serialization, and flattening the tree that - * `SourceNode#toStringWithSourceMap` will have to recursively walk. When - * timing how long it takes to pretty print jQuery, this optimization - * brought the time down from ~390 ms to ~190ms! - * - * @param String str - * The string to be added to the result. - * @param Number line - * The line number the string came from in the ugly source. - * @param Number column - * The column number the string came from in the ugly source. - */ - var write = (function () { - var buffer = []; - var bufferLine = -1; - var bufferColumn = -1; - return function write(str, line, column) { - if (line != null && bufferLine === -1) { - bufferLine = line; - } - if (column != null && bufferColumn === -1) { - bufferColumn = column; - } - buffer.push(str); - - if (str == "\n") { - var lineStr = ""; - for (var i = 0, len = buffer.length; i < len; i++) { - lineStr += buffer[i]; - } - result.add(new SourceNode(bufferLine, bufferColumn, options.url, lineStr)); - buffer.splice(0, buffer.length); - bufferLine = -1; - bufferColumn = -1; - } - } - }()); - - // Whether or not we added a newline on after we added the last token. - var addedNewline = false; - - // The current token we will be adding to the pretty printed code. - var token; - - // Shorthand for token.type.type, so we don't have to repeatedly access - // properties. - var ttt; - - // Shorthand for token.type.keyword, so we don't have to repeatedly access - // properties. - var ttk; - - // The last token we added to the pretty printed code. - var lastToken; - - // Stack of token types/keywords that can affect whether we want to add a - // newline or a space. We can make that decision based on what token type is - // on the top of the stack. For example, a comma in a parameter list should - // be followed by a space, while a comma in an object literal should be - // followed by a newline. - // - // Strings that go on the stack: - // - // - "{" - // - "(" - // - "[" - // - "[\n" - // - "do" - // - "?" - // - "case" - // - "default" - // - // The difference between "[" and "[\n" is that "[\n" is used when we are - // treating "[" and "]" tokens as line delimiters and should increment and - // decrement the indent level when we find them. - var stack = []; - - // Acorn's tokenizer will always yield comments *before* the token they - // follow (unless the very first thing in the source is a comment), so we - // have to queue the comments in order to pretty print them in the correct - // location. For example, the source file: - // - // foo - // // a - // // b - // bar - // - // When tokenized by acorn, gives us the following token stream: - // - // [ '// a', '// b', foo, bar ] - var commentQueue = []; - - var getToken = acorn.tokenize(input, { - locations: true, - sourceFile: options.url, - onComment: function (block, text, start, end, startLoc, endLoc) { - if (lastToken) { - commentQueue.push({ - block: block, - text: text, - line: startLoc.line, - column: startLoc.column - }); - } else { - addComment(write, indentLevel, options, block, text, startLoc.line, - startLoc.column); - addedNewline = true; - } - } - }); - - while (true) { - token = getToken(); - - ttk = token.type.keyword; - ttt = token.type.type; - - if (ttt == "eof") { - if (!addedNewline) { - write("\n"); - } - break; - } - - token.isArrayLiteral = isArrayLiteral(token, lastToken); - - if (belongsOnStack(token)) { - if (token.isArrayLiteral) { - stack.push("[\n"); - } else { - stack.push(ttt || ttk); - } - } - - if (decrementsIndent(ttt, stack)) { - indentLevel--; - } - - prependWhiteSpace(token, lastToken, addedNewline, write, options, - indentLevel, stack); - addToken(token, write, options); - addedNewline = appendNewline(token, write, stack); - - if (shouldStackPop(token, stack)) { - stack.pop(); - } - - if (incrementsIndent(token)) { - indentLevel++; - } - - // Acorn's tokenizer re-uses tokens, so we have to copy the last token on - // every iteration. We follow acorn's lead here, and reuse the lastToken - // object the same way that acorn reuses the token object. This allows us - // to avoid allocations and minimize GC pauses. - if (!lastToken) { - lastToken = { startLoc: {}, endLoc: {} }; - } - lastToken.start = token.start; - lastToken.end = token.end; - lastToken.startLoc.line = token.startLoc.line; - lastToken.startLoc.column = token.startLoc.column; - lastToken.endLoc.line = token.endLoc.line; - lastToken.endLoc.column = token.endLoc.column; - lastToken.type = token.type; - lastToken.value = token.value; - lastToken.isArrayLiteral = token.isArrayLiteral; - - // Apply all the comments that have been queued up. - if (commentQueue.length) { - if (!addedNewline) { - write("\n"); - } - for (var i = 0, n = commentQueue.length; i < n; i++) { - var comment = commentQueue[i]; - addComment(write, indentLevel, options, comment.block, comment.text, - comment.line, comment.column); - } - addedNewline = true; - commentQueue.splice(0, commentQueue.length); - } - } - - return result.toStringWithSourceMap({ file: options.url }); - }; - -}.bind(this))); diff --git a/toolkit/devtools/pretty-fast/tests/unit/test.js b/toolkit/devtools/pretty-fast/tests/unit/test.js deleted file mode 100644 index bada192e487..00000000000 --- a/toolkit/devtools/pretty-fast/tests/unit/test.js +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2013 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.md or: - * http://opensource.org/licenses/BSD-2-Clause - */ -var prettyFast = this.prettyFast || require("./pretty-fast"); - -var testCases = [ - { - name: "Simple function", - input: "function foo() { bar(); }", - output: "function foo() {\n" + - " bar();\n" + - "}\n", - mappings: [ - // function foo() { - { - inputLine: 1, - outputLine: 1 - }, - // bar(); - { - inputLine: 1, - outputLine: 2 - }, - // } - { - inputLine: 1, - outputLine: 3 - }, - ] - }, - - { - name: "Nested function", - input: "function foo() { function bar() { debugger; } bar(); }", - output: "function foo() {\n" + - " function bar() {\n" + - " debugger;\n" + - " }\n" + - " bar();\n" + - "}\n", - mappings: [ - // function bar() { - { - inputLine: 1, - outputLine: 2 - }, - // debugger; - { - inputLine: 1, - outputLine: 3 - }, - // bar(); - { - inputLine: 1, - outputLine: 5 - }, - ] - }, - - { - name: "Immediately invoked function expression", - input: "(function(){thingy()}())", - output: "(function () {\n" + - " thingy()\n" + - "}())\n" - }, - - { - name: "Single line comment", - input: "// Comment\n" + - "function foo() { bar(); }\n", - output: "// Comment\n" + - "function foo() {\n" + - " bar();\n" + - "}\n", - mappings: [ - // // Comment - { - inputLine: 1, - outputLine: 1 - } - ] - }, - - { - name: "Multi line comment", - input: "/* Comment\n" + - "more comment */\n" + - "function foo() { bar(); }\n", - output: "/* Comment\n" + - "more comment */\n" + - "function foo() {\n" + - " bar();\n" + - "}\n", - mappings: [ - // /* Comment - { - inputLine: 1, - outputLine: 1 - }, - // \nmore comment */ - { - inputLine: 1, - outputLine: 2 - } - ] - }, - - { - name: "Null assignment", - input: "var i=null;\n", - output: "var i = null;\n", - mappings: [ - { - inputLine: 1, - outputLine: 1 - } - ] - }, - - { - name: "Undefined assignment", - input: "var i=undefined;\n", - output: "var i = undefined;\n" - }, - - { - name: "Void 0 assignment", - input: "var i=void 0;\n", - output: "var i = void 0;\n" - }, - - { - name: "This property access", - input: "var foo=this.foo;\n", - output: "var foo = this.foo;\n" - }, - - { - name: "True assignment", - input: "var foo=true;\n", - output: "var foo = true;\n" - }, - - { - name: "False assignment", - input: "var foo=false;\n", - output: "var foo = false;\n" - }, - - { - name: "For loop", - input: "for (var i = 0; i < n; i++) { console.log(i); }", - output: "for (var i = 0; i < n; i++) {\n" + - " console.log(i);\n" + - "}\n", - mappings: [ - // for (var i = 0; i < n; i++) { - { - inputLine: 1, - outputLine: 1 - }, - // console.log(i); - { - inputLine: 1, - outputLine: 2 - }, - ] - }, - - { - name: "String with semicolon", - input: "var foo = ';';\n", - output: "var foo = ';';\n" - }, - - { - name: "String with quote", - input: "var foo = \"'\";\n", - output: "var foo = '\'';\n" - }, - - { - name: "Function calls", - input: "var result=func(a,b,c,d);", - output: "var result = func(a, b, c, d);\n" - }, - - { - name: "Regexp", - input: "var r=/foobar/g;", - output: "var r = /foobar/g;\n" - }, - - { - name: "In operator", - input: "if(foo in bar){doThing()}", - output: "if (foo in bar) {\n" + - " doThing()\n" + - "}\n" - }, - - { - name: "With statement", - input: "with(obj){crock()}", - output: "with (obj) {\n" + - " crock()\n" + - "}\n" - }, - - { - name: "New expression", - input: "var foo=new Foo();", - output: "var foo = new Foo();\n" - }, - - { - name: "Continue/break statements", - input: "while(1){if(x){continue}if(y){break}}", - output: "while (1) {\n" + - " if (x) {\n" + - " continue\n" + - " }\n" + - " if (y) {\n" + - " break\n" + - " }\n" + - "}\n" - }, - - { - name: "Instanceof", - input: "var a=x instanceof y;", - output: "var a = x instanceof y;\n" - }, - - { - name: "Binary operators", - input: "var a=5*30;var b=5>>3;", - output: "var a = 5 * 30;\n" + - "var b = 5 >> 3;\n" - }, - - { - name: "Delete", - input: "delete obj.prop;", - output: "delete obj.prop;\n" - }, - - { - name: "Try/catch/finally statement", - input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}", - output: "try {\n" + - " dangerous()\n" + - "} catch (e) {\n" + - " handle(e)\n" + - "} finally {\n" + - " cleanup()\n" + - "}\n" - }, - - { - name: "If/else statement", - input: "if(c){then()}else{other()}", - output: "if (c) {\n" + - " then()\n" + - "} else {\n" + - " other()\n" + - "}\n" - }, - - { - name: "If/else without curlies", - input: "if(c) a else b", - output: "if (c) a else b\n" - }, - - { - name: "Objects", - input: "var o={a:1,\n" + - " b:2};", - output: "var o = {\n" + - " a: 1,\n" + - " b: 2\n" + - "};\n", - mappings: [ - // a: 1, - { - inputLine: 1, - outputLine: 2 - }, - // b: 2 - { - inputLine: 2, - outputLine: 3 - }, - ] - }, - - { - name: "Do/while loop", - input: "do{x}while(y)", - output: "do {\n" + - " x\n" + - "} while (y)\n" - }, - - { - name: "Arrays", - input: "var a=[1,2,3];", - output: "var a = [\n" + - " 1,\n" + - " 2,\n" + - " 3\n" + - "];\n" - }, - - { - name: "Code that relies on ASI", - input: "var foo = 10\n" + - "var bar = 20\n" + - "function g() {\n" + - " a()\n" + - " b()\n" + - "}", - output: "var foo = 10\n" + - "var bar = 20\n" + - "function g() {\n" + - " a()\n" + - " b()\n" + - "}\n" - }, - - { - name: "Ternary operator", - input: "bar?baz:bang;", - output: "bar ? baz : bang;\n" - }, - - { - name: "Switch statements", - input: "switch(x){case a:foo();break;default:bar()}", - output: "switch (x) {\n" + - "case a:\n" + - " foo();\n" + - " break;\n" + - "default:\n" + - " bar()\n" + - "}\n" - }, - - { - name: "Multiple single line comments", - input: "function f() {\n" + - " // a\n" + - " // b\n" + - " // c\n" + - "}\n", - output: "function f() {\n" + - " // a\n" + - " // b\n" + - " // c\n" + - "}\n", - }, - - { - name: "Indented multiline comment", - input: "function foo() {\n" + - " /**\n" + - " * java doc style comment\n" + - " * more comment\n" + - " */\n" + - " bar();\n" + - "}\n", - output: "function foo() {\n" + - " /**\n" + - " * java doc style comment\n" + - " * more comment\n" + - " */\n" + - " bar();\n" + - "}\n", - }, - - { - name: "ASI return", - input: "function f() {\n" + - " return\n" + - " {}\n" + - "}\n", - output: "function f() {\n" + - " return\n" + - " {\n" + - " }\n" + - "}\n", - }, - - { - name: "Non-ASI property access", - input: "[1,2,3]\n" + - "[0]", - output: "[\n" + - " 1,\n" + - " 2,\n" + - " 3\n" + - "]\n" + - "[0]\n" - }, - - { - name: "Non-ASI in", - input: "'x'\n" + - "in foo", - output: "'x' in foo\n" - }, - - { - name: "Non-ASI function call", - input: "f\n" + - "()", - output: "f()\n" - }, - - { - name: "Non-ASI new", - input: "new\n" + - "F()", - output: "new F()\n" - }, - -]; - -var sourceMap = this.sourceMap || require("source-map"); - -function run_test() { - testCases.forEach(function (test) { - console.log(test.name); - - var actual = prettyFast(test.input, { - indent: " ", - url: "test.js" - }); - - if (actual.code !== test.output) { - throw new Error("Expected:\n" + test.output - + "\nGot:\n" + actual.code); - } - - if (test.mappings) { - var smc = new sourceMap.SourceMapConsumer(actual.map.toJSON()); - test.mappings.forEach(function (m) { - var query = { line: m.outputLine, column: 0 }; - var original = smc.originalPositionFor(query); - if (original.line != m.inputLine) { - throw new Error("Querying:\n" + JSON.stringify(query, null, 2) + "\n" - + "Expected line:\n" + m.inputLine + "\n" - + "Got:\n" + JSON.stringify(original, null, 2)); - } - }); - } - }); - console.log("✓ All tests pass!"); -} - -// Only run the tests if this is node and we are running this file -// directly. (Firefox's test runner will import this test file, and then call -// run_test itself.) -if (typeof exports == "object") { - run_test(); -} diff --git a/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini b/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini deleted file mode 100644 index 94833e29289..00000000000 --- a/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -head = head_pretty-fast.js -tail = - -[test.js] diff --git a/toolkit/devtools/server/actors/pretty-print-worker.js b/toolkit/devtools/server/actors/pretty-print-worker.js index 07fad4eaafe..404b24390a8 100644 --- a/toolkit/devtools/server/actors/pretty-print-worker.js +++ b/toolkit/devtools/server/actors/pretty-print-worker.js @@ -8,11 +8,11 @@ * This file is meant to be loaded as a ChromeWorker. It accepts messages which * have data of the form: * - * { id, url, indent, source } + * { id, url, indent, ast } * * Where `id` is a unique ID to identify this request, `url` is the url of the * source being pretty printed, `indent` is the number of spaces to indent the - * code by, and `source` is the source text. + * code by, and `ast` is the source's abstract syntax tree. * * On success, the worker responds with a message of the form: * @@ -20,23 +20,25 @@ * * Where `id` is the same unique ID from the request, `code` is the pretty * printed source text, and `mappings` is an array or source mappings from the - * pretty printed code back to the ugly source text. + * pretty printed code to the AST's source locations. * * In the case of an error, the worker responds with a message of the form: * - * { id, error } + * { error } */ -importScripts("resource://gre/modules/devtools/acorn.js"); -importScripts("resource://gre/modules/devtools/source-map.js"); -importScripts("resource://gre/modules/devtools/pretty-fast.js"); +importScripts("resource://gre/modules/devtools/escodegen/escodegen.worker.js"); -self.onmessage = (event) => { - const { data: { id, url, indent, source } } = event; +self.onmessage = ({ data: { id, url, indent, ast } }) => { try { - const prettified = prettyFast(source, { - url: url, - indent: " ".repeat(indent) + const prettified = escodegen.generate(ast, { + format: { + indent: { + style: " ".repeat(indent) + } + }, + sourceMap: url, + sourceMapWithCode: true }); self.postMessage({ @@ -46,7 +48,6 @@ self.onmessage = (event) => { }); } catch (e) { self.postMessage({ - id: id, error: e.message + "\n" + e.stack }); } diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index 715c9d52713..f11ceb4870b 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -497,8 +497,8 @@ ThreadActor.prototype = { return this._prettyPrintWorker; }, - _onPrettyPrintError: function ({ message, filename, lineno }) { - reportError(new Error(message + " @ " + filename + ":" + lineno)); + _onPrettyPrintError: function (error) { + reportError(new Error(error)); }, _onPrettyPrintMsg: function ({ data }) { @@ -2459,6 +2459,7 @@ SourceActor.prototype = { onPrettyPrint: function ({ indent }) { this.threadActor.sources.prettyPrint(this._url, indent); return this._getSourceText() + .then(this._parseAST) .then(this._sendToPrettyPrintWorker(indent)) .then(this._invertSourceMap) .then(this._saveMap) @@ -2479,6 +2480,13 @@ SourceActor.prototype = { }); }, + /** + * Parse the source content into an AST. + */ + _parseAST: function SA__parseAST({ content}) { + return Reflect.parse(content); + }, + /** * Return a function that sends a request to the pretty print worker, waits on * the worker's response, and then returns the pretty printed code. @@ -2492,7 +2500,7 @@ SourceActor.prototype = { * printed code, and `mappings` is an array of source mappings. */ _sendToPrettyPrintWorker: function SA__sendToPrettyPrintWorker(aIndent) { - return ({ content }) => { + return aAST => { const deferred = promise.defer(); const id = Math.random(); @@ -2514,7 +2522,7 @@ SourceActor.prototype = { id: id, url: this._url, indent: aIndent, - source: content + ast: aAST }); return deferred.promise; diff --git a/toolkit/devtools/server/main.js b/toolkit/devtools/server/main.js index a221682c3b8..dad9ea1106a 100644 --- a/toolkit/devtools/server/main.js +++ b/toolkit/devtools/server/main.js @@ -74,6 +74,7 @@ loadSubScript.call(this, "resource://gre/modules/commonjs/sdk/core/promise.js"); this.require = loaderRequire; Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); +const escodegen = localRequire("escodegen/escodegen"); loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js"); diff --git a/toolkit/devtools/sourcemap/Makefile.in b/toolkit/devtools/sourcemap/Makefile.in index aa6749658d5..aad3588f054 100644 --- a/toolkit/devtools/sourcemap/Makefile.in +++ b/toolkit/devtools/sourcemap/Makefile.in @@ -7,4 +7,3 @@ include $(topsrcdir)/config/rules.mk libs:: $(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools - $(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools diff --git a/toolkit/devtools/sourcemap/source-map.js b/toolkit/devtools/sourcemap/source-map.js deleted file mode 100644 index 57fe57f02f3..00000000000 --- a/toolkit/devtools/sourcemap/source-map.js +++ /dev/null @@ -1,1929 +0,0 @@ -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -/** - * Define a module along with a payload. - * @param {string} moduleName Name for the payload - * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec - * @param {function} payload Function with (require, exports, module) params - */ -function define(moduleName, deps, payload) { - if (typeof moduleName != "string") { - throw new TypeError('Expected string, got: ' + moduleName); - } - - if (arguments.length == 2) { - payload = deps; - } - - if (moduleName in define.modules) { - throw new Error("Module already defined: " + moduleName); - } - define.modules[moduleName] = payload; -}; - -/** - * The global store of un-instantiated modules - */ -define.modules = {}; - - -/** - * We invoke require() in the context of a Domain so we can have multiple - * sets of modules running separate from each other. - * This contrasts with JSMs which are singletons, Domains allows us to - * optionally load a CommonJS module twice with separate data each time. - * Perhaps you want 2 command lines with a different set of commands in each, - * for example. - */ -function Domain() { - this.modules = {}; - this._currentModule = null; -} - -(function () { - - /** - * Lookup module names and resolve them by calling the definition function if - * needed. - * There are 2 ways to call this, either with an array of dependencies and a - * callback to call when the dependencies are found (which can happen - * asynchronously in an in-page context) or with a single string an no callback - * where the dependency is resolved synchronously and returned. - * The API is designed to be compatible with the CommonJS AMD spec and - * RequireJS. - * @param {string[]|string} deps A name, or names for the payload - * @param {function|undefined} callback Function to call when the dependencies - * are resolved - * @return {undefined|object} The module required or undefined for - * array/callback method - */ - Domain.prototype.require = function(deps, callback) { - if (Array.isArray(deps)) { - var params = deps.map(function(dep) { - return this.lookup(dep); - }, this); - if (callback) { - callback.apply(null, params); - } - return undefined; - } - else { - return this.lookup(deps); - } - }; - - function normalize(path) { - var bits = path.split('/'); - var i = 1; - while (i < bits.length) { - if (bits[i] === '..') { - bits.splice(i-1, 1); - } else if (bits[i] === '.') { - bits.splice(i, 1); - } else { - i++; - } - } - return bits.join('/'); - } - - function join(a, b) { - a = a.trim(); - b = b.trim(); - if (/^\//.test(b)) { - return b; - } else { - return a.replace(/\/*$/, '/') + b; - } - } - - function dirname(path) { - var bits = path.split('/'); - bits.pop(); - return bits.join('/'); - } - - /** - * Lookup module names and resolve them by calling the definition function if - * needed. - * @param {string} moduleName A name for the payload to lookup - * @return {object} The module specified by aModuleName or null if not found. - */ - Domain.prototype.lookup = function(moduleName) { - if (/^\./.test(moduleName)) { - moduleName = normalize(join(dirname(this._currentModule), moduleName)); - } - - if (moduleName in this.modules) { - var module = this.modules[moduleName]; - return module; - } - - if (!(moduleName in define.modules)) { - throw new Error("Module not defined: " + moduleName); - } - - var module = define.modules[moduleName]; - - if (typeof module == "function") { - var exports = {}; - var previousModule = this._currentModule; - this._currentModule = moduleName; - module(this.require.bind(this), exports, { id: moduleName, uri: "" }); - this._currentModule = previousModule; - module = exports; - } - - // cache the resulting module object for next time - this.modules[moduleName] = module; - - return module; - }; - -}()); - -define.Domain = Domain; -define.globalDomain = new Domain(); -var require = define.globalDomain.require.bind(define.globalDomain); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-map-generator', ['require', 'exports', 'module' , 'source-map/base64-vlq', 'source-map/util', 'source-map/array-set'], function(require, exports, module) { - - var base64VLQ = require('./base64-vlq'); - var util = require('./util'); - var ArraySet = require('./array-set').ArraySet; - - /** - * An instance of the SourceMapGenerator represents a source map which is - * being built incrementally. To create a new one, you must pass an object - * with the following properties: - * - * - file: The filename of the generated source. - * - sourceRoot: An optional root for all URLs in this source map. - */ - function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._sources = new ArraySet(); - this._names = new ArraySet(); - this._mappings = []; - this._sourcesContents = null; - } - - SourceMapGenerator.prototype._version = 3; - - /** - * Creates a new SourceMapGenerator based on a SourceMapConsumer - * - * @param aSourceMapConsumer The SourceMap. - */ - SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - - if (mapping.source) { - newMapping.source = mapping.source; - if (sourceRoot) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - - if (mapping.name) { - newMapping.name = mapping.name; - } - } - - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - - /** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. - */ - SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - - this._validateMapping(generated, original, source, name); - - if (source && !this._sources.has(source)) { - this._sources.add(source); - } - - if (name && !this._names.has(name)) { - this._names.add(name); - } - - this._mappings.push({ - generatedLine: generated.line, - generatedColumn: generated.column, - originalLine: original != null && original.line, - originalColumn: original != null && original.column, - source: source, - name: name - }); - }; - - /** - * Set the source content for a source file. - */ - SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot) { - source = util.relative(this._sourceRoot, source); - } - - if (aSourceContent !== null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = {}; - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - - /** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - */ - SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (!aSourceFile) { - aSourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "aSourceFile" relative if an absolute Url is passed. - if (sourceRoot) { - aSourceFile = util.relative(sourceRoot, aSourceFile); - } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); - - // Find mappings for the "aSourceFile" - this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.originalLine) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.originalLine, - column: mapping.originalColumn - }); - if (original.source !== null) { - // Copy mapping - if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; - } - 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 - mapping.name = original.name; - } - } - } - - var source = mapping.source; - if (source && !newSources.has(source)) { - newSources.add(source); - } - - var name = mapping.name; - if (name && !newNames.has(name)) { - newNames.add(name); - } - - }, this); - this._sources = newSources; - this._names = newNames; - - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - if (sourceRoot) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - - /** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. - * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. - */ - SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aGenerated.line > 0 && aGenerated.column >= 0 - && !aOriginal && !aSource && !aName) { - // Case 1. - return; - } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal - && aGenerated.line > 0 && aGenerated.column >= 0 - && aOriginal.line > 0 && aOriginal.column >= 0 - && aSource) { - // Cases 2 and 3. - return; - } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ - generated: aGenerated, - source: aSource, - orginal: aOriginal, - name: aName - })); - } - }; - - /** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. - */ - SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var mapping; - - // The mappings must be guaranteed to be in sorted order before we start - // serializing them or else the generated line numbers (which are defined - // via the ';' separators) will be all messed up. Note: it might be more - // performant to maintain the sorting as we insert them, rather than as we - // serialize them, but the big O is the same either way. - this._mappings.sort(util.compareByGeneratedPositions); - - for (var i = 0, len = this._mappings.length; i < len; i++) { - mapping = this._mappings[i]; - - if (mapping.generatedLine !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generatedLine !== previousGeneratedLine) { - result += ';'; - previousGeneratedLine++; - } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { - continue; - } - result += ','; - } - } - - result += base64VLQ.encode(mapping.generatedColumn - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generatedColumn; - - 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.originalLine - 1 - - previousOriginalLine); - previousOriginalLine = mapping.originalLine - 1; - - result += base64VLQ.encode(mapping.originalColumn - - previousOriginalColumn); - previousOriginalColumn = mapping.originalColumn; - - if (mapping.name) { - result += base64VLQ.encode(this._names.indexOf(mapping.name) - - previousName); - previousName = this._names.indexOf(mapping.name); - } - } - } - - 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. - */ - SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - file: this._file, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._sourceRoot) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); - } - - return map; - }; - - /** - * Render the source map being generated to a string. - */ - SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this); - }; - - exports.SourceMapGenerator = SourceMapGenerator; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - * - * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java - * - * Copyright 2011 The Closure Compiler Authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/base64'], function(require, exports, module) { - - var base64 = require('./base64'); - - // A single base 64 digit can contain 6 bits of data. For the base 64 variable - // length quantities we use in the source map spec, the first bit is the sign, - // the next four bits are the actual value, and the 6th bit is the - // continuation bit. The continuation bit tells us whether there are more - // digits in this value following this digit. - // - // Continuation - // | Sign - // | | - // V V - // 101011 - - var VLQ_BASE_SHIFT = 5; - - // binary: 100000 - var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - - // binary: 011111 - var VLQ_BASE_MASK = VLQ_BASE - 1; - - // binary: 100000 - var VLQ_CONTINUATION_BIT = VLQ_BASE; - - /** - * Converts from a two-complement value to a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) - */ - function toVLQSigned(aValue) { - return aValue < 0 - ? ((-aValue) << 1) + 1 - : (aValue << 1) + 0; - } - - /** - * Converts to a two-complement value from a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 - */ - function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative - ? -shifted - : shifted; - } - - /** - * Returns the base 64 VLQ encoded value. - */ - exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; - - var vlq = toVLQSigned(aValue); - - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - // There are still more digits in this value, so we must make sure the - // continuation bit is marked. - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - - return encoded; - }; - - /** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string. - */ - exports.decode = function base64VLQ_decode(aStr) { - var i = 0; - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - - do { - if (i >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); - } - digit = base64.decode(aStr.charAt(i++)); - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - return { - value: fromVLQSigned(result), - rest: aStr.slice(i) - }; - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/base64', ['require', 'exports', 'module' , ], function(require, exports, module) { - - var charToIntMap = {}; - var intToCharMap = {}; - - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - .split('') - .forEach(function (ch, index) { - charToIntMap[ch] = index; - intToCharMap[index] = ch; - }); - - /** - * Encode an integer in the range of 0 to 63 to a single base 64 digit. - */ - exports.encode = function base64_encode(aNumber) { - if (aNumber in intToCharMap) { - return intToCharMap[aNumber]; - } - throw new TypeError("Must be between 0 and 63: " + aNumber); - }; - - /** - * Decode a single base 64 digit to an integer. - */ - exports.decode = function base64_decode(aChar) { - if (aChar in charToIntMap) { - return charToIntMap[aChar]; - } - throw new TypeError("Not a valid base 64 digit: " + aChar); - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) { - - /** - * This is a helper function for getting values from parameter/options - * objects. - * - * @param args The object we are extracting values from - * @param name The name of the property we are getting. - * @param defaultValue An optional value to return if the property is missing - * from the object. If this is not specified and the property is missing, an - * error will be thrown. - */ - function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } - } - exports.getArg = getArg; - - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - var dataUrlRegexp = /^data:.+\,.+/; - - function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] - }; - } - exports.urlParse = urlParse; - - 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; - - if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { - return aPath; - } - - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); - } - - return aRoot.replace(/\/$/, '') + '/' + aPath; - } - exports.join = join; - - /** - * Because behavior goes wacky when you set `__proto__` on objects, we - * have to prefix all the strings in our set with an arbitrary character. - * - * See https://github.com/mozilla/source-map/pull/31 and - * https://github.com/mozilla/source-map/issues/30 - * - * @param String aStr - */ - function toSetString(aStr) { - return '$' + aStr; - } - exports.toSetString = toSetString; - - function fromSetString(aStr) { - return aStr.substr(1); - } - exports.fromSetString = fromSetString; - - function relative(aRoot, aPath) { - aRoot = aRoot.replace(/\/$/, ''); - - var url = urlParse(aRoot); - if (aPath.charAt(0) == "/" && url && url.path == "/") { - return aPath.slice(1); - } - - return aPath.indexOf(aRoot + '/') === 0 - ? aPath.substr(aRoot.length + 1) - : aPath; - } - exports.relative = relative; - - 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; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) { - - var util = require('./util'); - - /** - * A data structure which is a combination of an array and a set. Adding a new - * member is O(1), testing for membership is O(1), and finding the index of an - * element is O(1). Removing elements from the set is not supported. Only - * strings are supported for membership. - */ - function ArraySet() { - this._array = []; - this._set = {}; - } - - /** - * Static method for creating ArraySet instances from an existing array. - */ - ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); - } - return set; - }; - - /** - * Add the given string to this set. - * - * @param String aStr - */ - ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var isDuplicate = this.has(aStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - this._set[util.toSetString(aStr)] = idx; - } - }; - - /** - * Is the given string a member of this set? - * - * @param String aStr - */ - ArraySet.prototype.has = function ArraySet_has(aStr) { - return Object.prototype.hasOwnProperty.call(this._set, - util.toSetString(aStr)); - }; - - /** - * What is the index of the given string in the array? - * - * @param String aStr - */ - ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (this.has(aStr)) { - return this._set[util.toSetString(aStr)]; - } - throw new Error('"' + aStr + '" is not in the set.'); - }; - - /** - * What is the element at the given index? - * - * @param Number aIdx - */ - ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); - }; - - /** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ - ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); - }; - - exports.ArraySet = ArraySet; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'source-map/util', 'source-map/binary-search', 'source-map/array-set', 'source-map/base64-vlq'], function(require, exports, module) { - - var util = require('./util'); - var binarySearch = require('./binary-search'); - var ArraySet = require('./array-set').ArraySet; - var base64VLQ = require('./base64-vlq'); - - /** - * A SourceMapConsumer instance represents a parsed source map which we can - * query for information about the original file positions by giving it a file - * position in the generated source. - * - * The only parameter is the raw source map (either as a JSON string, or - * already parsed to an object). According to the spec, source maps have the - * following attributes: - * - * - version: Which version of the source map spec this map is following. - * - sources: An array of URLs to the original source files. - * - names: An array of identifiers which can be referrenced by individual mappings. - * - sourceRoot: Optional. The URL root from which all sources are relative. - * - sourcesContent: Optional. An array of contents of the original source files. - * - mappings: A string of base64 VLQs which contain the actual mappings. - * - file: The generated file this source map is associated with. - * - * Here is an example source map, taken from the source map spec[0]: - * - * { - * version : 3, - * file: "out.js", - * sourceRoot : "", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AA,AB;;ABCDE;" - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# - */ - function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - var names = util.getArg(sourceMap, 'names'); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - - if (version !== this._version) { - throw new Error('Unsupported version: ' + version); - } - - // 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._mappings = mappings; - this.file = file; - } - - /** - * 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. - */ - SourceMapConsumer.prototype._version = 3; - - /** - * The list of original sources. - */ - Object.defineProperty(SourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot ? util.join(this.sourceRoot, s) : s; - }, this); - } - }); - - // `__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 (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ - SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var mappingSeparator = /^[,;]/; - var str = aStr; - var mapping; - var temp; - - while (str.length > 0) { - if (str.charAt(0) === ';') { - generatedLine++; - str = str.slice(1); - previousGeneratedColumn = 0; - } - else if (str.charAt(0) === ',') { - str = str.slice(1); - } - else { - mapping = {}; - mapping.generatedLine = generatedLine; - - // Generated column. - temp = base64VLQ.decode(str); - mapping.generatedColumn = previousGeneratedColumn + temp.value; - previousGeneratedColumn = mapping.generatedColumn; - str = temp.rest; - - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original source. - temp = base64VLQ.decode(str); - mapping.source = this._sources.at(previousSource + temp.value); - previousSource += temp.value; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source, but no line and column'); - } - - // Original line. - temp = base64VLQ.decode(str); - mapping.originalLine = previousOriginalLine + temp.value; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source and line, but no column'); - } - - // Original column. - temp = base64VLQ.decode(str); - mapping.originalColumn = previousOriginalColumn + temp.value; - previousOriginalColumn = mapping.originalColumn; - str = temp.rest; - - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original name. - temp = base64VLQ.decode(str); - mapping.name = this._names.at(previousName + temp.value); - previousName += temp.value; - str = temp.rest; - } - } - - this.__generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - this.__originalMappings.push(mapping); - } - } - } - - this.__originalMappings.sort(util.compareByOriginalPositions); - }; - - /** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ - SourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, - aColumnName, aComparator) { - // To return the position we are searching for, we must first find the - // mapping for the given position and then return the opposite position it - // points to. Because the mappings are sorted, we can use binary search to - // find the best mapping. - - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); - } - - return binarySearch.search(aNeedle, aMappings, aComparator); - }; - - /** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ - SourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - var mapping = this._findMapping(needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositions); - - if (mapping) { - var source = util.getArg(mapping, 'source', null); - if (source && this.sourceRoot) { - source = util.join(this.sourceRoot, source); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: util.getArg(mapping, 'name', null) - }; - } - - return { - source: null, - line: null, - column: null, - name: null - }; - }; - - /** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * availible. - */ - SourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource) { - if (!this.sourcesContent) { - return null; - } - - if (this.sourceRoot) { - 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.'); - }; - - /** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ - SourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - - if (this.sourceRoot) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - - var mapping = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions); - - if (mapping) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null) - }; - } - - return { - line: null, - column: null - }; - }; - - SourceMapConsumer.GENERATED_ORDER = 1; - SourceMapConsumer.ORIGINAL_ORDER = 2; - - /** - * Iterate over each mapping between an original source/line/column and a - * generated line/column in this source map. - * - * @param Function aCallback - * The function that is called with each mapping. - * @param Object aContext - * Optional. If specified, this object will be the value of `this` every - * time that `aCallback` is called. - * @param aOrder - * Either `SourceMapConsumer.GENERATED_ORDER` or - * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to - * iterate over the mappings sorted by the generated file's line/column - * order or the original's source/line/column order, respectively. Defaults to - * `SourceMapConsumer.GENERATED_ORDER`. - */ - SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error("Unknown order of iteration."); - } - - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source; - if (source && sourceRoot) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name - }; - }).forEach(aCallback, context); - }; - - exports.SourceMapConsumer = SourceMapConsumer; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/binary-search', ['require', 'exports', 'module' , ], function(require, exports, module) { - - /** - * Recursive implementation of binary search. - * - * @param aLow Indices here and lower do not contain the needle. - * @param aHigh Indices here and higher do not contain the needle. - * @param aNeedle The element being searched for. - * @param aHaystack The non-empty array being searched. - * @param aCompare Function which takes two elements and returns -1, 0, or 1. - */ - function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { - // This function terminates when one of the following is true: - // - // 1. We find the exact element we are looking for. - // - // 2. We did not find the exact element, but we can return the next - // closest element that is less than that element. - // - // 3. We did not find the exact element, and there is no next-closest - // element which is less than the one we are searching for, so we - // return null. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); - if (cmp === 0) { - // Found the element we are looking for. - return aHaystack[mid]; - } - else if (cmp > 0) { - // aHaystack[mid] is greater than our needle. - if (aHigh - mid > 1) { - // The element is in the upper half. - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); - } - // We did not find an exact match, return the next closest one - // (termination case 2). - return aHaystack[mid]; - } - else { - // aHaystack[mid] is less than our needle. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); - } - // The exact needle element was not found in this haystack. Determine if - // we are in termination case (2) or (3) and return the appropriate thing. - return aLow < 0 - ? null - : aHaystack[aLow]; - } - } - - /** - * This is an implementation of binary search which will always try and return - * the next lowest value checked if there is no exact hit. This is because - * mappings between original and generated line/col pairs are single points, - * and there is an implicit region between each of them, so a miss just means - * that you aren't on the very start of a region. - * - * @param aNeedle The element you are looking for. - * @param aHaystack The array that is being searched. - * @param aCompare A function which takes the needle and an element in the - * array and returns -1, 0, or 1 depending on whether the needle is less - * than, equal to, or greater than the element, respectively. - */ - exports.search = function search(aNeedle, aHaystack, aCompare) { - return aHaystack.length > 0 - ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) - : null; - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) { - - var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; - var util = require('./util'); - - /** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ - function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine === undefined ? null : aLine; - this.column = aColumn === undefined ? null : aColumn; - this.source = aSource === undefined ? null : aSource; - this.name = aName === undefined ? null : aName; - if (aChunks != null) this.add(aChunks); - } - - /** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - */ - SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); - - // The generated code - // Processed fragments are removed from this array. - var remainingLines = aGeneratedCode.split('\n'); - - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; - - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping === null) { - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(remainingLines.shift() + "\n"); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - } else { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - var code = ""; - // Associate full lines with "lastMapping" - do { - code += remainingLines.shift() + "\n"; - lastGeneratedLine++; - lastGeneratedColumn = 0; - } while (lastGeneratedLine < mapping.generatedLine); - // When we reached the correct line, we add code until we - // reach the correct column too. - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - code += nextLine.substr(0, mapping.generatedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - // Create the SourceNode. - addMappingWithCode(lastMapping, code); - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[0]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - } - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - // Associate the remaining code in the current line with "lastMapping" - // and add the remaining lines without any mapping - addMappingWithCode(lastMapping, remainingLines.join("\n")); - - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - node.setSourceContent(sourceFile, content); - } - }); - - return node; - - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - mapping.source, - code, - mapping.name)); - } - } - }; - - /** - * Add a chunk of generated JS to this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ - SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); - } - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; - }; - - /** - * Add a chunk of generated JS to the beginning of this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ - SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - this.children.unshift(aChunk); - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; - }; - - /** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk instanceof SourceNode) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { - aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); - } - } - } - }; - - /** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ - SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; - }; - - /** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ - SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild instanceof SourceNode) { - lastChild.replaceRight(aPattern, aReplacement); - } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } - else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; - }; - - /** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ - SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - - /** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { - if (this.children[i] instanceof SourceNode) { - this.children[i].walkSourceContents(aFn); - } - } - - 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]]); - } - }; - - /** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ - SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; - }; - - /** - * Returns the string representation of this source node along with a source - * map. - */ - SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - 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) { - 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({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - chunk.split('').forEach(function (ch) { - if (ch === '\n') { - generated.line++; - generated.column = 0; - } else { - generated.column++; - } - }); - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - - return { code: generated.code, map: map }; - }; - - exports.SourceNode = SourceNode; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/////////////////////////////////////////////////////////////////////////////// - -this.sourceMap = { - SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, - SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, - SourceNode: require('source-map/source-node').SourceNode -}; From 0165bc0da0ddb657ad437fcaf27a6029b5dd23dc Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Sat, 2 Nov 2013 11:29:40 +0100 Subject: [PATCH 49/53] Bug 934091 - Add current process ID to the {++|--}{DOMWINDOW|DOCSHELL} debug output r=smaug From 4ac8092c5148f927e305be79c1667173d456313c Mon Sep 17 00:00:00 2001 --- docshell/base/nsDocShell.cpp | 19 +++++++++++++++---- dom/base/nsGlobalWindow.cpp | 25 ++++++++++++++++++------- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index b7f782de70a..68775674ed1 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -194,6 +194,11 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); #define DEBUG_PAGE_CACHE #endif +#ifdef XP_WIN +#include +#define getpid _getpid +#endif + using namespace mozilla; using namespace mozilla::dom; @@ -795,8 +800,11 @@ nsDocShell::nsDocShell(): // We're counting the number of |nsDocShells| to help find leaks ++gNumberOfDocShells; if (!PR_GetEnv("MOZ_QUIET")) { - printf("++DOCSHELL %p == %ld [id = %llu]\n", (void*) this, - gNumberOfDocShells, SafeCast(mHistoryID)); + printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n", + (void*) this, + gNumberOfDocShells, + getpid(), + SafeCast(mHistoryID)); } #endif } @@ -824,8 +832,11 @@ nsDocShell::~nsDocShell() // We're counting the number of |nsDocShells| to help find leaks --gNumberOfDocShells; if (!PR_GetEnv("MOZ_QUIET")) { - printf("--DOCSHELL %p == %ld [id = %llu]\n", (void*) this, - gNumberOfDocShells, SafeCast(mHistoryID)); + printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %llu]\n", + (void*) this, + gNumberOfDocShells, + getpid(), + SafeCast(mHistoryID)); } #endif } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 8431f2d0017..f37871724d2 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -237,6 +237,11 @@ class nsIScriptTimeoutHandler; static PRLogModuleInfo* gDOMLeakPRLog; #endif +#ifdef XP_WIN +#include +#define getpid _getpid +#endif + static const char kStorageEnabled[] = "dom.storage.enabled"; using namespace mozilla; @@ -1121,10 +1126,12 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) #ifdef DEBUG if (!PR_GetEnv("MOZ_QUIET")) { - printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt, - static_cast(static_cast(this)), - gSerialCounter, - static_cast(static_cast(aOuterWindow))); + printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n", + gRefCnt, + static_cast(static_cast(this)), + getpid(), + gSerialCounter, + static_cast(static_cast(aOuterWindow))); } #endif @@ -1197,9 +1204,13 @@ nsGlobalWindow::~nsGlobalWindow() } nsGlobalWindow* outer = static_cast(mOuterWindow.get()); - printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n", - gRefCnt, static_cast(static_cast(this)), - mSerial, static_cast(static_cast(outer)), url.get()); + printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n", + gRefCnt, + static_cast(static_cast(this)), + getpid(), + mSerial, + static_cast(static_cast(outer)), + url.get()); } #endif From c8681d87a878f92d7cc20e254baab70f338ee152 Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 5 Nov 2013 21:12:56 -0800 Subject: [PATCH 50/53] Bug 935376 - Back out 2e6063aa9b77 (bug 328755) on suspicion of causing a crash in ntdll --- xpcom/io/Base64.cpp | 5 +---- xpcom/io/nsEscape.cpp | 10 +--------- xpcom/string/public/nsCharTraits.h | 4 ++-- xpcom/string/src/nsSubstring.cpp | 8 +++----- xpcom/string/src/nsTSubstring.cpp | 2 +- 5 files changed, 8 insertions(+), 21 deletions(-) diff --git a/xpcom/io/Base64.cpp b/xpcom/io/Base64.cpp index 9061b9dec51..94fec02775a 100644 --- a/xpcom/io/Base64.cpp +++ b/xpcom/io/Base64.cpp @@ -208,10 +208,7 @@ EncodeInputStream(nsIInputStream *aInputStream, if (state.charsOnStack) Encode(state.c, state.charsOnStack, state.buffer); - if (aDest.Length()) - // May belong to an nsCString with an unallocated buffer, so only null - // terminate if there is a need to. - *aDest.EndWriting() = '\0'; + *aDest.EndWriting() = '\0'; return NS_OK; } diff --git a/xpcom/io/nsEscape.cpp b/xpcom/io/nsEscape.cpp index cd18ba0050b..3e212a13e50 100644 --- a/xpcom/io/nsEscape.cpp +++ b/xpcom/io/nsEscape.cpp @@ -181,15 +181,7 @@ int32_t nsUnescapeCount(char * str) } } - /* The string may belong to a nsCString with an unallocated buffer. - In such a situation the buffer points to a const char, so attempting - to write to it will crash. This can be avoided by only null-terminating - when needed. The above while loop is safe as it won't iterate when this - occurs. - */ - if (*dst) { - *dst = 0; - } + *dst = 0; return (int)(dst - str); } /* NET_UnEscapeCnt */ diff --git a/xpcom/string/public/nsCharTraits.h b/xpcom/string/public/nsCharTraits.h index 6a309f0fa2b..46c34a93570 100644 --- a/xpcom/string/public/nsCharTraits.h +++ b/xpcom/string/public/nsCharTraits.h @@ -100,7 +100,7 @@ struct nsCharTraits typedef uint16_t unsigned_char_type; typedef char incompatible_char_type; - static char_type * const sEmptyBuffer; + static char_type *sEmptyBuffer; static void @@ -326,7 +326,7 @@ struct nsCharTraits typedef unsigned char unsigned_char_type; typedef PRUnichar incompatible_char_type; - static char_type *const sEmptyBuffer; + static char_type *sEmptyBuffer; static void diff --git a/xpcom/string/src/nsSubstring.cpp b/xpcom/string/src/nsSubstring.cpp index 2ca85b60a2a..7a9df8b3e1c 100644 --- a/xpcom/string/src/nsSubstring.cpp +++ b/xpcom/string/src/nsSubstring.cpp @@ -29,12 +29,10 @@ using mozilla::Atomic; // --------------------------------------------------------------------------- -static const PRUnichar gNullChar = 0; +static PRUnichar gNullChar = 0; -char* const nsCharTraits ::sEmptyBuffer = - (char*) const_cast(&gNullChar); -PRUnichar* const nsCharTraits::sEmptyBuffer = - const_cast(&gNullChar); +char* nsCharTraits ::sEmptyBuffer = (char*) &gNullChar; +PRUnichar* nsCharTraits::sEmptyBuffer = &gNullChar; // --------------------------------------------------------------------------- diff --git a/xpcom/string/src/nsTSubstring.cpp b/xpcom/string/src/nsTSubstring.cpp index af14bc52c42..eb8adda10cb 100644 --- a/xpcom/string/src/nsTSubstring.cpp +++ b/xpcom/string/src/nsTSubstring.cpp @@ -302,7 +302,7 @@ nsTSubstring_CharT::Assign( const char_type* data, size_type length ) bool nsTSubstring_CharT::Assign( const char_type* data, size_type length, const fallible_t& ) { - if (!data || length == 0) + if (!data) { Truncate(); return true; From 7877d181c0b329e3981c50d248b5372e7434cab9 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 5 Nov 2013 22:49:22 -0800 Subject: [PATCH 51/53] Bug 930141 - Replace escodegen with pretty-fast in the debugger and scratchpad pretty printing backend; r=gps,dcamp,past,benvie --- .../test/browser_dbg_pretty-print-08.js | 3 +- .../test/browser_dbg_pretty-print-09.js | 3 +- browser/devtools/scratchpad/scratchpad.js | 68 +- browser/devtools/scratchpad/test/browser.ini | 5 +- .../test/browser_scratchpad_pprint-02.js | 22 +- .../test/browser_scratchpad_pprint.js | 11 +- toolkit/devtools/Loader.jsm | 15 +- toolkit/devtools/acorn/moz.build | 2 +- .../acorn/tests/unit/test_import_acorn.js | 4 +- .../acorn/tests/unit/test_lenient_parser.js | 2 +- .../acorn/tests/unit/test_same_ast.js | 2 +- toolkit/devtools/escodegen/LICENSE.BSD | 19 - toolkit/devtools/escodegen/UPGRADING.md | 54 - toolkit/devtools/escodegen/escodegen.js | 2065 ------ .../devtools/escodegen/escodegen.worker.js | 5539 ----------------- toolkit/devtools/escodegen/estraverse.js | 678 -- toolkit/devtools/escodegen/package.json.js | 57 - .../tests/unit/test_generate_source_maps.js | 71 - .../tests/unit/test_import_escodegen.js | 11 - .../escodegen/tests/unit/test_same_ast.js | 76 - .../escodegen/tests/unit/xpcshell.ini | 7 - toolkit/devtools/moz.build | 4 +- toolkit/devtools/pretty-fast/UPGRADING.md | 7 + .../{escodegen => pretty-fast}/moz.build | 7 +- toolkit/devtools/pretty-fast/pretty-fast.js | 781 +++ .../tests/unit/head_pretty-fast.js} | 7 +- .../devtools/pretty-fast/tests/unit/test.js | 470 ++ .../pretty-fast/tests/unit/xpcshell.ini | 5 + .../server/actors/pretty-print-worker.js | 27 +- toolkit/devtools/server/actors/script.js | 16 +- toolkit/devtools/server/main.js | 1 - toolkit/devtools/sourcemap/Makefile.in | 1 + toolkit/devtools/sourcemap/source-map.js | 1929 ++++++ 33 files changed, 3313 insertions(+), 8656 deletions(-) delete mode 100644 toolkit/devtools/escodegen/LICENSE.BSD delete mode 100644 toolkit/devtools/escodegen/UPGRADING.md delete mode 100644 toolkit/devtools/escodegen/escodegen.js delete mode 100644 toolkit/devtools/escodegen/escodegen.worker.js delete mode 100644 toolkit/devtools/escodegen/estraverse.js delete mode 100644 toolkit/devtools/escodegen/package.json.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/test_same_ast.js delete mode 100644 toolkit/devtools/escodegen/tests/unit/xpcshell.ini create mode 100644 toolkit/devtools/pretty-fast/UPGRADING.md rename toolkit/devtools/{escodegen => pretty-fast}/moz.build (73%) create mode 100644 toolkit/devtools/pretty-fast/pretty-fast.js rename toolkit/devtools/{escodegen/tests/unit/head_escodegen.js => pretty-fast/tests/unit/head_pretty-fast.js} (82%) create mode 100644 toolkit/devtools/pretty-fast/tests/unit/test.js create mode 100644 toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini create mode 100644 toolkit/devtools/sourcemap/source-map.js diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js index 6985c72615a..8466ddf6f79 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-08.js @@ -80,10 +80,9 @@ function testStepping() { function testHitBreakpoint() { gClient.addOneTimeListener("paused", (event, { why, frame }) => { is(why.type, "breakpoint"); - const { url, line, column } = frame.where; + const { url, line } = frame.where; is(url, CODE_URL); is(line, BP_LOCATION.line); - is(column, BP_LOCATION.column); resumeDebuggerThenCloseAndFinish(gPanel); }); diff --git a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js index 07bdeb2fa81..952f8a92f05 100644 --- a/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js +++ b/browser/devtools/debugger/test/browser_dbg_pretty-print-09.js @@ -55,10 +55,9 @@ function runCode({ error }) { function testDbgStatement(event, { frame, why }) { is(why.type, "debuggerStatement"); - const { url, line, column } = frame.where; + const { url, line } = frame.where; is(url, B_URL); is(line, 2); - is(column, 2); disablePrettyPrint(); } diff --git a/browser/devtools/scratchpad/scratchpad.js b/browser/devtools/scratchpad/scratchpad.js index 48780058ece..c139c362007 100644 --- a/browser/devtools/scratchpad/scratchpad.js +++ b/browser/devtools/scratchpad/scratchpad.js @@ -34,7 +34,6 @@ const VARIABLES_VIEW_URL = "chrome://browser/content/devtools/widgets/VariablesV const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const promise = require("sdk/core/promise"); const Telemetry = require("devtools/shared/telemetry"); -const escodegen = require("escodegen/escodegen"); const Editor = require("devtools/sourceeditor/editor"); const TargetFactory = require("devtools/framework/target").TargetFactory; @@ -516,25 +515,61 @@ var Scratchpad = { return deferred.promise; }, + _prettyPrintWorker: null, + + /** + * Get or create the worker that handles pretty printing. + */ + get prettyPrintWorker() { + if (!this._prettyPrintWorker) { + this._prettyPrintWorker = new ChromeWorker( + "resource://gre/modules/devtools/server/actors/pretty-print-worker.js"); + + this._prettyPrintWorker.addEventListener("error", ({ message, filename, lineno }) => { + DevToolsUtils.reportException(message + " @ " + filename + ":" + lineno); + }, false); + } + return this._prettyPrintWorker; + }, + /** * Pretty print the source text inside the scratchpad. + * + * @return Promise + * A promise resolved with the pretty printed code, or rejected with + * an error. */ prettyPrint: function SP_prettyPrint() { const uglyText = this.getText(); const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); - try { - const ast = Reflect.parse(uglyText); - const prettyText = escodegen.generate(ast, { - format: { - indent: { - style: " ".repeat(tabsize) - } - } - }); - this.editor.setText(prettyText); - } catch (e) { - this.writeAsErrorComment(DevToolsUtils.safeErrorString(e)); - } + const id = Math.random(); + const deferred = promise.defer(); + + const onReply = ({ data }) => { + if (data.id !== id) { + return; + } + this.prettyPrintWorker.removeEventListener("message", onReply, false); + + if (data.error) { + let errorString = DevToolsUtils.safeErrorString(data.error); + this.writeAsErrorComment(errorString); + deferred.reject(errorString); + } else { + this.editor.setText(data.code); + deferred.resolve(data.code); + } + }; + + this.prettyPrintWorker.addEventListener("message", onReply, false); + this.prettyPrintWorker.postMessage({ + id: id, + url: "(scratchpad)", + indent: tabsize, + source: uglyText + }); + + return deferred.promise; }, /** @@ -1375,6 +1410,11 @@ var Scratchpad = { this._sidebar = null; } + if (this._prettyPrintWorker) { + this._prettyPrintWorker.terminate(); + this._prettyPrintWorker = null; + } + scratchpadTargets = null; this.webConsoleClient = null; this.debuggerClient = null; diff --git a/browser/devtools/scratchpad/test/browser.ini b/browser/devtools/scratchpad/test/browser.ini index f1b27427250..57e39157a35 100644 --- a/browser/devtools/scratchpad/test/browser.ini +++ b/browser/devtools/scratchpad/test/browser.ini @@ -28,10 +28,9 @@ support-files = head.js [browser_scratchpad_long_string.js] [browser_scratchpad_open.js] [browser_scratchpad_open_error_console.js] -# Disabled, as escodegen is being replaced - bug 930141 -# [browser_scratchpad_pprint-02.js] -# [browser_scratchpad_pprint.js] [browser_scratchpad_throw_output.js] +[browser_scratchpad_pprint-02.js] +[browser_scratchpad_pprint.js] [browser_scratchpad_restore.js] [browser_scratchpad_tab_switch.js] [browser_scratchpad_ui.js] diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js b/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js index 8deffdda943..13a6e91c1cc 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_pprint-02.js @@ -15,18 +15,26 @@ function test() content.location = "data:text/html;charset=utf8,test Scratchpad pretty print."; } +let gTabsize; + function runTests(sw) { - const tabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); + gTabsize = Services.prefs.getIntPref("devtools.editor.tabsize"); Services.prefs.setIntPref("devtools.editor.tabsize", 6); const space = " ".repeat(6); const sp = sw.Scratchpad; sp.setText("function main() { console.log(5); }"); - sp.prettyPrint(); - const prettyText = sp.getText(); - ok(prettyText.contains(space)); - - Services.prefs.setIntPref("devtools.editor.tabsize", tabsize); - finish(); + sp.prettyPrint().then(() => { + const prettyText = sp.getText(); + ok(prettyText.contains(space)); + finish(); + }).then(null, error => { + ok(false, error); + }); } + +registerCleanupFunction(function () { + Services.prefs.setIntPref("devtools.editor.tabsize", gTabsize); + gTabsize = null; +}); diff --git a/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js b/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js index 9b5a6b3d243..d8ff7039d41 100644 --- a/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js +++ b/browser/devtools/scratchpad/test/browser_scratchpad_pprint.js @@ -19,8 +19,11 @@ function runTests(sw) { const sp = sw.Scratchpad; sp.setText("function main() { console.log(5); }"); - sp.prettyPrint(); - const prettyText = sp.getText(); - ok(prettyText.contains("\n")); - finish(); + sp.prettyPrint().then(() => { + const prettyText = sp.getText(); + ok(prettyText.contains("\n")); + finish(); + }).then(null, error => { + ok(false, error); + }); } diff --git a/toolkit/devtools/Loader.jsm b/toolkit/devtools/Loader.jsm index 6b68aeae508..d2c8bb03473 100644 --- a/toolkit/devtools/Loader.jsm +++ b/toolkit/devtools/Loader.jsm @@ -64,10 +64,10 @@ var BuiltinProvider = { "devtools/output-parser": "resource://gre/modules/devtools/output-parser", "devtools/touch-events": "resource://gre/modules/devtools/touch-events", "devtools/client": "resource://gre/modules/devtools/client", + "devtools/pretty-fast": "resource://gre/modules/devtools/pretty-fast.js", - "acorn": "resource://gre/modules/devtools/acorn", - "escodegen": "resource://gre/modules/devtools/escodegen", - "estraverse": "resource://gre/modules/devtools/escodegen/estraverse", + "acorn": "resource://gre/modules/devtools/acorn.js", + "acorn_loose": "resource://gre/modules/devtools/acorn_loose.js", // Allow access to xpcshell test items from the loader. "xpcshell-test": "resource://test" @@ -109,9 +109,9 @@ var SrcdirProvider = { let outputParserURI = this.fileURI(OS.Path.join(toolkitDir, "output-parser")); let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events")); let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client")); + let prettyFastURI = this.fileURI(OS.Path.join(toolkitDir), "pretty-fast.js"); let acornURI = this.fileURI(OS.Path.join(toolkitDir, "acorn")); - let escodegenURI = this.fileURI(OS.Path.join(toolkitDir, "escodegen")); - let estraverseURI = this.fileURI(OS.Path.join(toolkitDir, "escodegen", "estraverse")); + let acornLoosseURI = this.fileURI(OS.Path.join(toolkitDir, "acorn_loose.js")); this.loader = new loader.Loader({ modules: { "toolkit/loader": loader, @@ -129,9 +129,10 @@ var SrcdirProvider = { "devtools/output-parser": outputParserURI, "devtools/touch-events": touchEventsURI, "devtools/client": clientURI, + "devtools/pretty-fast": prettyFastURI, + "acorn": acornURI, - "escodegen": escodegenURI, - "estraverse": estraverseURI + "acorn_loose": acornLoosseURI }, globals: loaderGlobals }); diff --git a/toolkit/devtools/acorn/moz.build b/toolkit/devtools/acorn/moz.build index 1eafb9bc925..8f3524f7d23 100644 --- a/toolkit/devtools/acorn/moz.build +++ b/toolkit/devtools/acorn/moz.build @@ -6,7 +6,7 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] -JS_MODULES_PATH = 'modules/devtools/acorn' +JS_MODULES_PATH = 'modules/devtools' EXTRA_JS_MODULES += [ 'acorn.js', diff --git a/toolkit/devtools/acorn/tests/unit/test_import_acorn.js b/toolkit/devtools/acorn/tests/unit/test_import_acorn.js index d9d72ef2684..969893f36c2 100644 --- a/toolkit/devtools/acorn/tests/unit/test_import_acorn.js +++ b/toolkit/devtools/acorn/tests/unit/test_import_acorn.js @@ -6,8 +6,8 @@ */ function run_test() { - const acorn = require("acorn/acorn"); - const acorn_loose = require("acorn/acorn_loose"); + const acorn = require("acorn"); + const acorn_loose = require("acorn_loose"); do_check_true(isObject(acorn)); do_check_true(isObject(acorn_loose)); do_check_eq(typeof acorn.parse, "function"); diff --git a/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js b/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js index 794918b6357..e72aac0f5c3 100644 --- a/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js +++ b/toolkit/devtools/acorn/tests/unit/test_lenient_parser.js @@ -5,7 +5,7 @@ * Test that acorn's lenient parser gives something usable. */ -const acorn_loose = require("acorn/acorn_loose"); +const acorn_loose = require("acorn_loose"); function run_test() { let actualAST = acorn_loose.parse_dammit("let x = 10"); diff --git a/toolkit/devtools/acorn/tests/unit/test_same_ast.js b/toolkit/devtools/acorn/tests/unit/test_same_ast.js index ce2de6076d7..d01916d7abb 100644 --- a/toolkit/devtools/acorn/tests/unit/test_same_ast.js +++ b/toolkit/devtools/acorn/tests/unit/test_same_ast.js @@ -5,7 +5,7 @@ * Test that Reflect and acorn create the same AST for ES5. */ -const acorn = require("acorn/acorn"); +const acorn = require("acorn"); Cu.import("resource://gre/modules/reflect.jsm"); const testCode = "" + function main () { diff --git a/toolkit/devtools/escodegen/LICENSE.BSD b/toolkit/devtools/escodegen/LICENSE.BSD deleted file mode 100644 index 3e580c355a9..00000000000 --- a/toolkit/devtools/escodegen/LICENSE.BSD +++ /dev/null @@ -1,19 +0,0 @@ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/toolkit/devtools/escodegen/UPGRADING.md b/toolkit/devtools/escodegen/UPGRADING.md deleted file mode 100644 index bf8d2882d67..00000000000 --- a/toolkit/devtools/escodegen/UPGRADING.md +++ /dev/null @@ -1,54 +0,0 @@ -Assuming that escodegen's dependencies have not changed, to upgrade our tree's -escodegen to a new version: - -1. Clone the escodegen repository, and check out the version you want to upgrade -to: - - $ git clone https://github.com/Constellation/escodegen.git - $ cd escodegen - $ git checkout - -2. Make sure that all tests pass: - - $ npm install . - $ npm test - - If there are any test failures, do not upgrade to that version of escodegen! - -3. Copy escodegen.js to our tree: - - $ cp escodegen.js /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.js - -4. Copy the package.json to our tree, and append ".js" to make it work with our -loader: - - $ cp package.json /path/to/mozilla-central/toolkit/devtools/escodegen/package.json.js - -5. Prepend `module.exports = ` to the package.json file contents, so that the -JSON data is exported, and we can load package.json as a module. - - Bug 933482: Note, this is a workaround for Bug 910594, which will allow the SDK loader to require JSON files. To remove ambiguity, comment out the `require('./package.json').version` line in `escodegen.js` so that when Bug 910594 is uplifted into central, it does not attempt to look for `package.json`, rather than `package.json.js`. This is a temporary workaround, and once Bug 933500 is solved, either `package.json` or `package.json.js` will work. - -6. Copy the estraverse.js that escodegen depends on into our tree: - - $ cp node_modules/estraverse/estraverse.js /path/to/mozilla-central/devtools/escodegen/estraverse.js - -7. Build the version of the escodegen that we can use in workers: - - First we need to alias `self` as `window`: - - $ echo 'let window = self;' >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js - - Then we need to add the browser build of the source map library: - - $ git clone https://github.com/mozilla/source-map - $ cd source-map - $ git co - $ npm run-script build - $ cat dist/source-map.js >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js - - Then we need to build the browser version of escodegen: - - $ cd /path/to/escodegen - $ npm run-script build - $ cat escodegen.browser.js >> /path/to/mozilla-central/toolkit/devtools/escodegen/escodegen.worker.js diff --git a/toolkit/devtools/escodegen/escodegen.js b/toolkit/devtools/escodegen/escodegen.js deleted file mode 100644 index 41b32286431..00000000000 --- a/toolkit/devtools/escodegen/escodegen.js +++ /dev/null @@ -1,2065 +0,0 @@ -/* - Copyright (C) 2012-2013 Yusuke Suzuki - Copyright (C) 2012-2013 Michael Ficarra - Copyright (C) 2012-2013 Mathias Bynens - Copyright (C) 2013 Irakli Gozalishvili - Copyright (C) 2012 Robert Gust-Bardon - Copyright (C) 2012 John Freeman - Copyright (C) 2011-2012 Ariya Hidayat - Copyright (C) 2012 Joost-Wim Boekesteijn - Copyright (C) 2012 Kris Kowal - Copyright (C) 2012 Arpad Borsos - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/*jslint bitwise:true */ -/*global exports:true, generateStatement:true, generateExpression:true, require:true, global:true*/ -(function () { - 'use strict'; - - var Syntax, - Precedence, - BinaryPrecedence, - Regex, - SourceNode, - estraverse, - isArray, - base, - indent, - json, - renumber, - hexadecimal, - quotes, - escapeless, - newline, - space, - parentheses, - semicolons, - safeConcatenation, - directive, - extra, - parse, - sourceMap, - FORMAT_MINIFY, - FORMAT_DEFAULTS; - - estraverse = require('estraverse'); - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ComprehensionBlock: 'ComprehensionBlock', - ComprehensionExpression: 'ComprehensionExpression', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - - }; - - Precedence = { - Sequence: 0, - Assignment: 1, - Conditional: 2, - LogicalOR: 3, - LogicalAND: 4, - BitwiseOR: 5, - BitwiseXOR: 6, - BitwiseAND: 7, - Equality: 8, - Relational: 9, - BitwiseSHIFT: 10, - Additive: 11, - Multiplicative: 12, - Unary: 13, - Postfix: 14, - Call: 15, - New: 16, - Member: 17, - Primary: 18 - }; - - BinaryPrecedence = { - '||': Precedence.LogicalOR, - '&&': Precedence.LogicalAND, - '|': Precedence.BitwiseOR, - '^': Precedence.BitwiseXOR, - '&': Precedence.BitwiseAND, - '==': Precedence.Equality, - '!=': Precedence.Equality, - '===': Precedence.Equality, - '!==': Precedence.Equality, - 'is': Precedence.Equality, - 'isnt': Precedence.Equality, - '<': Precedence.Relational, - '>': Precedence.Relational, - '<=': Precedence.Relational, - '>=': Precedence.Relational, - 'in': Precedence.Relational, - 'instanceof': Precedence.Relational, - '<<': Precedence.BitwiseSHIFT, - '>>': Precedence.BitwiseSHIFT, - '>>>': Precedence.BitwiseSHIFT, - '+': Precedence.Additive, - '-': Precedence.Additive, - '*': Precedence.Multiplicative, - '%': Precedence.Multiplicative, - '/': Precedence.Multiplicative - }; - - Regex = { - 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]') - }; - - function getDefaultOptions() { - // default options - return { - indent: null, - base: null, - parse: null, - comment: false, - format: { - indent: { - style: ' ', - base: 0, - adjustMultilineComment: false - }, - json: false, - renumber: false, - hexadecimal: false, - quotes: 'single', - escapeless: false, - compact: false, - parentheses: true, - semicolons: true, - safeConcatenation: false - }, - moz: { - starlessGenerator: false, - parenthesizedComprehensionBlock: false - }, - sourceMap: null, - sourceMapRoot: null, - sourceMapWithCode: false, - directive: false, - verbatim: null - }; - } - - function stringToArray(str) { - var length = str.length, - result = [], - i; - for (i = 0; i < length; i += 1) { - result[i] = str.charAt(i); - } - return result; - } - - function stringRepeat(str, num) { - var result = ''; - - for (num |= 0; num > 0; num >>>= 1, str += str) { - if (num & 1) { - result += str; - } - } - - return result; - } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - - // Fallback for the non SourceMap environment - function SourceNodeMock(line, column, filename, chunk) { - var result = []; - - function flatten(input) { - var i, iz; - if (isArray(input)) { - for (i = 0, iz = input.length; i < iz; ++i) { - flatten(input[i]); - } - } else if (input instanceof SourceNodeMock) { - result.push(input); - } else if (typeof input === 'string' && input) { - result.push(input); - } - } - - flatten(chunk); - this.children = result; - } - - SourceNodeMock.prototype.toString = function toString() { - var res = '', i, iz, node; - for (i = 0, iz = this.children.length; i < iz; ++i) { - node = this.children[i]; - if (node instanceof SourceNodeMock) { - res += node.toString(); - } else { - res += node; - } - } - return res; - }; - - SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) { - var last = this.children[this.children.length - 1]; - if (last instanceof SourceNodeMock) { - last.replaceRight(pattern, replacement); - } else if (typeof last === 'string') { - this.children[this.children.length - 1] = last.replace(pattern, replacement); - } else { - this.children.push(''.replace(pattern, replacement)); - } - return this; - }; - - SourceNodeMock.prototype.join = function join(sep) { - var i, iz, result; - result = []; - iz = this.children.length; - if (iz > 0) { - for (i = 0, iz -= 1; i < iz; ++i) { - result.push(this.children[i], sep); - } - result.push(this.children[iz]); - this.children = result; - } - return this; - }; - - function hasLineTerminator(str) { - return (/[\r\n]/g).test(str); - } - - function endsWithLineTerminator(str) { - var ch = str.charAt(str.length - 1); - return ch === '\r' || ch === '\n'; - } - - function updateDeeply(target, override) { - var key, val; - - function isHashObject(target) { - return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); - } - - for (key in override) { - if (override.hasOwnProperty(key)) { - val = override[key]; - if (isHashObject(val)) { - if (isHashObject(target[key])) { - updateDeeply(target[key], val); - } else { - target[key] = updateDeeply({}, val); - } - } else { - target[key] = val; - } - } - } - return target; - } - - function generateNumber(value) { - var result, point, temp, exponent, pos; - - if (value !== value) { - throw new Error('Numeric literal whose value is NaN'); - } - if (value < 0 || (value === 0 && 1 / value < 0)) { - throw new Error('Numeric literal whose value is negative'); - } - - if (value === 1 / 0) { - return json ? 'null' : renumber ? '1e400' : '1e+400'; - } - - result = '' + value; - if (!renumber || result.length < 3) { - return result; - } - - point = result.indexOf('.'); - if (!json && result.charAt(0) === '0' && point === 1) { - point = 0; - result = result.slice(1); - } - temp = result; - result = result.replace('e+', 'e'); - exponent = 0; - if ((pos = temp.indexOf('e')) > 0) { - exponent = +temp.slice(pos + 1); - temp = temp.slice(0, pos); - } - if (point >= 0) { - exponent -= temp.length - point - 1; - temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; - } - pos = 0; - while (temp.charAt(temp.length + pos - 1) === '0') { - pos -= 1; - } - if (pos !== 0) { - exponent -= pos; - temp = temp.slice(0, pos); - } - if (exponent !== 0) { - temp += 'e' + exponent; - } - if ((temp.length < result.length || - (hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) && - +temp === value) { - result = temp; - } - - return result; - } - - // Generate valid RegExp expression. - // This function is based on https://github.com/Constellation/iv Engine - - function escapeRegExpCharacter(ch, previousIsBackslash) { - // not handling '\' and handling \u2028 or \u2029 to unicode escape sequence - if ((ch & ~1) === 0x2028) { - return (previousIsBackslash ? 'u' : '\\u') + ((ch === 0x2028) ? '2028' : '2029'); - } else if (ch === 10 || ch === 13) { // \n, \r - return (previousIsBackslash ? '' : '\\') + ((ch === 10) ? 'n' : 'r'); - } - return String.fromCharCode(ch); - } - - function generateRegExp(reg) { - var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash; - - result = reg.toString(); - - if (reg.source) { - // extract flag from toString result - match = result.match(/\/([^/]*)$/); - if (!match) { - return result; - } - - flags = match[1]; - result = ''; - - characterInBrack = false; - previousIsBackslash = false; - for (i = 0, iz = reg.source.length; i < iz; ++i) { - ch = reg.source.charCodeAt(i); - - if (!previousIsBackslash) { - if (characterInBrack) { - if (ch === 93) { // ] - characterInBrack = false; - } - } else { - if (ch === 47) { // / - result += '\\'; - } else if (ch === 91) { // [ - characterInBrack = true; - } - } - result += escapeRegExpCharacter(ch, previousIsBackslash); - previousIsBackslash = ch === 92; // \ - } else { - // if new RegExp("\\\n') is provided, create /\n/ - result += escapeRegExpCharacter(ch, previousIsBackslash); - // prevent like /\\[/]/ - previousIsBackslash = false; - } - } - - return '/' + result + '/' + flags; - } - - return result; - } - - function escapeAllowedCharacter(ch, next) { - var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; - - switch (ch) { - case '\b': - result += 'b'; - break; - case '\f': - result += 'f'; - break; - case '\t': - result += 't'; - break; - default: - if (json || code > 0xff) { - result += 'u' + '0000'.slice(hex.length) + hex; - } else if (ch === '\u0000' && '0123456789'.indexOf(next) < 0) { - result += '0'; - } else if (ch === '\x0B') { // '\v' - result += 'x0B'; - } else { - result += 'x' + '00'.slice(hex.length) + hex; - } - break; - } - - return result; - } - - function escapeDisallowedCharacter(ch) { - var result = '\\'; - switch (ch) { - case '\\': - result += '\\'; - break; - case '\n': - result += 'n'; - break; - case '\r': - result += 'r'; - break; - case '\u2028': - result += 'u2028'; - break; - case '\u2029': - result += 'u2029'; - break; - default: - throw new Error('Incorrectly classified character'); - } - - return result; - } - - function escapeDirective(str) { - var i, iz, ch, buf, quote; - - buf = str; - if (typeof buf[0] === 'undefined') { - buf = stringToArray(buf); - } - - quote = quotes === 'double' ? '"' : '\''; - for (i = 0, iz = buf.length; i < iz; i += 1) { - ch = buf[i]; - if (ch === '\'') { - quote = '"'; - break; - } else if (ch === '"') { - quote = '\''; - break; - } else if (ch === '\\') { - i += 1; - } - } - - return quote + str + quote; - } - - function escapeString(str) { - var result = '', i, len, ch, singleQuotes = 0, doubleQuotes = 0, single; - - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if (ch === '\'') { - singleQuotes += 1; - } else if (ch === '"') { - doubleQuotes += 1; - } else if (ch === '/' && json) { - result += '\\'; - } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { - result += escapeDisallowedCharacter(ch); - continue; - } else if ((json && ch < ' ') || !(json || escapeless || (ch >= ' ' && ch <= '~'))) { - result += escapeAllowedCharacter(ch, str[i + 1]); - continue; - } - result += ch; - } - - single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes)); - str = result; - result = single ? '\'' : '"'; - - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if ((ch === '\'' && single) || (ch === '"' && !single)) { - result += '\\'; - } - result += ch; - } - - return result + (single ? '\'' : '"'); - } - - function isWhiteSpace(ch) { - // Use `\x0B` instead of `\v` for IE < 9 compatibility - return '\t\x0B\f \xa0'.indexOf(ch) >= 0 || (ch.charCodeAt(0) >= 0x1680 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0); - } - - function isLineTerminator(ch) { - return '\n\r\u2028\u2029'.indexOf(ch) >= 0; - } - - 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)); - } - - function toSourceNode(generated, node) { - if (node == null) { - if (generated instanceof SourceNode) { - return generated; - } else { - node = {}; - } - } - if (node.loc == null) { - return new SourceNode(null, null, sourceMap, generated, node.name || null); - } - return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated, node.name || null); - } - - function join(left, right) { - var leftSource = toSourceNode(left).toString(), - rightSource = toSourceNode(right).toString(), - leftChar = leftSource.charAt(leftSource.length - 1), - rightChar = rightSource.charAt(0); - - if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) { - return [left, ' ', right]; - } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { - return [left, right]; - } - return [left, space, right]; - } - - function addIndent(stmt) { - return [base, stmt]; - } - - function withIndent(fn) { - var previousBase, result; - previousBase = base; - base += indent; - result = fn.call(this, base); - base = previousBase; - return result; - } - - function calculateSpaces(str) { - var i; - for (i = str.length - 1; i >= 0; i -= 1) { - if (isLineTerminator(str.charAt(i))) { - break; - } - } - return (str.length - 1) - i; - } - - function adjustMultilineComment(value, specialBase) { - var array, i, len, line, j, spaces, previousBase; - - array = value.split(/\r\n|[\r\n]/); - spaces = Number.MAX_VALUE; - - // first line doesn't have indentation - for (i = 1, len = array.length; i < len; i += 1) { - line = array[i]; - j = 0; - while (j < line.length && isWhiteSpace(line[j])) { - j += 1; - } - if (spaces > j) { - spaces = j; - } - } - - if (typeof specialBase !== 'undefined') { - // pattern like - // { - // var t = 20; /* - // * this is comment - // */ - // } - previousBase = base; - if (array[1][spaces] === '*') { - specialBase += ' '; - } - base = specialBase; - } else { - if (spaces & 1) { - // /* - // * - // */ - // If spaces are odd number, above pattern is considered. - // We waste 1 space. - spaces -= 1; - } - previousBase = base; - } - - for (i = 1, len = array.length; i < len; i += 1) { - array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join(''); - } - - base = previousBase; - - return array.join('\n'); - } - - function generateComment(comment, specialBase) { - if (comment.type === 'Line') { - if (endsWithLineTerminator(comment.value)) { - return '//' + comment.value; - } else { - // Always use LineTerminator - return '//' + comment.value + '\n'; - } - } - if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { - return adjustMultilineComment('/*' + comment.value + '*/', specialBase); - } - return '/*' + comment.value + '*/'; - } - - function addCommentsToStatement(stmt, result) { - var i, len, comment, save, tailingToStatement, specialBase, fragment; - - if (stmt.leadingComments && stmt.leadingComments.length > 0) { - save = result; - - comment = stmt.leadingComments[0]; - result = []; - if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { - result.push('\n'); - } - result.push(generateComment(comment)); - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push('\n'); - } - - for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { - comment = stmt.leadingComments[i]; - fragment = [generateComment(comment)]; - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - fragment.push('\n'); - } - result.push(addIndent(fragment)); - } - - result.push(addIndent(save)); - } - - if (stmt.trailingComments) { - tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString()); - specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([base, result, indent]).toString())); - for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { - comment = stmt.trailingComments[i]; - if (tailingToStatement) { - // We assume target like following script - // - // var t = 20; /** - // * This is comment of t - // */ - if (i === 0) { - // first case - result = [result, indent]; - } else { - result = [result, specialBase]; - } - result.push(generateComment(comment, specialBase)); - } else { - result = [result, addIndent(generateComment(comment))]; - } - if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) { - result = [result, '\n']; - } - } - } - - return result; - } - - function parenthesize(text, current, should) { - if (current < should) { - return ['(', text, ')']; - } - return text; - } - - function maybeBlock(stmt, semicolonOptional, functionBody) { - var result, noLeadingComment; - - noLeadingComment = !extra.comment || !stmt.leadingComments; - - if (stmt.type === Syntax.BlockStatement && noLeadingComment) { - return [space, generateStatement(stmt, { functionBody: functionBody })]; - } - - if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { - return ';'; - } - - withIndent(function () { - result = [newline, addIndent(generateStatement(stmt, { semicolonOptional: semicolonOptional, functionBody: functionBody }))]; - }); - - return result; - } - - function maybeBlockSuffix(stmt, result) { - var ends = endsWithLineTerminator(toSourceNode(result).toString()); - if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) { - return [result, space]; - } - if (ends) { - return [result, base]; - } - return [result, newline, base]; - } - - function generateVerbatim(expr, option) { - var i, result; - result = expr[extra.verbatim].split(/\r\n|\n/); - for (i = 1; i < result.length; i++) { - result[i] = newline + base + result[i]; - } - - result = parenthesize(result, Precedence.Sequence, option.precedence); - return toSourceNode(result, expr); - } - - function generateIdentifier(node) { - return toSourceNode(node.name, node); - } - - function generateFunctionBody(node) { - var result, i, len, expr; - result = ['(']; - for (i = 0, len = node.params.length; i < len; i += 1) { - result.push(generateIdentifier(node.params[i])); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - - if (node.expression) { - result.push(space); - expr = generateExpression(node.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }); - if (expr.toString().charAt(0) === '{') { - expr = ['(', expr, ')']; - } - result.push(expr); - } else { - result.push(maybeBlock(node.body, false, true)); - } - return result; - } - - function generateExpression(expr, option) { - var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, allowIn, allowCall, allowUnparenthesizedNew, property; - - precedence = option.precedence; - allowIn = option.allowIn; - allowCall = option.allowCall; - type = expr.type || option.type; - - if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { - return generateVerbatim(expr, option); - } - - switch (type) { - case Syntax.SequenceExpression: - result = []; - allowIn |= (Precedence.Sequence < precedence); - for (i = 0, len = expr.expressions.length; i < len; i += 1) { - result.push(generateExpression(expr.expressions[i], { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result = parenthesize(result, Precedence.Sequence, precedence); - break; - - case Syntax.AssignmentExpression: - allowIn |= (Precedence.Assignment < precedence); - result = parenthesize( - [ - generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: allowIn, - allowCall: true - }), - space + expr.operator + space, - generateExpression(expr.right, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], - Precedence.Assignment, - precedence - ); - break; - - case Syntax.ConditionalExpression: - allowIn |= (Precedence.Conditional < precedence); - result = parenthesize( - [ - generateExpression(expr.test, { - precedence: Precedence.LogicalOR, - allowIn: allowIn, - allowCall: true - }), - space + '?' + space, - generateExpression(expr.consequent, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space + ':' + space, - generateExpression(expr.alternate, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], - Precedence.Conditional, - precedence - ); - break; - - case Syntax.LogicalExpression: - case Syntax.BinaryExpression: - currentPrecedence = BinaryPrecedence[expr.operator]; - - allowIn |= (currentPrecedence < precedence); - - fragment = generateExpression(expr.left, { - precedence: currentPrecedence, - allowIn: allowIn, - allowCall: true - }); - - leftSource = fragment.toString(); - - if (leftSource.charAt(leftSource.length - 1) === '/' && isIdentifierPart(expr.operator.charAt(0))) { - result = [fragment, ' ', expr.operator]; - } else { - result = join(fragment, expr.operator); - } - - fragment = generateExpression(expr.right, { - precedence: currentPrecedence + 1, - allowIn: allowIn, - allowCall: true - }); - - if (expr.operator === '/' && fragment.toString().charAt(0) === '/') { - // If '/' concats with '/', it is interpreted as comment start - result.push(' ', fragment); - } else { - result = join(result, fragment); - } - - if (expr.operator === 'in' && !allowIn) { - result = ['(', result, ')']; - } else { - result = parenthesize(result, currentPrecedence, precedence); - } - - break; - - case Syntax.CallExpression: - result = [generateExpression(expr.callee, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true, - allowUnparenthesizedNew: false - })]; - - result.push('('); - for (i = 0, len = expr['arguments'].length; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - - if (!allowCall) { - result = ['(', result, ')']; - } else { - result = parenthesize(result, Precedence.Call, precedence); - } - break; - - case Syntax.NewExpression: - len = expr['arguments'].length; - allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; - - result = join( - 'new', - generateExpression(expr.callee, { - precedence: Precedence.New, - allowIn: true, - allowCall: false, - allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 - }) - ); - - if (!allowUnparenthesizedNew || parentheses || len > 0) { - result.push('('); - for (i = 0; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - } - - result = parenthesize(result, Precedence.New, precedence); - break; - - case Syntax.MemberExpression: - result = [generateExpression(expr.object, { - precedence: Precedence.Call, - allowIn: true, - allowCall: allowCall, - allowUnparenthesizedNew: false - })]; - - if (expr.computed) { - result.push('[', generateExpression(expr.property, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: allowCall - }), ']'); - } else { - if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { - fragment = toSourceNode(result).toString(); - if (fragment.indexOf('.') < 0) { - if (!/[eExX]/.test(fragment) && - !(fragment.length >= 2 && fragment.charCodeAt(0) === 48)) { // '0' - result.push('.'); - } - } - } - result.push('.', generateIdentifier(expr.property)); - } - - result = parenthesize(result, Precedence.Member, precedence); - break; - - case Syntax.UnaryExpression: - fragment = generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }); - - if (space === '') { - result = join(expr.operator, fragment); - } else { - result = [expr.operator]; - if (expr.operator.length > 2) { - // delete, void, typeof - // get `typeof []`, not `typeof[]` - result = join(result, fragment); - } else { - // Prevent inserting spaces between operator and argument if it is unnecessary - // like, `!cond` - leftSource = toSourceNode(result).toString(); - leftChar = leftSource.charAt(leftSource.length - 1); - rightChar = fragment.toString().charAt(0); - - if (((leftChar === '+' || leftChar === '-') && leftChar === rightChar) || (isIdentifierPart(leftChar) && isIdentifierPart(rightChar))) { - result.push(' ', fragment); - } else { - result.push(fragment); - } - } - } - result = parenthesize(result, Precedence.Unary, precedence); - break; - - case Syntax.YieldExpression: - if (expr.delegate) { - result = 'yield*'; - } else { - result = 'yield'; - } - if (expr.argument) { - result = join( - result, - generateExpression(expr.argument, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ); - } - break; - - case Syntax.UpdateExpression: - if (expr.prefix) { - result = parenthesize( - [ - expr.operator, - generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }) - ], - Precedence.Unary, - precedence - ); - } else { - result = parenthesize( - [ - generateExpression(expr.argument, { - precedence: Precedence.Postfix, - allowIn: true, - allowCall: true - }), - expr.operator - ], - Precedence.Postfix, - precedence - ); - } - break; - - case Syntax.FunctionExpression: - result = 'function'; - - if (expr.id) { - result = [result + ' ', - generateIdentifier(expr.id), - generateFunctionBody(expr)]; - } else { - result = [result + space, generateFunctionBody(expr)]; - } - - break; - - case Syntax.ArrayPattern: - case Syntax.ArrayExpression: - if (!expr.elements.length) { - result = '[]'; - break; - } - multiline = expr.elements.length > 1; - result = ['[', multiline ? newline : '']; - withIndent(function (indent) { - for (i = 0, len = expr.elements.length; i < len; i += 1) { - if (!expr.elements[i]) { - if (multiline) { - result.push(indent); - } - if (i + 1 === len) { - result.push(','); - } - } else { - result.push(multiline ? indent : '', generateExpression(expr.elements[i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - } - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', ']'); - break; - - case Syntax.Property: - if (expr.kind === 'get' || expr.kind === 'set') { - result = [ - expr.kind + ' ', - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - generateFunctionBody(expr.value) - ]; - } else { - if (expr.shorthand) { - result = generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - } else if (expr.method) { - result = []; - if (expr.value.generator) { - result.push('*'); - } - result.push(generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), generateFunctionBody(expr.value)); - } else { - result = [ - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ':' + space, - generateExpression(expr.value, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - } - } - break; - - case Syntax.ObjectExpression: - if (!expr.properties.length) { - result = '{}'; - break; - } - multiline = expr.properties.length > 1; - - withIndent(function () { - fragment = generateExpression(expr.properties[0], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - }); - }); - - if (!multiline) { - // issues 4 - // Do not transform from - // dejavu.Class.declare({ - // method2: function () {} - // }); - // to - // dejavu.Class.declare({method2: function () { - // }}); - if (!hasLineTerminator(toSourceNode(fragment).toString())) { - result = [ '{', space, fragment, space, '}' ]; - break; - } - } - - withIndent(function (indent) { - result = [ '{', newline, indent, fragment ]; - - if (multiline) { - result.push(',' + newline); - for (i = 1, len = expr.properties.length; i < len; i += 1) { - result.push(indent, generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - })); - if (i + 1 < len) { - result.push(',' + newline); - } - } - } - }); - - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(base, '}'); - break; - - case Syntax.ObjectPattern: - if (!expr.properties.length) { - result = '{}'; - break; - } - - multiline = false; - if (expr.properties.length === 1) { - property = expr.properties[0]; - if (property.value.type !== Syntax.Identifier) { - multiline = true; - } - } else { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - property = expr.properties[i]; - if (!property.shorthand) { - multiline = true; - break; - } - } - } - result = ['{', multiline ? newline : '' ]; - - withIndent(function (indent) { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - result.push(multiline ? indent : '', generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', '}'); - break; - - case Syntax.ThisExpression: - result = 'this'; - break; - - case Syntax.Identifier: - result = generateIdentifier(expr); - break; - - case Syntax.Literal: - if (expr.hasOwnProperty('raw') && parse) { - try { - raw = parse(expr.raw).body[0].expression; - if (raw.type === Syntax.Literal) { - if (raw.value === expr.value) { - result = expr.raw; - break; - } - } - } catch (e) { - // not use raw property - } - } - - if (expr.value === null) { - result = 'null'; - break; - } - - if (typeof expr.value === 'string') { - result = escapeString(expr.value); - break; - } - - if (typeof expr.value === 'number') { - result = generateNumber(expr.value); - break; - } - - if (typeof expr.value === 'boolean') { - result = expr.value ? 'true' : 'false'; - break; - } - - result = generateRegExp(expr.value); - break; - - case Syntax.ComprehensionExpression: - result = [ - '[', - generateExpression(expr.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - - if (expr.blocks) { - for (i = 0, len = expr.blocks.length; i < len; i += 1) { - fragment = generateExpression(expr.blocks[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - result = join(result, fragment); - } - } - - if (expr.filter) { - result = join(result, 'if' + space); - fragment = generateExpression(expr.filter, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - if (extra.moz.parenthesizedComprehensionBlock) { - result = join(result, [ '(', fragment, ')' ]); - } else { - result = join(result, fragment); - } - } - result.push(']'); - break; - - case Syntax.ComprehensionBlock: - if (expr.left.type === Syntax.VariableDeclaration) { - fragment = [ - expr.left.kind + ' ', - generateStatement(expr.left.declarations[0], { - allowIn: false - }) - ]; - } else { - fragment = generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - }); - } - - fragment = join(fragment, expr.of ? 'of' : 'in'); - fragment = join(fragment, generateExpression(expr.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - - if (extra.moz.parenthesizedComprehensionBlock) { - result = [ 'for' + space + '(', fragment, ')' ]; - } else { - result = join('for' + space, fragment); - } - break; - - default: - throw new Error('Unknown expression type: ' + expr.type); - } - - return toSourceNode(result, expr); - } - - function generateStatement(stmt, option) { - var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon; - - allowIn = true; - semicolon = ';'; - functionBody = false; - directiveContext = false; - if (option) { - allowIn = option.allowIn === undefined || option.allowIn; - if (!semicolons && option.semicolonOptional === true) { - semicolon = ''; - } - functionBody = option.functionBody; - directiveContext = option.directiveContext; - } - - switch (stmt.type) { - case Syntax.BlockStatement: - result = ['{', newline]; - - withIndent(function () { - for (i = 0, len = stmt.body.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.body[i], { - semicolonOptional: i === len - 1, - directiveContext: functionBody - })); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - - result.push(addIndent('}')); - break; - - case Syntax.BreakStatement: - if (stmt.label) { - result = 'break ' + stmt.label.name + semicolon; - } else { - result = 'break' + semicolon; - } - break; - - case Syntax.ContinueStatement: - if (stmt.label) { - result = 'continue ' + stmt.label.name + semicolon; - } else { - result = 'continue' + semicolon; - } - break; - - case Syntax.DirectiveStatement: - if (stmt.raw) { - result = stmt.raw + semicolon; - } else { - result = escapeDirective(stmt.directive) + semicolon; - } - break; - - case Syntax.DoWhileStatement: - // Because `do 42 while (cond)` is Syntax Error. We need semicolon. - result = join('do', maybeBlock(stmt.body)); - result = maybeBlockSuffix(stmt.body, result); - result = join(result, [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + semicolon - ]); - break; - - case Syntax.CatchClause: - withIndent(function () { - result = [ - 'catch' + space + '(', - generateExpression(stmt.param, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body)); - break; - - case Syntax.DebuggerStatement: - result = 'debugger' + semicolon; - break; - - case Syntax.EmptyStatement: - result = ';'; - break; - - case Syntax.ExpressionStatement: - result = [generateExpression(stmt.expression, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })]; - // 12.4 '{', 'function' is not allowed in this position. - // wrap expression with parentheses - fragment = toSourceNode(result).toString(); - if (fragment.charAt(0) === '{' || (fragment.slice(0, 8) === 'function' && ' ('.indexOf(fragment.charAt(8)) >= 0) || (directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) { - result = ['(', result, ')' + semicolon]; - } else { - result.push(semicolon); - } - break; - - case Syntax.VariableDeclarator: - if (stmt.init) { - result = [ - generateExpression(stmt.id, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space, - '=', - space, - generateExpression(stmt.init, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ]; - } else { - result = generateIdentifier(stmt.id); - } - break; - - case Syntax.VariableDeclaration: - result = [stmt.kind]; - // special path for - // var x = function () { - // }; - if (stmt.declarations.length === 1 && stmt.declarations[0].init && - stmt.declarations[0].init.type === Syntax.FunctionExpression) { - result.push(' ', generateStatement(stmt.declarations[0], { - allowIn: allowIn - })); - } else { - // VariableDeclarator is typed as Statement, - // but joined with comma (not LineTerminator). - // So if comment is attached to target node, we should specialize. - withIndent(function () { - node = stmt.declarations[0]; - if (extra.comment && node.leadingComments) { - result.push('\n', addIndent(generateStatement(node, { - allowIn: allowIn - }))); - } else { - result.push(' ', generateStatement(node, { - allowIn: allowIn - })); - } - - for (i = 1, len = stmt.declarations.length; i < len; i += 1) { - node = stmt.declarations[i]; - if (extra.comment && node.leadingComments) { - result.push(',' + newline, addIndent(generateStatement(node, { - allowIn: allowIn - }))); - } else { - result.push(',' + space, generateStatement(node, { - allowIn: allowIn - })); - } - } - }); - } - result.push(semicolon); - break; - - case Syntax.ThrowStatement: - result = [join( - 'throw', - generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }) - ), semicolon]; - break; - - case Syntax.TryStatement: - result = ['try', maybeBlock(stmt.block)]; - result = maybeBlockSuffix(stmt.block, result); - if (stmt.handlers) { - // old interface - for (i = 0, len = stmt.handlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.handlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.handlers[i].body, result); - } - } - } else { - // new interface - if (stmt.handler) { - result = join(result, generateStatement(stmt.handler)); - if (stmt.finalizer || stmt.guardedHandlers.length > 0) { - result = maybeBlockSuffix(stmt.handler.body, result); - } - } - - for (i = 0, len = stmt.guardedHandlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.guardedHandlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.guardedHandlers[i].body, result); - } - } - } - if (stmt.finalizer) { - result = join(result, ['finally', maybeBlock(stmt.finalizer)]); - } - break; - - case Syntax.SwitchStatement: - withIndent(function () { - result = [ - 'switch' + space + '(', - generateExpression(stmt.discriminant, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + space + '{' + newline - ]; - }); - if (stmt.cases) { - for (i = 0, len = stmt.cases.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.cases[i], {semicolonOptional: i === len - 1})); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - } - result.push(addIndent('}')); - break; - - case Syntax.SwitchCase: - withIndent(function () { - if (stmt.test) { - result = [ - join('case', generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - ':' - ]; - } else { - result = ['default:']; - } - - i = 0; - len = stmt.consequent.length; - if (len && stmt.consequent[0].type === Syntax.BlockStatement) { - fragment = maybeBlock(stmt.consequent[0]); - result.push(fragment); - i = 1; - } - - if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - - for (; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.consequent[i], {semicolonOptional: i === len - 1 && semicolon === ''})); - result.push(fragment); - if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - break; - - case Syntax.IfStatement: - withIndent(function () { - result = [ - 'if' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - if (stmt.alternate) { - result.push(maybeBlock(stmt.consequent)); - result = maybeBlockSuffix(stmt.consequent, result); - if (stmt.alternate.type === Syntax.IfStatement) { - result = join(result, ['else ', generateStatement(stmt.alternate, {semicolonOptional: semicolon === ''})]); - } else { - result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === ''))); - } - } else { - result.push(maybeBlock(stmt.consequent, semicolon === '')); - } - break; - - case Syntax.ForStatement: - withIndent(function () { - result = ['for' + space + '(']; - if (stmt.init) { - if (stmt.init.type === Syntax.VariableDeclaration) { - result.push(generateStatement(stmt.init, {allowIn: false})); - } else { - result.push(generateExpression(stmt.init, { - precedence: Precedence.Sequence, - allowIn: false, - allowCall: true - }), ';'); - } - } else { - result.push(';'); - } - - if (stmt.test) { - result.push(space, generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ';'); - } else { - result.push(';'); - } - - if (stmt.update) { - result.push(space, generateExpression(stmt.update, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ')'); - } else { - result.push(')'); - } - }); - - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - case Syntax.ForInStatement: - result = ['for' + space + '(']; - withIndent(function () { - if (stmt.left.type === Syntax.VariableDeclaration) { - withIndent(function () { - result.push(stmt.left.kind + ' ', generateStatement(stmt.left.declarations[0], { - allowIn: false - })); - }); - } else { - result.push(generateExpression(stmt.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - })); - } - - result = join(result, 'in'); - result = [join( - result, - generateExpression(stmt.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }) - ), ')']; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - case Syntax.LabeledStatement: - result = [stmt.label.name + ':', maybeBlock(stmt.body, semicolon === '')]; - break; - - case Syntax.Program: - len = stmt.body.length; - result = [safeConcatenation && len > 0 ? '\n' : '']; - for (i = 0; i < len; i += 1) { - fragment = addIndent( - generateStatement(stmt.body[i], { - semicolonOptional: !safeConcatenation && i === len - 1, - directiveContext: true - }) - ); - result.push(fragment); - if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - break; - - case Syntax.FunctionDeclaration: - result = [(stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function '), - generateIdentifier(stmt.id), - generateFunctionBody(stmt)]; - break; - - case Syntax.ReturnStatement: - if (stmt.argument) { - result = [join( - 'return', - generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }) - ), semicolon]; - } else { - result = ['return' + semicolon]; - } - break; - - case Syntax.WhileStatement: - withIndent(function () { - result = [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - case Syntax.WithStatement: - withIndent(function () { - result = [ - 'with' + space + '(', - generateExpression(stmt.object, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - - default: - throw new Error('Unknown statement type: ' + stmt.type); - } - - // Attach comments - - if (extra.comment) { - result = addCommentsToStatement(stmt, result); - } - - fragment = toSourceNode(result).toString(); - if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') { - result = toSourceNode(result).replaceRight(/\s+$/, ''); - } - - return toSourceNode(result, stmt); - } - - function generate(node, options) { - var defaultOptions = getDefaultOptions(), result, pair; - - if (options != null) { - // Obsolete options - // - // `options.indent` - // `options.base` - // - // Instead of them, we can use `option.format.indent`. - if (typeof options.indent === 'string') { - defaultOptions.format.indent.style = options.indent; - } - if (typeof options.base === 'number') { - defaultOptions.format.indent.base = options.base; - } - options = updateDeeply(defaultOptions, options); - indent = options.format.indent.style; - if (typeof options.base === 'string') { - base = options.base; - } else { - base = stringRepeat(indent, options.format.indent.base); - } - } else { - options = defaultOptions; - indent = options.format.indent.style; - base = stringRepeat(indent, options.format.indent.base); - } - json = options.format.json; - renumber = options.format.renumber; - hexadecimal = json ? false : options.format.hexadecimal; - quotes = json ? 'double' : options.format.quotes; - escapeless = options.format.escapeless; - if (options.format.compact) { - newline = space = indent = base = ''; - } else { - newline = '\n'; - space = ' '; - } - parentheses = options.format.parentheses; - semicolons = options.format.semicolons; - safeConcatenation = options.format.safeConcatenation; - directive = options.directive; - parse = json ? null : options.parse; - sourceMap = options.sourceMap; - extra = options; - - if (sourceMap) { - if (!exports.browser) { - // We assume environment is node.js - // And prevent from including source-map by browserify - SourceNode = require('source-map').SourceNode; - } else { - SourceNode = global.sourceMap.SourceNode; - } - } else { - SourceNode = SourceNodeMock; - } - - switch (node.type) { - case Syntax.BlockStatement: - case Syntax.BreakStatement: - case Syntax.CatchClause: - case Syntax.ContinueStatement: - case Syntax.DirectiveStatement: - case Syntax.DoWhileStatement: - case Syntax.DebuggerStatement: - case Syntax.EmptyStatement: - case Syntax.ExpressionStatement: - case Syntax.ForStatement: - case Syntax.ForInStatement: - case Syntax.FunctionDeclaration: - case Syntax.IfStatement: - case Syntax.LabeledStatement: - case Syntax.Program: - case Syntax.ReturnStatement: - case Syntax.SwitchStatement: - case Syntax.SwitchCase: - case Syntax.ThrowStatement: - case Syntax.TryStatement: - case Syntax.VariableDeclaration: - case Syntax.VariableDeclarator: - case Syntax.WhileStatement: - case Syntax.WithStatement: - result = generateStatement(node); - break; - - case Syntax.AssignmentExpression: - case Syntax.ArrayExpression: - case Syntax.ArrayPattern: - case Syntax.BinaryExpression: - case Syntax.CallExpression: - case Syntax.ConditionalExpression: - case Syntax.FunctionExpression: - case Syntax.Identifier: - case Syntax.Literal: - case Syntax.LogicalExpression: - case Syntax.MemberExpression: - case Syntax.NewExpression: - case Syntax.ObjectExpression: - case Syntax.ObjectPattern: - case Syntax.Property: - case Syntax.SequenceExpression: - case Syntax.ThisExpression: - case Syntax.UnaryExpression: - case Syntax.UpdateExpression: - case Syntax.YieldExpression: - - result = generateExpression(node, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - break; - - default: - throw new Error('Unknown node type: ' + node.type); - } - - if (!sourceMap) { - return result.toString(); - } - - pair = result.toStringWithSourceMap({ - file: options.file, - sourceRoot: options.sourceMapRoot - }); - - if (options.sourceMapWithCode) { - return pair; - } - return pair.map.toString(); - } - - FORMAT_MINIFY = { - indent: { - style: '', - base: 0 - }, - renumber: true, - hexadecimal: true, - quotes: 'auto', - escapeless: true, - compact: true, - parentheses: false, - semicolons: false - }; - - FORMAT_DEFAULTS = getDefaultOptions().format; - - // exports.version = require('./package.json').version; - exports.generate = generate; - exports.attachComments = estraverse.attachComments; - exports.browser = false; - exports.FORMAT_MINIFY = FORMAT_MINIFY; - exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS; -}()); -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/toolkit/devtools/escodegen/escodegen.worker.js b/toolkit/devtools/escodegen/escodegen.worker.js deleted file mode 100644 index 16aaa2901d3..00000000000 --- a/toolkit/devtools/escodegen/escodegen.worker.js +++ /dev/null @@ -1,5539 +0,0 @@ -let window = self; -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -/** - * Define a module along with a payload. - * @param {string} moduleName Name for the payload - * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec - * @param {function} payload Function with (require, exports, module) params - */ -function define(moduleName, deps, payload) { - if (typeof moduleName != "string") { - throw new TypeError('Expected string, got: ' + moduleName); - } - - if (arguments.length == 2) { - payload = deps; - } - - if (moduleName in define.modules) { - throw new Error("Module already defined: " + moduleName); - } - define.modules[moduleName] = payload; -}; - -/** - * The global store of un-instantiated modules - */ -define.modules = {}; - - -/** - * We invoke require() in the context of a Domain so we can have multiple - * sets of modules running separate from each other. - * This contrasts with JSMs which are singletons, Domains allows us to - * optionally load a CommonJS module twice with separate data each time. - * Perhaps you want 2 command lines with a different set of commands in each, - * for example. - */ -function Domain() { - this.modules = {}; - this._currentModule = null; -} - -(function () { - - /** - * Lookup module names and resolve them by calling the definition function if - * needed. - * There are 2 ways to call this, either with an array of dependencies and a - * callback to call when the dependencies are found (which can happen - * asynchronously in an in-page context) or with a single string an no callback - * where the dependency is resolved synchronously and returned. - * The API is designed to be compatible with the CommonJS AMD spec and - * RequireJS. - * @param {string[]|string} deps A name, or names for the payload - * @param {function|undefined} callback Function to call when the dependencies - * are resolved - * @return {undefined|object} The module required or undefined for - * array/callback method - */ - Domain.prototype.require = function(deps, callback) { - if (Array.isArray(deps)) { - var params = deps.map(function(dep) { - return this.lookup(dep); - }, this); - if (callback) { - callback.apply(null, params); - } - return undefined; - } - else { - return this.lookup(deps); - } - }; - - function normalize(path) { - var bits = path.split('/'); - var i = 1; - while (i < bits.length) { - if (bits[i] === '..') { - bits.splice(i-1, 1); - } else if (bits[i] === '.') { - bits.splice(i, 1); - } else { - i++; - } - } - return bits.join('/'); - } - - function join(a, b) { - a = a.trim(); - b = b.trim(); - if (/^\//.test(b)) { - return b; - } else { - return a.replace(/\/*$/, '/') + b; - } - } - - function dirname(path) { - var bits = path.split('/'); - bits.pop(); - return bits.join('/'); - } - - /** - * Lookup module names and resolve them by calling the definition function if - * needed. - * @param {string} moduleName A name for the payload to lookup - * @return {object} The module specified by aModuleName or null if not found. - */ - Domain.prototype.lookup = function(moduleName) { - if (/^\./.test(moduleName)) { - moduleName = normalize(join(dirname(this._currentModule), moduleName)); - } - - if (moduleName in this.modules) { - var module = this.modules[moduleName]; - return module; - } - - if (!(moduleName in define.modules)) { - throw new Error("Module not defined: " + moduleName); - } - - var module = define.modules[moduleName]; - - if (typeof module == "function") { - var exports = {}; - var previousModule = this._currentModule; - this._currentModule = moduleName; - module(this.require.bind(this), exports, { id: moduleName, uri: "" }); - this._currentModule = previousModule; - module = exports; - } - - // cache the resulting module object for next time - this.modules[moduleName] = module; - - return module; - }; - -}()); - -define.Domain = Domain; -define.globalDomain = new Domain(); -var require = define.globalDomain.require.bind(define.globalDomain); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-map-generator', ['require', 'exports', 'module' , 'source-map/base64-vlq', 'source-map/util', 'source-map/array-set'], function(require, exports, module) { - - var base64VLQ = require('./base64-vlq'); - var util = require('./util'); - var ArraySet = require('./array-set').ArraySet; - - /** - * An instance of the SourceMapGenerator represents a source map which is - * being built incrementally. To create a new one, you must pass an object - * with the following properties: - * - * - file: The filename of the generated source. - * - sourceRoot: An optional root for all URLs in this source map. - */ - function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._sources = new ArraySet(); - this._names = new ArraySet(); - this._mappings = []; - this._sourcesContents = null; - } - - SourceMapGenerator.prototype._version = 3; - - /** - * Creates a new SourceMapGenerator based on a SourceMapConsumer - * - * @param aSourceMapConsumer The SourceMap. - */ - SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - - if (mapping.source) { - newMapping.source = mapping.source; - if (sourceRoot) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - - if (mapping.name) { - newMapping.name = mapping.name; - } - } - - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - - /** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. - */ - SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - - this._validateMapping(generated, original, source, name); - - if (source && !this._sources.has(source)) { - this._sources.add(source); - } - - if (name && !this._names.has(name)) { - this._names.add(name); - } - - this._mappings.push({ - generatedLine: generated.line, - generatedColumn: generated.column, - originalLine: original != null && original.line, - originalColumn: original != null && original.column, - source: source, - name: name - }); - }; - - /** - * Set the source content for a source file. - */ - SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot) { - source = util.relative(this._sourceRoot, source); - } - - if (aSourceContent !== null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = {}; - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - - /** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - */ - SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (!aSourceFile) { - aSourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "aSourceFile" relative if an absolute Url is passed. - if (sourceRoot) { - aSourceFile = util.relative(sourceRoot, aSourceFile); - } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); - - // Find mappings for the "aSourceFile" - this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.originalLine) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.originalLine, - column: mapping.originalColumn - }); - if (original.source !== null) { - // Copy mapping - if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; - } - 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 - mapping.name = original.name; - } - } - } - - var source = mapping.source; - if (source && !newSources.has(source)) { - newSources.add(source); - } - - var name = mapping.name; - if (name && !newNames.has(name)) { - newNames.add(name); - } - - }, this); - this._sources = newSources; - this._names = newNames; - - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - if (sourceRoot) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - - /** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. - * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. - */ - SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aGenerated.line > 0 && aGenerated.column >= 0 - && !aOriginal && !aSource && !aName) { - // Case 1. - return; - } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal - && aGenerated.line > 0 && aGenerated.column >= 0 - && aOriginal.line > 0 && aOriginal.column >= 0 - && aSource) { - // Cases 2 and 3. - return; - } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ - generated: aGenerated, - source: aSource, - orginal: aOriginal, - name: aName - })); - } - }; - - /** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. - */ - SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var mapping; - - // The mappings must be guaranteed to be in sorted order before we start - // serializing them or else the generated line numbers (which are defined - // via the ';' separators) will be all messed up. Note: it might be more - // performant to maintain the sorting as we insert them, rather than as we - // serialize them, but the big O is the same either way. - this._mappings.sort(util.compareByGeneratedPositions); - - for (var i = 0, len = this._mappings.length; i < len; i++) { - mapping = this._mappings[i]; - - if (mapping.generatedLine !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generatedLine !== previousGeneratedLine) { - result += ';'; - previousGeneratedLine++; - } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { - continue; - } - result += ','; - } - } - - result += base64VLQ.encode(mapping.generatedColumn - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generatedColumn; - - 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.originalLine - 1 - - previousOriginalLine); - previousOriginalLine = mapping.originalLine - 1; - - result += base64VLQ.encode(mapping.originalColumn - - previousOriginalColumn); - previousOriginalColumn = mapping.originalColumn; - - if (mapping.name) { - result += base64VLQ.encode(this._names.indexOf(mapping.name) - - previousName); - previousName = this._names.indexOf(mapping.name); - } - } - } - - 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. - */ - SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - file: this._file, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._sourceRoot) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); - } - - return map; - }; - - /** - * Render the source map being generated to a string. - */ - SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this); - }; - - exports.SourceMapGenerator = SourceMapGenerator; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - * - * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java - * - * Copyright 2011 The Closure Compiler Authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/base64'], function(require, exports, module) { - - var base64 = require('./base64'); - - // A single base 64 digit can contain 6 bits of data. For the base 64 variable - // length quantities we use in the source map spec, the first bit is the sign, - // the next four bits are the actual value, and the 6th bit is the - // continuation bit. The continuation bit tells us whether there are more - // digits in this value following this digit. - // - // Continuation - // | Sign - // | | - // V V - // 101011 - - var VLQ_BASE_SHIFT = 5; - - // binary: 100000 - var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - - // binary: 011111 - var VLQ_BASE_MASK = VLQ_BASE - 1; - - // binary: 100000 - var VLQ_CONTINUATION_BIT = VLQ_BASE; - - /** - * Converts from a two-complement value to a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) - */ - function toVLQSigned(aValue) { - return aValue < 0 - ? ((-aValue) << 1) + 1 - : (aValue << 1) + 0; - } - - /** - * Converts to a two-complement value from a value where the sign bit is - * is placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 - */ - function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative - ? -shifted - : shifted; - } - - /** - * Returns the base 64 VLQ encoded value. - */ - exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; - - var vlq = toVLQSigned(aValue); - - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - // There are still more digits in this value, so we must make sure the - // continuation bit is marked. - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - - return encoded; - }; - - /** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string. - */ - exports.decode = function base64VLQ_decode(aStr) { - var i = 0; - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - - do { - if (i >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); - } - digit = base64.decode(aStr.charAt(i++)); - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - return { - value: fromVLQSigned(result), - rest: aStr.slice(i) - }; - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/base64', ['require', 'exports', 'module' , ], function(require, exports, module) { - - var charToIntMap = {}; - var intToCharMap = {}; - - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - .split('') - .forEach(function (ch, index) { - charToIntMap[ch] = index; - intToCharMap[index] = ch; - }); - - /** - * Encode an integer in the range of 0 to 63 to a single base 64 digit. - */ - exports.encode = function base64_encode(aNumber) { - if (aNumber in intToCharMap) { - return intToCharMap[aNumber]; - } - throw new TypeError("Must be between 0 and 63: " + aNumber); - }; - - /** - * Decode a single base 64 digit to an integer. - */ - exports.decode = function base64_decode(aChar) { - if (aChar in charToIntMap) { - return charToIntMap[aChar]; - } - throw new TypeError("Not a valid base 64 digit: " + aChar); - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) { - - /** - * This is a helper function for getting values from parameter/options - * objects. - * - * @param args The object we are extracting values from - * @param name The name of the property we are getting. - * @param defaultValue An optional value to return if the property is missing - * from the object. If this is not specified and the property is missing, an - * error will be thrown. - */ - function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } - } - exports.getArg = getArg; - - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - var dataUrlRegexp = /^data:.+\,.+/; - - function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] - }; - } - exports.urlParse = urlParse; - - 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; - - if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { - return aPath; - } - - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); - } - - return aRoot.replace(/\/$/, '') + '/' + aPath; - } - exports.join = join; - - /** - * Because behavior goes wacky when you set `__proto__` on objects, we - * have to prefix all the strings in our set with an arbitrary character. - * - * See https://github.com/mozilla/source-map/pull/31 and - * https://github.com/mozilla/source-map/issues/30 - * - * @param String aStr - */ - function toSetString(aStr) { - return '$' + aStr; - } - exports.toSetString = toSetString; - - function fromSetString(aStr) { - return aStr.substr(1); - } - exports.fromSetString = fromSetString; - - function relative(aRoot, aPath) { - aRoot = aRoot.replace(/\/$/, ''); - - var url = urlParse(aRoot); - if (aPath.charAt(0) == "/" && url && url.path == "/") { - return aPath.slice(1); - } - - return aPath.indexOf(aRoot + '/') === 0 - ? aPath.substr(aRoot.length + 1) - : aPath; - } - exports.relative = relative; - - 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; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) { - - var util = require('./util'); - - /** - * A data structure which is a combination of an array and a set. Adding a new - * member is O(1), testing for membership is O(1), and finding the index of an - * element is O(1). Removing elements from the set is not supported. Only - * strings are supported for membership. - */ - function ArraySet() { - this._array = []; - this._set = {}; - } - - /** - * Static method for creating ArraySet instances from an existing array. - */ - ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); - } - return set; - }; - - /** - * Add the given string to this set. - * - * @param String aStr - */ - ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var isDuplicate = this.has(aStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - this._set[util.toSetString(aStr)] = idx; - } - }; - - /** - * Is the given string a member of this set? - * - * @param String aStr - */ - ArraySet.prototype.has = function ArraySet_has(aStr) { - return Object.prototype.hasOwnProperty.call(this._set, - util.toSetString(aStr)); - }; - - /** - * What is the index of the given string in the array? - * - * @param String aStr - */ - ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (this.has(aStr)) { - return this._set[util.toSetString(aStr)]; - } - throw new Error('"' + aStr + '" is not in the set.'); - }; - - /** - * What is the element at the given index? - * - * @param Number aIdx - */ - ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); - }; - - /** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ - ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); - }; - - exports.ArraySet = ArraySet; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'source-map/util', 'source-map/binary-search', 'source-map/array-set', 'source-map/base64-vlq'], function(require, exports, module) { - - var util = require('./util'); - var binarySearch = require('./binary-search'); - var ArraySet = require('./array-set').ArraySet; - var base64VLQ = require('./base64-vlq'); - - /** - * A SourceMapConsumer instance represents a parsed source map which we can - * query for information about the original file positions by giving it a file - * position in the generated source. - * - * The only parameter is the raw source map (either as a JSON string, or - * already parsed to an object). According to the spec, source maps have the - * following attributes: - * - * - version: Which version of the source map spec this map is following. - * - sources: An array of URLs to the original source files. - * - names: An array of identifiers which can be referrenced by individual mappings. - * - sourceRoot: Optional. The URL root from which all sources are relative. - * - sourcesContent: Optional. An array of contents of the original source files. - * - mappings: A string of base64 VLQs which contain the actual mappings. - * - file: The generated file this source map is associated with. - * - * Here is an example source map, taken from the source map spec[0]: - * - * { - * version : 3, - * file: "out.js", - * sourceRoot : "", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AA,AB;;ABCDE;" - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# - */ - function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - var names = util.getArg(sourceMap, 'names'); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - - if (version !== this._version) { - throw new Error('Unsupported version: ' + version); - } - - // 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; - - // `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); - } - - /** - * 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. - */ - SourceMapConsumer.prototype._version = 3; - - /** - * The list of original sources. - */ - Object.defineProperty(SourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot ? util.join(this.sourceRoot, s) : s; - }, this); - } - }); - - /** - * Parse the mappings in a string in to a data structure which we can easily - * query (an ordered list in this._generatedMappings). - */ - SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var mappingSeparator = /^[,;]/; - var str = aStr; - var mapping; - var temp; - - while (str.length > 0) { - if (str.charAt(0) === ';') { - generatedLine++; - str = str.slice(1); - previousGeneratedColumn = 0; - } - else if (str.charAt(0) === ',') { - str = str.slice(1); - } - else { - mapping = {}; - mapping.generatedLine = generatedLine; - - // Generated column. - temp = base64VLQ.decode(str); - mapping.generatedColumn = previousGeneratedColumn + temp.value; - previousGeneratedColumn = mapping.generatedColumn; - str = temp.rest; - - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original source. - temp = base64VLQ.decode(str); - mapping.source = this._sources.at(previousSource + temp.value); - previousSource += temp.value; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source, but no line and column'); - } - - // Original line. - temp = base64VLQ.decode(str); - mapping.originalLine = previousOriginalLine + temp.value; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source and line, but no column'); - } - - // Original column. - temp = base64VLQ.decode(str); - mapping.originalColumn = previousOriginalColumn + temp.value; - previousOriginalColumn = mapping.originalColumn; - str = temp.rest; - - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - // Original name. - temp = base64VLQ.decode(str); - mapping.name = this._names.at(previousName + temp.value); - previousName += temp.value; - str = temp.rest; - } - } - - this._generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - this._originalMappings.push(mapping); - } - } - } - - this._originalMappings.sort(util.compareByOriginalPositions); - }; - - /** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ - SourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, - aColumnName, aComparator) { - // To return the position we are searching for, we must first find the - // mapping for the given position and then return the opposite position it - // points to. Because the mappings are sorted, we can use binary search to - // find the best mapping. - - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); - } - - return binarySearch.search(aNeedle, aMappings, aComparator); - }; - - /** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ - SourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - - var mapping = this._findMapping(needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositions); - - if (mapping) { - var source = util.getArg(mapping, 'source', null); - if (source && this.sourceRoot) { - source = util.join(this.sourceRoot, source); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: util.getArg(mapping, 'name', null) - }; - } - - return { - source: null, - line: null, - column: null, - name: null - }; - }; - - /** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * availible. - */ - SourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource) { - if (!this.sourcesContent) { - return null; - } - - if (this.sourceRoot) { - 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.'); - }; - - /** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ - SourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - - if (this.sourceRoot) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - - var mapping = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions); - - if (mapping) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null) - }; - } - - return { - line: null, - column: null - }; - }; - - SourceMapConsumer.GENERATED_ORDER = 1; - SourceMapConsumer.ORIGINAL_ORDER = 2; - - /** - * Iterate over each mapping between an original source/line/column and a - * generated line/column in this source map. - * - * @param Function aCallback - * The function that is called with each mapping. - * @param Object aContext - * Optional. If specified, this object will be the value of `this` every - * time that `aCallback` is called. - * @param aOrder - * Either `SourceMapConsumer.GENERATED_ORDER` or - * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to - * iterate over the mappings sorted by the generated file's line/column - * order or the original's source/line/column order, respectively. Defaults to - * `SourceMapConsumer.GENERATED_ORDER`. - */ - SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error("Unknown order of iteration."); - } - - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source; - if (source && sourceRoot) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name - }; - }).forEach(aCallback, context); - }; - - exports.SourceMapConsumer = SourceMapConsumer; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/binary-search', ['require', 'exports', 'module' , ], function(require, exports, module) { - - /** - * Recursive implementation of binary search. - * - * @param aLow Indices here and lower do not contain the needle. - * @param aHigh Indices here and higher do not contain the needle. - * @param aNeedle The element being searched for. - * @param aHaystack The non-empty array being searched. - * @param aCompare Function which takes two elements and returns -1, 0, or 1. - */ - function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { - // This function terminates when one of the following is true: - // - // 1. We find the exact element we are looking for. - // - // 2. We did not find the exact element, but we can return the next - // closest element that is less than that element. - // - // 3. We did not find the exact element, and there is no next-closest - // element which is less than the one we are searching for, so we - // return null. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); - if (cmp === 0) { - // Found the element we are looking for. - return aHaystack[mid]; - } - else if (cmp > 0) { - // aHaystack[mid] is greater than our needle. - if (aHigh - mid > 1) { - // The element is in the upper half. - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); - } - // We did not find an exact match, return the next closest one - // (termination case 2). - return aHaystack[mid]; - } - else { - // aHaystack[mid] is less than our needle. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); - } - // The exact needle element was not found in this haystack. Determine if - // we are in termination case (2) or (3) and return the appropriate thing. - return aLow < 0 - ? null - : aHaystack[aLow]; - } - } - - /** - * This is an implementation of binary search which will always try and return - * the next lowest value checked if there is no exact hit. This is because - * mappings between original and generated line/col pairs are single points, - * and there is an implicit region between each of them, so a miss just means - * that you aren't on the very start of a region. - * - * @param aNeedle The element you are looking for. - * @param aHaystack The array that is being searched. - * @param aCompare A function which takes the needle and an element in the - * array and returns -1, 0, or 1 depending on whether the needle is less - * than, equal to, or greater than the element, respectively. - */ - exports.search = function search(aNeedle, aHaystack, aCompare) { - return aHaystack.length > 0 - ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) - : null; - }; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) { - - var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; - var util = require('./util'); - - /** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ - function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine === undefined ? null : aLine; - this.column = aColumn === undefined ? null : aColumn; - this.source = aSource === undefined ? null : aSource; - this.name = aName === undefined ? null : aName; - if (aChunks != null) this.add(aChunks); - } - - /** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - */ - SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); - - // The generated code - // Processed fragments are removed from this array. - var remainingLines = aGeneratedCode.split('\n'); - - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; - - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping === null) { - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(remainingLines.shift() + "\n"); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - } else { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - var code = ""; - // Associate full lines with "lastMapping" - do { - code += remainingLines.shift() + "\n"; - lastGeneratedLine++; - lastGeneratedColumn = 0; - } while (lastGeneratedLine < mapping.generatedLine); - // When we reached the correct line, we add code until we - // reach the correct column too. - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - code += nextLine.substr(0, mapping.generatedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - // Create the SourceNode. - addMappingWithCode(lastMapping, code); - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[0]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - } - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - // Associate the remaining code in the current line with "lastMapping" - // and add the remaining lines without any mapping - addMappingWithCode(lastMapping, remainingLines.join("\n")); - - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - node.setSourceContent(sourceFile, content); - } - }); - - return node; - - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - mapping.source, - code, - mapping.name)); - } - } - }; - - /** - * Add a chunk of generated JS to this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ - SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); - } - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; - }; - - /** - * Add a chunk of generated JS to the beginning of this source node. - * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. - */ - SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } - else if (aChunk instanceof SourceNode || typeof aChunk === "string") { - this.children.unshift(aChunk); - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); - } - return this; - }; - - /** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk instanceof SourceNode) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { - aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); - } - } - } - }; - - /** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ - SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; - }; - - /** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ - SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild instanceof SourceNode) { - lastChild.replaceRight(aPattern, aReplacement); - } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } - else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; - }; - - /** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file - */ - SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - - /** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. - */ - SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { - if (this.children[i] instanceof SourceNode) { - this.children[i].walkSourceContents(aFn); - } - } - - 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]]); - } - }; - - /** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. - */ - SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; - }; - - /** - * Returns the string representation of this source node along with a source - * map. - */ - SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - 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) { - 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({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - chunk.split('').forEach(function (ch) { - if (ch === '\n') { - generated.line++; - generated.column = 0; - } else { - generated.column++; - } - }); - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - - return { code: generated.code, map: map }; - }; - - exports.SourceNode = SourceNode; - -}); -/* -*- Mode: js; js-indent-level: 2; -*- */ -/////////////////////////////////////////////////////////////////////////////// - -window.sourceMap = { - SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, - SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, - SourceNode: require('source-map/source-node').SourceNode -}; -// Generated by CommonJS Everywhere 0.8.1 -(function (global) { - function require(file, parentModule) { - if ({}.hasOwnProperty.call(require.cache, file)) - return require.cache[file]; - var resolved = require.resolve(file); - if (!resolved) - throw new Error('Failed to resolve module ' + file); - var module$ = { - id: file, - require: require, - filename: file, - exports: {}, - loaded: false, - parent: parentModule, - children: [] - }; - if (parentModule) - parentModule.children.push(module$); - var dirname = file.slice(0, file.lastIndexOf('/') + 1); - require.cache[file] = module$.exports; - resolved.call(module$.exports, module$, module$.exports, dirname, file); - module$.loaded = true; - return require.cache[file] = module$.exports; - } - require.modules = {}; - require.cache = {}; - require.resolve = function (file) { - return {}.hasOwnProperty.call(require.modules, file) ? require.modules[file] : void 0; - }; - require.define = function (file, fn) { - require.modules[file] = fn; - }; - var process = function () { - var cwd = '/'; - return { - title: 'browser', - version: 'v0.10.5', - browser: true, - env: {}, - argv: [], - nextTick: global.setImmediate || function (fn) { - setTimeout(fn, 0); - }, - cwd: function () { - return cwd; - }, - chdir: function (dir) { - cwd = dir; - } - }; - }(); - require.define('/tools/entry-point.js', function (module, exports, __dirname, __filename) { - (function () { - 'use strict'; - global.escodegen = require('/escodegen.js', module); - escodegen.browser = true; - }()); - }); - require.define('/escodegen.js', function (module, exports, __dirname, __filename) { - (function () { - 'use strict'; - var Syntax, Precedence, BinaryPrecedence, Regex, SourceNode, estraverse, isArray, base, indent, json, renumber, hexadecimal, quotes, escapeless, newline, space, parentheses, semicolons, safeConcatenation, directive, extra, parse, sourceMap, FORMAT_MINIFY, FORMAT_DEFAULTS; - estraverse = require('/node_modules/estraverse/estraverse.js', module); - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrayPattern: 'ArrayPattern', - ArrowFunctionExpression: 'ArrowFunctionExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ComprehensionBlock: 'ComprehensionBlock', - ComprehensionExpression: 'ComprehensionExpression', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - ObjectPattern: 'ObjectPattern', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - Precedence = { - Sequence: 0, - Assignment: 1, - Conditional: 2, - ArrowFunction: 2, - LogicalOR: 3, - LogicalAND: 4, - BitwiseOR: 5, - BitwiseXOR: 6, - BitwiseAND: 7, - Equality: 8, - Relational: 9, - BitwiseSHIFT: 10, - Additive: 11, - Multiplicative: 12, - Unary: 13, - Postfix: 14, - Call: 15, - New: 16, - Member: 17, - Primary: 18 - }; - BinaryPrecedence = { - '||': Precedence.LogicalOR, - '&&': Precedence.LogicalAND, - '|': Precedence.BitwiseOR, - '^': Precedence.BitwiseXOR, - '&': Precedence.BitwiseAND, - '==': Precedence.Equality, - '!=': Precedence.Equality, - '===': Precedence.Equality, - '!==': Precedence.Equality, - 'is': Precedence.Equality, - 'isnt': Precedence.Equality, - '<': Precedence.Relational, - '>': Precedence.Relational, - '<=': Precedence.Relational, - '>=': Precedence.Relational, - 'in': Precedence.Relational, - 'instanceof': Precedence.Relational, - '<<': Precedence.BitwiseSHIFT, - '>>': Precedence.BitwiseSHIFT, - '>>>': Precedence.BitwiseSHIFT, - '+': Precedence.Additive, - '-': Precedence.Additive, - '*': Precedence.Multiplicative, - '%': Precedence.Multiplicative, - '/': Precedence.Multiplicative - }; - Regex = { 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]') }; - function getDefaultOptions() { - return { - indent: null, - base: null, - parse: null, - comment: false, - format: { - indent: { - style: ' ', - base: 0, - adjustMultilineComment: false - }, - newline: '\n', - space: ' ', - json: false, - renumber: false, - hexadecimal: false, - quotes: 'single', - escapeless: false, - compact: false, - parentheses: true, - semicolons: true, - safeConcatenation: false - }, - moz: { - starlessGenerator: false, - parenthesizedComprehensionBlock: false - }, - sourceMap: null, - sourceMapRoot: null, - sourceMapWithCode: false, - directive: false, - verbatim: null - }; - } - function stringToArray(str) { - var length = str.length, result = [], i; - for (i = 0; i < length; i += 1) { - result[i] = str.charAt(i); - } - return result; - } - function stringRepeat(str, num) { - var result = ''; - for (num |= 0; num > 0; num >>>= 1, str += str) { - if (num & 1) { - result += str; - } - } - return result; - } - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - function SourceNodeMock(line, column, filename, chunk) { - var result = []; - function flatten(input) { - var i, iz; - if (isArray(input)) { - for (i = 0, iz = input.length; i < iz; ++i) { - flatten(input[i]); - } - } else if (input instanceof SourceNodeMock) { - result.push(input); - } else if (typeof input === 'string' && input) { - result.push(input); - } - } - flatten(chunk); - this.children = result; - } - SourceNodeMock.prototype.toString = function toString() { - var res = '', i, iz, node; - for (i = 0, iz = this.children.length; i < iz; ++i) { - node = this.children[i]; - if (node instanceof SourceNodeMock) { - res += node.toString(); - } else { - res += node; - } - } - return res; - }; - SourceNodeMock.prototype.replaceRight = function replaceRight(pattern, replacement) { - var last = this.children[this.children.length - 1]; - if (last instanceof SourceNodeMock) { - last.replaceRight(pattern, replacement); - } else if (typeof last === 'string') { - this.children[this.children.length - 1] = last.replace(pattern, replacement); - } else { - this.children.push(''.replace(pattern, replacement)); - } - return this; - }; - SourceNodeMock.prototype.join = function join(sep) { - var i, iz, result; - result = []; - iz = this.children.length; - if (iz > 0) { - for (i = 0, iz -= 1; i < iz; ++i) { - result.push(this.children[i], sep); - } - result.push(this.children[iz]); - this.children = result; - } - return this; - }; - function hasLineTerminator(str) { - return /[\r\n]/g.test(str); - } - function endsWithLineTerminator(str) { - var ch = str.charAt(str.length - 1); - return ch === '\r' || ch === '\n'; - } - function updateDeeply(target, override) { - var key, val; - function isHashObject(target) { - return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp); - } - for (key in override) { - if (override.hasOwnProperty(key)) { - val = override[key]; - if (isHashObject(val)) { - if (isHashObject(target[key])) { - updateDeeply(target[key], val); - } else { - target[key] = updateDeeply({}, val); - } - } else { - target[key] = val; - } - } - } - return target; - } - function generateNumber(value) { - var result, point, temp, exponent, pos; - if (value !== value) { - throw new Error('Numeric literal whose value is NaN'); - } - if (value < 0 || value === 0 && 1 / value < 0) { - throw new Error('Numeric literal whose value is negative'); - } - if (value === 1 / 0) { - return json ? 'null' : renumber ? '1e400' : '1e+400'; - } - result = '' + value; - if (!renumber || result.length < 3) { - return result; - } - point = result.indexOf('.'); - if (!json && result.charAt(0) === '0' && point === 1) { - point = 0; - result = result.slice(1); - } - temp = result; - result = result.replace('e+', 'e'); - exponent = 0; - if ((pos = temp.indexOf('e')) > 0) { - exponent = +temp.slice(pos + 1); - temp = temp.slice(0, pos); - } - if (point >= 0) { - exponent -= temp.length - point - 1; - temp = +(temp.slice(0, point) + temp.slice(point + 1)) + ''; - } - pos = 0; - while (temp.charAt(temp.length + pos - 1) === '0') { - pos -= 1; - } - if (pos !== 0) { - exponent -= pos; - temp = temp.slice(0, pos); - } - if (exponent !== 0) { - temp += 'e' + exponent; - } - if ((temp.length < result.length || hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length) && +temp === value) { - result = temp; - } - return result; - } - function escapeRegExpCharacter(ch, previousIsBackslash) { - if ((ch & ~1) === 8232) { - return (previousIsBackslash ? 'u' : '\\u') + (ch === 8232 ? '2028' : '2029'); - } else if (ch === 10 || ch === 13) { - return (previousIsBackslash ? '' : '\\') + (ch === 10 ? 'n' : 'r'); - } - return String.fromCharCode(ch); - } - function generateRegExp(reg) { - var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash; - result = reg.toString(); - if (reg.source) { - match = result.match(/\/([^/]*)$/); - if (!match) { - return result; - } - flags = match[1]; - result = ''; - characterInBrack = false; - previousIsBackslash = false; - for (i = 0, iz = reg.source.length; i < iz; ++i) { - ch = reg.source.charCodeAt(i); - if (!previousIsBackslash) { - if (characterInBrack) { - if (ch === 93) { - characterInBrack = false; - } - } else { - if (ch === 47) { - result += '\\'; - } else if (ch === 91) { - characterInBrack = true; - } - } - result += escapeRegExpCharacter(ch, previousIsBackslash); - previousIsBackslash = ch === 92; - } else { - result += escapeRegExpCharacter(ch, previousIsBackslash); - previousIsBackslash = false; - } - } - return '/' + result + '/' + flags; - } - return result; - } - function escapeAllowedCharacter(ch, next) { - var code = ch.charCodeAt(0), hex = code.toString(16), result = '\\'; - switch (ch) { - case '\b': - result += 'b'; - break; - case '\f': - result += 'f'; - break; - case '\t': - result += 't'; - break; - default: - if (json || code > 255) { - result += 'u' + '0000'.slice(hex.length) + hex; - } else if (ch === '\0' && '0123456789'.indexOf(next) < 0) { - result += '0'; - } else if (ch === '\x0B') { - result += 'x0B'; - } else { - result += 'x' + '00'.slice(hex.length) + hex; - } - break; - } - return result; - } - function escapeDisallowedCharacter(ch) { - var result = '\\'; - switch (ch) { - case '\\': - result += '\\'; - break; - case '\n': - result += 'n'; - break; - case '\r': - result += 'r'; - break; - case '\u2028': - result += 'u2028'; - break; - case '\u2029': - result += 'u2029'; - break; - default: - throw new Error('Incorrectly classified character'); - } - return result; - } - function escapeDirective(str) { - var i, iz, ch, buf, quote; - buf = str; - if (typeof buf[0] === 'undefined') { - buf = stringToArray(buf); - } - quote = quotes === 'double' ? '"' : "'"; - for (i = 0, iz = buf.length; i < iz; i += 1) { - ch = buf[i]; - if (ch === "'") { - quote = '"'; - break; - } else if (ch === '"') { - quote = "'"; - break; - } else if (ch === '\\') { - i += 1; - } - } - return quote + str + quote; - } - function escapeString(str) { - var result = '', i, len, ch, singleQuotes = 0, doubleQuotes = 0, single; - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if (ch === "'") { - singleQuotes += 1; - } else if (ch === '"') { - doubleQuotes += 1; - } else if (ch === '/' && json) { - result += '\\'; - } else if ('\\\n\r\u2028\u2029'.indexOf(ch) >= 0) { - result += escapeDisallowedCharacter(ch); - continue; - } else if (json && ch < ' ' || !(json || escapeless || ch >= ' ' && ch <= '~')) { - result += escapeAllowedCharacter(ch, str[i + 1]); - continue; - } - result += ch; - } - single = !(quotes === 'double' || quotes === 'auto' && doubleQuotes < singleQuotes); - str = result; - result = single ? "'" : '"'; - if (typeof str[0] === 'undefined') { - str = stringToArray(str); - } - for (i = 0, len = str.length; i < len; i += 1) { - ch = str[i]; - if (ch === "'" && single || ch === '"' && !single) { - result += '\\'; - } - result += ch; - } - return result + (single ? "'" : '"'); - } - function isWhiteSpace(ch) { - return '\t\x0B\f \xa0'.indexOf(ch) >= 0 || ch.charCodeAt(0) >= 5760 && '\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff'.indexOf(ch) >= 0; - } - function isLineTerminator(ch) { - return '\n\r\u2028\u2029'.indexOf(ch) >= 0; - } - function isIdentifierPart(ch) { - return ch === '$' || ch === '_' || ch === '\\' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9' || ch.charCodeAt(0) >= 128 && Regex.NonAsciiIdentifierPart.test(ch); - } - function isDecimalDigit(ch) { - return ch >= 48 && ch <= 57; - } - function toSourceNode(generated, node) { - if (node == null) { - if (generated instanceof SourceNode) { - return generated; - } else { - node = {}; - } - } - if (node.loc == null) { - return new SourceNode(null, null, sourceMap, generated, node.name || null); - } - return new SourceNode(node.loc.start.line, node.loc.start.column, sourceMap === true ? node.loc.source || null : sourceMap, generated, node.name || null); - } - function noEmptySpace() { - return space ? space : ' '; - } - function join(left, right) { - var leftSource = toSourceNode(left).toString(), rightSource = toSourceNode(right).toString(), leftChar = leftSource.charAt(leftSource.length - 1), rightChar = rightSource.charAt(0); - if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar) || leftChar === '/' && rightChar === 'i') { - return [ - left, - noEmptySpace(), - right - ]; - } else if (isWhiteSpace(leftChar) || isLineTerminator(leftChar) || isWhiteSpace(rightChar) || isLineTerminator(rightChar)) { - return [ - left, - right - ]; - } - return [ - left, - space, - right - ]; - } - function addIndent(stmt) { - return [ - base, - stmt - ]; - } - function withIndent(fn) { - var previousBase, result; - previousBase = base; - base += indent; - result = fn.call(this, base); - base = previousBase; - return result; - } - function calculateSpaces(str) { - var i; - for (i = str.length - 1; i >= 0; i -= 1) { - if (isLineTerminator(str.charAt(i))) { - break; - } - } - return str.length - 1 - i; - } - function adjustMultilineComment(value, specialBase) { - var array, i, len, line, j, spaces, previousBase; - array = value.split(/\r\n|[\r\n]/); - spaces = Number.MAX_VALUE; - for (i = 1, len = array.length; i < len; i += 1) { - line = array[i]; - j = 0; - while (j < line.length && isWhiteSpace(line[j])) { - j += 1; - } - if (spaces > j) { - spaces = j; - } - } - if (typeof specialBase !== 'undefined') { - previousBase = base; - if (array[1][spaces] === '*') { - specialBase += ' '; - } - base = specialBase; - } else { - if (spaces & 1) { - spaces -= 1; - } - previousBase = base; - } - for (i = 1, len = array.length; i < len; i += 1) { - array[i] = toSourceNode(addIndent(array[i].slice(spaces))).join(''); - } - base = previousBase; - return array.join('\n'); - } - function generateComment(comment, specialBase) { - if (comment.type === 'Line') { - if (endsWithLineTerminator(comment.value)) { - return '//' + comment.value; - } else { - return '//' + comment.value + '\n'; - } - } - if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) { - return adjustMultilineComment('/*' + comment.value + '*/', specialBase); - } - return '/*' + comment.value + '*/'; - } - function addCommentsToStatement(stmt, result) { - var i, len, comment, save, tailingToStatement, specialBase, fragment; - if (stmt.leadingComments && stmt.leadingComments.length > 0) { - save = result; - comment = stmt.leadingComments[0]; - result = []; - if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) { - result.push('\n'); - } - result.push(generateComment(comment)); - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push('\n'); - } - for (i = 1, len = stmt.leadingComments.length; i < len; i += 1) { - comment = stmt.leadingComments[i]; - fragment = [generateComment(comment)]; - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - fragment.push('\n'); - } - result.push(addIndent(fragment)); - } - result.push(addIndent(save)); - } - if (stmt.trailingComments) { - tailingToStatement = !endsWithLineTerminator(toSourceNode(result).toString()); - specialBase = stringRepeat(' ', calculateSpaces(toSourceNode([ - base, - result, - indent - ]).toString())); - for (i = 0, len = stmt.trailingComments.length; i < len; i += 1) { - comment = stmt.trailingComments[i]; - if (tailingToStatement) { - if (i === 0) { - result = [ - result, - indent - ]; - } else { - result = [ - result, - specialBase - ]; - } - result.push(generateComment(comment, specialBase)); - } else { - result = [ - result, - addIndent(generateComment(comment)) - ]; - } - if (i !== len - 1 && !endsWithLineTerminator(toSourceNode(result).toString())) { - result = [ - result, - '\n' - ]; - } - } - } - return result; - } - function parenthesize(text, current, should) { - if (current < should) { - return [ - '(', - text, - ')' - ]; - } - return text; - } - function maybeBlock(stmt, semicolonOptional, functionBody) { - var result, noLeadingComment; - noLeadingComment = !extra.comment || !stmt.leadingComments; - if (stmt.type === Syntax.BlockStatement && noLeadingComment) { - return [ - space, - generateStatement(stmt, { functionBody: functionBody }) - ]; - } - if (stmt.type === Syntax.EmptyStatement && noLeadingComment) { - return ';'; - } - withIndent(function () { - result = [ - newline, - addIndent(generateStatement(stmt, { - semicolonOptional: semicolonOptional, - functionBody: functionBody - })) - ]; - }); - return result; - } - function maybeBlockSuffix(stmt, result) { - var ends = endsWithLineTerminator(toSourceNode(result).toString()); - if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) { - return [ - result, - space - ]; - } - if (ends) { - return [ - result, - base - ]; - } - return [ - result, - newline, - base - ]; - } - function generateVerbatim(expr, option) { - var i, result; - result = expr[extra.verbatim].split(/\r\n|\n/); - for (i = 1; i < result.length; i++) { - result[i] = newline + base + result[i]; - } - result = parenthesize(result, Precedence.Sequence, option.precedence); - return toSourceNode(result, expr); - } - function generateIdentifier(node) { - return toSourceNode(node.name, node); - } - function generateFunctionBody(node) { - var result, i, len, expr, arrow; - arrow = node.type === Syntax.ArrowFunctionExpression; - if (arrow && node.params.length === 1 && node.params[0].type === Syntax.Identifier) { - result = [generateIdentifier(node.params[0])]; - } else { - result = ['(']; - for (i = 0, len = node.params.length; i < len; i += 1) { - result.push(generateIdentifier(node.params[i])); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - } - if (arrow) { - result.push(space, '=>'); - } - if (node.expression) { - result.push(space); - expr = generateExpression(node.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }); - if (expr.toString().charAt(0) === '{') { - expr = [ - '(', - expr, - ')' - ]; - } - result.push(expr); - } else { - result.push(maybeBlock(node.body, false, true)); - } - return result; - } - function generateExpression(expr, option) { - var result, precedence, type, currentPrecedence, i, len, raw, fragment, multiline, leftChar, leftSource, rightChar, allowIn, allowCall, allowUnparenthesizedNew, property; - precedence = option.precedence; - allowIn = option.allowIn; - allowCall = option.allowCall; - type = expr.type || option.type; - if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) { - return generateVerbatim(expr, option); - } - switch (type) { - case Syntax.SequenceExpression: - result = []; - allowIn |= Precedence.Sequence < precedence; - for (i = 0, len = expr.expressions.length; i < len; i += 1) { - result.push(generateExpression(expr.expressions[i], { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result = parenthesize(result, Precedence.Sequence, precedence); - break; - case Syntax.AssignmentExpression: - allowIn |= Precedence.Assignment < precedence; - result = parenthesize([ - generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: allowIn, - allowCall: true - }), - space + expr.operator + space, - generateExpression(expr.right, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], Precedence.Assignment, precedence); - break; - case Syntax.ArrowFunctionExpression: - allowIn |= Precedence.ArrowFunction < precedence; - result = parenthesize(generateFunctionBody(expr), Precedence.ArrowFunction, precedence); - break; - case Syntax.ConditionalExpression: - allowIn |= Precedence.Conditional < precedence; - result = parenthesize([ - generateExpression(expr.test, { - precedence: Precedence.LogicalOR, - allowIn: allowIn, - allowCall: true - }), - space + '?' + space, - generateExpression(expr.consequent, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space + ':' + space, - generateExpression(expr.alternate, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ], Precedence.Conditional, precedence); - break; - case Syntax.LogicalExpression: - case Syntax.BinaryExpression: - currentPrecedence = BinaryPrecedence[expr.operator]; - allowIn |= currentPrecedence < precedence; - fragment = generateExpression(expr.left, { - precedence: currentPrecedence, - allowIn: allowIn, - allowCall: true - }); - leftSource = fragment.toString(); - if (leftSource.charAt(leftSource.length - 1) === '/' && isIdentifierPart(expr.operator.charAt(0))) { - result = [ - fragment, - noEmptySpace(), - expr.operator - ]; - } else { - result = join(fragment, expr.operator); - } - fragment = generateExpression(expr.right, { - precedence: currentPrecedence + 1, - allowIn: allowIn, - allowCall: true - }); - if (expr.operator === '/' && fragment.toString().charAt(0) === '/' || expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') { - result.push(noEmptySpace(), fragment); - } else { - result = join(result, fragment); - } - if (expr.operator === 'in' && !allowIn) { - result = [ - '(', - result, - ')' - ]; - } else { - result = parenthesize(result, currentPrecedence, precedence); - } - break; - case Syntax.CallExpression: - result = [generateExpression(expr.callee, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true, - allowUnparenthesizedNew: false - })]; - result.push('('); - for (i = 0, len = expr['arguments'].length; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - if (!allowCall) { - result = [ - '(', - result, - ')' - ]; - } else { - result = parenthesize(result, Precedence.Call, precedence); - } - break; - case Syntax.NewExpression: - len = expr['arguments'].length; - allowUnparenthesizedNew = option.allowUnparenthesizedNew === undefined || option.allowUnparenthesizedNew; - result = join('new', generateExpression(expr.callee, { - precedence: Precedence.New, - allowIn: true, - allowCall: false, - allowUnparenthesizedNew: allowUnparenthesizedNew && !parentheses && len === 0 - })); - if (!allowUnparenthesizedNew || parentheses || len > 0) { - result.push('('); - for (i = 0; i < len; i += 1) { - result.push(generateExpression(expr['arguments'][i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + space); - } - } - result.push(')'); - } - result = parenthesize(result, Precedence.New, precedence); - break; - case Syntax.MemberExpression: - result = [generateExpression(expr.object, { - precedence: Precedence.Call, - allowIn: true, - allowCall: allowCall, - allowUnparenthesizedNew: false - })]; - if (expr.computed) { - result.push('[', generateExpression(expr.property, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: allowCall - }), ']'); - } else { - if (expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') { - fragment = toSourceNode(result).toString(); - if (fragment.indexOf('.') < 0 && !/[eExX]/.test(fragment) && isDecimalDigit(fragment.charCodeAt(fragment.length - 1)) && !(fragment.length >= 2 && fragment.charCodeAt(0) === 48)) { - result.push('.'); - } - } - result.push('.', generateIdentifier(expr.property)); - } - result = parenthesize(result, Precedence.Member, precedence); - break; - case Syntax.UnaryExpression: - fragment = generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }); - if (space === '') { - result = join(expr.operator, fragment); - } else { - result = [expr.operator]; - if (expr.operator.length > 2) { - result = join(result, fragment); - } else { - leftSource = toSourceNode(result).toString(); - leftChar = leftSource.charAt(leftSource.length - 1); - rightChar = fragment.toString().charAt(0); - if ((leftChar === '+' || leftChar === '-') && leftChar === rightChar || isIdentifierPart(leftChar) && isIdentifierPart(rightChar)) { - result.push(noEmptySpace(), fragment); - } else { - result.push(fragment); - } - } - } - result = parenthesize(result, Precedence.Unary, precedence); - break; - case Syntax.YieldExpression: - if (expr.delegate) { - result = 'yield*'; - } else { - result = 'yield'; - } - if (expr.argument) { - result = join(result, generateExpression(expr.argument, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - } - break; - case Syntax.UpdateExpression: - if (expr.prefix) { - result = parenthesize([ - expr.operator, - generateExpression(expr.argument, { - precedence: Precedence.Unary, - allowIn: true, - allowCall: true - }) - ], Precedence.Unary, precedence); - } else { - result = parenthesize([ - generateExpression(expr.argument, { - precedence: Precedence.Postfix, - allowIn: true, - allowCall: true - }), - expr.operator - ], Precedence.Postfix, precedence); - } - break; - case Syntax.FunctionExpression: - result = 'function'; - if (expr.id) { - result = [ - result, - noEmptySpace(), - generateIdentifier(expr.id), - generateFunctionBody(expr) - ]; - } else { - result = [ - result + space, - generateFunctionBody(expr) - ]; - } - break; - case Syntax.ArrayPattern: - case Syntax.ArrayExpression: - if (!expr.elements.length) { - result = '[]'; - break; - } - multiline = expr.elements.length > 1; - result = [ - '[', - multiline ? newline : '' - ]; - withIndent(function (indent) { - for (i = 0, len = expr.elements.length; i < len; i += 1) { - if (!expr.elements[i]) { - if (multiline) { - result.push(indent); - } - if (i + 1 === len) { - result.push(','); - } - } else { - result.push(multiline ? indent : '', generateExpression(expr.elements[i], { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - })); - } - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', ']'); - break; - case Syntax.Property: - if (expr.kind === 'get' || expr.kind === 'set') { - result = [ - expr.kind, - noEmptySpace(), - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - generateFunctionBody(expr.value) - ]; - } else { - if (expr.shorthand) { - result = generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - } else if (expr.method) { - result = []; - if (expr.value.generator) { - result.push('*'); - } - result.push(generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), generateFunctionBody(expr.value)); - } else { - result = [ - generateExpression(expr.key, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ':' + space, - generateExpression(expr.value, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - } - } - break; - case Syntax.ObjectExpression: - if (!expr.properties.length) { - result = '{}'; - break; - } - multiline = expr.properties.length > 1; - withIndent(function () { - fragment = generateExpression(expr.properties[0], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - }); - }); - if (!multiline) { - if (!hasLineTerminator(toSourceNode(fragment).toString())) { - result = [ - '{', - space, - fragment, - space, - '}' - ]; - break; - } - } - withIndent(function (indent) { - result = [ - '{', - newline, - indent, - fragment - ]; - if (multiline) { - result.push(',' + newline); - for (i = 1, len = expr.properties.length; i < len; i += 1) { - result.push(indent, generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true, - type: Syntax.Property - })); - if (i + 1 < len) { - result.push(',' + newline); - } - } - } - }); - if (!endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(base, '}'); - break; - case Syntax.ObjectPattern: - if (!expr.properties.length) { - result = '{}'; - break; - } - multiline = false; - if (expr.properties.length === 1) { - property = expr.properties[0]; - if (property.value.type !== Syntax.Identifier) { - multiline = true; - } - } else { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - property = expr.properties[i]; - if (!property.shorthand) { - multiline = true; - break; - } - } - } - result = [ - '{', - multiline ? newline : '' - ]; - withIndent(function (indent) { - for (i = 0, len = expr.properties.length; i < len; i += 1) { - result.push(multiline ? indent : '', generateExpression(expr.properties[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - if (i + 1 < len) { - result.push(',' + (multiline ? newline : space)); - } - } - }); - if (multiline && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - result.push(multiline ? base : '', '}'); - break; - case Syntax.ThisExpression: - result = 'this'; - break; - case Syntax.Identifier: - result = generateIdentifier(expr); - break; - case Syntax.Literal: - if (expr.hasOwnProperty('raw') && parse) { - try { - raw = parse(expr.raw).body[0].expression; - if (raw.type === Syntax.Literal) { - if (raw.value === expr.value) { - result = expr.raw; - break; - } - } - } catch (e) { - } - } - if (expr.value === null) { - result = 'null'; - break; - } - if (typeof expr.value === 'string') { - result = escapeString(expr.value); - break; - } - if (typeof expr.value === 'number') { - result = generateNumber(expr.value); - break; - } - if (typeof expr.value === 'boolean') { - result = expr.value ? 'true' : 'false'; - break; - } - result = generateRegExp(expr.value); - break; - case Syntax.ComprehensionExpression: - result = [ - '[', - generateExpression(expr.body, { - precedence: Precedence.Assignment, - allowIn: true, - allowCall: true - }) - ]; - if (expr.blocks) { - for (i = 0, len = expr.blocks.length; i < len; i += 1) { - fragment = generateExpression(expr.blocks[i], { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - result = join(result, fragment); - } - } - if (expr.filter) { - result = join(result, 'if' + space); - fragment = generateExpression(expr.filter, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - if (extra.moz.parenthesizedComprehensionBlock) { - result = join(result, [ - '(', - fragment, - ')' - ]); - } else { - result = join(result, fragment); - } - } - result.push(']'); - break; - case Syntax.ComprehensionBlock: - if (expr.left.type === Syntax.VariableDeclaration) { - fragment = [ - expr.left.kind, - noEmptySpace(), - generateStatement(expr.left.declarations[0], { allowIn: false }) - ]; - } else { - fragment = generateExpression(expr.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - }); - } - fragment = join(fragment, expr.of ? 'of' : 'in'); - fragment = join(fragment, generateExpression(expr.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })); - if (extra.moz.parenthesizedComprehensionBlock) { - result = [ - 'for' + space + '(', - fragment, - ')' - ]; - } else { - result = join('for' + space, fragment); - } - break; - default: - throw new Error('Unknown expression type: ' + expr.type); - } - return toSourceNode(result, expr); - } - function generateStatement(stmt, option) { - var i, len, result, node, allowIn, functionBody, directiveContext, fragment, semicolon; - allowIn = true; - semicolon = ';'; - functionBody = false; - directiveContext = false; - if (option) { - allowIn = option.allowIn === undefined || option.allowIn; - if (!semicolons && option.semicolonOptional === true) { - semicolon = ''; - } - functionBody = option.functionBody; - directiveContext = option.directiveContext; - } - switch (stmt.type) { - case Syntax.BlockStatement: - result = [ - '{', - newline - ]; - withIndent(function () { - for (i = 0, len = stmt.body.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.body[i], { - semicolonOptional: i === len - 1, - directiveContext: functionBody - })); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - result.push(addIndent('}')); - break; - case Syntax.BreakStatement: - if (stmt.label) { - result = 'break ' + stmt.label.name + semicolon; - } else { - result = 'break' + semicolon; - } - break; - case Syntax.ContinueStatement: - if (stmt.label) { - result = 'continue ' + stmt.label.name + semicolon; - } else { - result = 'continue' + semicolon; - } - break; - case Syntax.DirectiveStatement: - if (stmt.raw) { - result = stmt.raw + semicolon; - } else { - result = escapeDirective(stmt.directive) + semicolon; - } - break; - case Syntax.DoWhileStatement: - result = join('do', maybeBlock(stmt.body)); - result = maybeBlockSuffix(stmt.body, result); - result = join(result, [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + semicolon - ]); - break; - case Syntax.CatchClause: - withIndent(function () { - result = [ - 'catch' + space + '(', - generateExpression(stmt.param, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body)); - break; - case Syntax.DebuggerStatement: - result = 'debugger' + semicolon; - break; - case Syntax.EmptyStatement: - result = ';'; - break; - case Syntax.ExpressionStatement: - result = [generateExpression(stmt.expression, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })]; - fragment = toSourceNode(result).toString(); - if (fragment.charAt(0) === '{' || fragment.slice(0, 8) === 'function' && ' ('.indexOf(fragment.charAt(8)) >= 0 || directive && directiveContext && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string') { - result = [ - '(', - result, - ')' + semicolon - ]; - } else { - result.push(semicolon); - } - break; - case Syntax.VariableDeclarator: - if (stmt.init) { - result = [ - generateExpression(stmt.id, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }), - space, - '=', - space, - generateExpression(stmt.init, { - precedence: Precedence.Assignment, - allowIn: allowIn, - allowCall: true - }) - ]; - } else { - result = generateIdentifier(stmt.id); - } - break; - case Syntax.VariableDeclaration: - result = [stmt.kind]; - if (stmt.declarations.length === 1 && stmt.declarations[0].init && stmt.declarations[0].init.type === Syntax.FunctionExpression) { - result.push(noEmptySpace(), generateStatement(stmt.declarations[0], { allowIn: allowIn })); - } else { - withIndent(function () { - node = stmt.declarations[0]; - if (extra.comment && node.leadingComments) { - result.push('\n', addIndent(generateStatement(node, { allowIn: allowIn }))); - } else { - result.push(noEmptySpace(), generateStatement(node, { allowIn: allowIn })); - } - for (i = 1, len = stmt.declarations.length; i < len; i += 1) { - node = stmt.declarations[i]; - if (extra.comment && node.leadingComments) { - result.push(',' + newline, addIndent(generateStatement(node, { allowIn: allowIn }))); - } else { - result.push(',' + space, generateStatement(node, { allowIn: allowIn })); - } - } - }); - } - result.push(semicolon); - break; - case Syntax.ThrowStatement: - result = [ - join('throw', generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - semicolon - ]; - break; - case Syntax.TryStatement: - result = [ - 'try', - maybeBlock(stmt.block) - ]; - result = maybeBlockSuffix(stmt.block, result); - if (stmt.handlers) { - for (i = 0, len = stmt.handlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.handlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.handlers[i].body, result); - } - } - } else { - if (stmt.handler) { - result = join(result, generateStatement(stmt.handler)); - if (stmt.finalizer || stmt.guardedHandlers.length > 0) { - result = maybeBlockSuffix(stmt.handler.body, result); - } - } - for (i = 0, len = stmt.guardedHandlers.length; i < len; i += 1) { - result = join(result, generateStatement(stmt.guardedHandlers[i])); - if (stmt.finalizer || i + 1 !== len) { - result = maybeBlockSuffix(stmt.guardedHandlers[i].body, result); - } - } - } - if (stmt.finalizer) { - result = join(result, [ - 'finally', - maybeBlock(stmt.finalizer) - ]); - } - break; - case Syntax.SwitchStatement: - withIndent(function () { - result = [ - 'switch' + space + '(', - generateExpression(stmt.discriminant, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' + space + '{' + newline - ]; - }); - if (stmt.cases) { - for (i = 0, len = stmt.cases.length; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.cases[i], { semicolonOptional: i === len - 1 })); - result.push(fragment); - if (!endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - } - result.push(addIndent('}')); - break; - case Syntax.SwitchCase: - withIndent(function () { - if (stmt.test) { - result = [ - join('case', generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - ':' - ]; - } else { - result = ['default:']; - } - i = 0; - len = stmt.consequent.length; - if (len && stmt.consequent[0].type === Syntax.BlockStatement) { - fragment = maybeBlock(stmt.consequent[0]); - result.push(fragment); - i = 1; - } - if (i !== len && !endsWithLineTerminator(toSourceNode(result).toString())) { - result.push(newline); - } - for (; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.consequent[i], { semicolonOptional: i === len - 1 && semicolon === '' })); - result.push(fragment); - if (i + 1 !== len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - }); - break; - case Syntax.IfStatement: - withIndent(function () { - result = [ - 'if' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - if (stmt.alternate) { - result.push(maybeBlock(stmt.consequent)); - result = maybeBlockSuffix(stmt.consequent, result); - if (stmt.alternate.type === Syntax.IfStatement) { - result = join(result, [ - 'else ', - generateStatement(stmt.alternate, { semicolonOptional: semicolon === '' }) - ]); - } else { - result = join(result, join('else', maybeBlock(stmt.alternate, semicolon === ''))); - } - } else { - result.push(maybeBlock(stmt.consequent, semicolon === '')); - } - break; - case Syntax.ForStatement: - withIndent(function () { - result = ['for' + space + '(']; - if (stmt.init) { - if (stmt.init.type === Syntax.VariableDeclaration) { - result.push(generateStatement(stmt.init, { allowIn: false })); - } else { - result.push(generateExpression(stmt.init, { - precedence: Precedence.Sequence, - allowIn: false, - allowCall: true - }), ';'); - } - } else { - result.push(';'); - } - if (stmt.test) { - result.push(space, generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ';'); - } else { - result.push(';'); - } - if (stmt.update) { - result.push(space, generateExpression(stmt.update, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), ')'); - } else { - result.push(')'); - } - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - case Syntax.ForInStatement: - result = ['for' + space + '(']; - withIndent(function () { - if (stmt.left.type === Syntax.VariableDeclaration) { - withIndent(function () { - result.push(stmt.left.kind + noEmptySpace(), generateStatement(stmt.left.declarations[0], { allowIn: false })); - }); - } else { - result.push(generateExpression(stmt.left, { - precedence: Precedence.Call, - allowIn: true, - allowCall: true - })); - } - result = join(result, 'in'); - result = [ - join(result, generateExpression(stmt.right, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - case Syntax.LabeledStatement: - result = [ - stmt.label.name + ':', - maybeBlock(stmt.body, semicolon === '') - ]; - break; - case Syntax.Program: - len = stmt.body.length; - result = [safeConcatenation && len > 0 ? '\n' : '']; - for (i = 0; i < len; i += 1) { - fragment = addIndent(generateStatement(stmt.body[i], { - semicolonOptional: !safeConcatenation && i === len - 1, - directiveContext: true - })); - result.push(fragment); - if (i + 1 < len && !endsWithLineTerminator(toSourceNode(fragment).toString())) { - result.push(newline); - } - } - break; - case Syntax.FunctionDeclaration: - result = [ - stmt.generator && !extra.moz.starlessGenerator ? 'function* ' : 'function ', - generateIdentifier(stmt.id), - generateFunctionBody(stmt) - ]; - break; - case Syntax.ReturnStatement: - if (stmt.argument) { - result = [ - join('return', generateExpression(stmt.argument, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - })), - semicolon - ]; - } else { - result = ['return' + semicolon]; - } - break; - case Syntax.WhileStatement: - withIndent(function () { - result = [ - 'while' + space + '(', - generateExpression(stmt.test, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - case Syntax.WithStatement: - withIndent(function () { - result = [ - 'with' + space + '(', - generateExpression(stmt.object, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }), - ')' - ]; - }); - result.push(maybeBlock(stmt.body, semicolon === '')); - break; - default: - throw new Error('Unknown statement type: ' + stmt.type); - } - if (extra.comment) { - result = addCommentsToStatement(stmt, result); - } - fragment = toSourceNode(result).toString(); - if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') { - result = toSourceNode(result).replaceRight(/\s+$/, ''); - } - return toSourceNode(result, stmt); - } - function generate(node, options) { - var defaultOptions = getDefaultOptions(), result, pair; - if (options != null) { - if (typeof options.indent === 'string') { - defaultOptions.format.indent.style = options.indent; - } - if (typeof options.base === 'number') { - defaultOptions.format.indent.base = options.base; - } - options = updateDeeply(defaultOptions, options); - indent = options.format.indent.style; - if (typeof options.base === 'string') { - base = options.base; - } else { - base = stringRepeat(indent, options.format.indent.base); - } - } else { - options = defaultOptions; - indent = options.format.indent.style; - base = stringRepeat(indent, options.format.indent.base); - } - json = options.format.json; - renumber = options.format.renumber; - hexadecimal = json ? false : options.format.hexadecimal; - quotes = json ? 'double' : options.format.quotes; - escapeless = options.format.escapeless; - newline = options.format.newline; - space = options.format.space; - if (options.format.compact) { - newline = space = indent = base = ''; - } - parentheses = options.format.parentheses; - semicolons = options.format.semicolons; - safeConcatenation = options.format.safeConcatenation; - directive = options.directive; - parse = json ? null : options.parse; - sourceMap = options.sourceMap; - extra = options; - if (sourceMap) { - if (!exports.browser) { - SourceNode = require('/node_modules/source-map/lib/source-map.js', module).SourceNode; - } else { - SourceNode = global.sourceMap.SourceNode; - } - } else { - SourceNode = SourceNodeMock; - } - switch (node.type) { - case Syntax.BlockStatement: - case Syntax.BreakStatement: - case Syntax.CatchClause: - case Syntax.ContinueStatement: - case Syntax.DirectiveStatement: - case Syntax.DoWhileStatement: - case Syntax.DebuggerStatement: - case Syntax.EmptyStatement: - case Syntax.ExpressionStatement: - case Syntax.ForStatement: - case Syntax.ForInStatement: - case Syntax.FunctionDeclaration: - case Syntax.IfStatement: - case Syntax.LabeledStatement: - case Syntax.Program: - case Syntax.ReturnStatement: - case Syntax.SwitchStatement: - case Syntax.SwitchCase: - case Syntax.ThrowStatement: - case Syntax.TryStatement: - case Syntax.VariableDeclaration: - case Syntax.VariableDeclarator: - case Syntax.WhileStatement: - case Syntax.WithStatement: - result = generateStatement(node); - break; - case Syntax.AssignmentExpression: - case Syntax.ArrayExpression: - case Syntax.ArrayPattern: - case Syntax.BinaryExpression: - case Syntax.CallExpression: - case Syntax.ConditionalExpression: - case Syntax.FunctionExpression: - case Syntax.Identifier: - case Syntax.Literal: - case Syntax.LogicalExpression: - case Syntax.MemberExpression: - case Syntax.NewExpression: - case Syntax.ObjectExpression: - case Syntax.ObjectPattern: - case Syntax.Property: - case Syntax.SequenceExpression: - case Syntax.ThisExpression: - case Syntax.UnaryExpression: - case Syntax.UpdateExpression: - case Syntax.YieldExpression: - result = generateExpression(node, { - precedence: Precedence.Sequence, - allowIn: true, - allowCall: true - }); - break; - default: - throw new Error('Unknown node type: ' + node.type); - } - if (!sourceMap) { - return result.toString(); - } - pair = result.toStringWithSourceMap({ - file: options.file, - sourceRoot: options.sourceMapRoot - }); - if (options.sourceMapWithCode) { - return pair; - } - return pair.map.toString(); - } - FORMAT_MINIFY = { - indent: { - style: '', - base: 0 - }, - renumber: true, - hexadecimal: true, - quotes: 'auto', - escapeless: true, - compact: true, - parentheses: false, - semicolons: false - }; - FORMAT_DEFAULTS = getDefaultOptions().format; - exports.version = require('/package.json', module).version; - exports.generate = generate; - exports.attachComments = estraverse.attachComments; - exports.browser = false; - exports.FORMAT_MINIFY = FORMAT_MINIFY; - exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS; - }()); - }); - require.define('/package.json', function (module, exports, __dirname, __filename) { - module.exports = { - 'name': 'escodegen', - 'description': 'ECMAScript code generator', - 'homepage': 'http://github.com/Constellation/escodegen.html', - 'main': 'escodegen.js', - 'bin': { - 'esgenerate': './bin/esgenerate.js', - 'escodegen': './bin/escodegen.js' - }, - 'version': '0.0.28-dev', - 'engines': { 'node': '>=0.4.0' }, - 'maintainers': [{ - 'name': 'Yusuke Suzuki', - 'email': 'utatane.tea@gmail.com', - 'web': 'http://github.com/Constellation' - }], - 'repository': { - 'type': 'git', - 'url': 'http://github.com/Constellation/escodegen.git' - }, - 'dependencies': { - 'esprima': '~1.0.2', - 'estraverse': '~1.3.0' - }, - 'optionalDependencies': { 'source-map': '>= 0.1.2' }, - 'devDependencies': { - 'esprima-moz': '*', - 'commonjs-everywhere': '~0.8.0', - 'q': '*', - 'bower': '*', - 'semver': '*', - 'chai': '~1.7.2', - 'grunt-contrib-jshint': '~0.5.0', - 'grunt-cli': '~0.1.9', - 'grunt': '~0.4.1', - 'grunt-mocha-test': '~0.6.2' - }, - 'licenses': [{ - 'type': 'BSD', - 'url': 'http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD' - }], - 'scripts': { - 'test': 'grunt travis', - 'unit-test': 'grunt test', - 'lint': 'grunt lint', - 'release': 'node tools/release.js', - 'build-min': './node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.min.js', - 'build': './node_modules/.bin/cjsify -a path: tools/entry-point.js > escodegen.browser.js' - } - }; - }); - require.define('/node_modules/source-map/lib/source-map.js', function (module, exports, __dirname, __filename) { - exports.SourceMapGenerator = require('/node_modules/source-map/lib/source-map/source-map-generator.js', module).SourceMapGenerator; - exports.SourceMapConsumer = require('/node_modules/source-map/lib/source-map/source-map-consumer.js', module).SourceMapConsumer; - exports.SourceNode = require('/node_modules/source-map/lib/source-map/source-node.js', module).SourceNode; - }); - require.define('/node_modules/source-map/lib/source-map/source-node.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var SourceMapGenerator = require('/node_modules/source-map/lib/source-map/source-map-generator.js', module).SourceMapGenerator; - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine === undefined ? null : aLine; - this.column = aColumn === undefined ? null : aColumn; - this.source = aSource === undefined ? null : aSource; - this.name = aName === undefined ? null : aName; - if (aChunks != null) - this.add(aChunks); - } - SourceNode.fromStringWithSourceMap = function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { - var node = new SourceNode; - var remainingLines = aGeneratedCode.split('\n'); - var lastGeneratedLine = 1, lastGeneratedColumn = 0; - var lastMapping = null; - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping === null) { - 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 (lastGeneratedLine < mapping.generatedLine) { - var code = ''; - do { - code += remainingLines.shift() + '\n'; - lastGeneratedLine++; - lastGeneratedColumn = 0; - } while (lastGeneratedLine < mapping.generatedLine); - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[0]; - code += nextLine.substr(0, mapping.generatedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - addMappingWithCode(lastMapping, code); - } else { - var nextLine = remainingLines[0]; - var code = nextLine.substr(0, mapping.generatedColumn - lastGeneratedColumn); - remainingLines[0] = nextLine.substr(mapping.generatedColumn - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - } - } - lastMapping = mapping; - }, this); - addMappingWithCode(lastMapping, remainingLines.join('\n')); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - node.setSourceContent(sourceFile, content); - } - }); - return node; - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - node.add(new SourceNode(mapping.originalLine, mapping.originalColumn, mapping.source, code, mapping.name)); - } - } - }; - SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } else if (aChunk instanceof SourceNode || typeof aChunk === 'string') { - if (aChunk) { - this.children.push(aChunk); - } - } else { - throw new TypeError('Expected a SourceNode, string, or an array of SourceNodes and strings. Got ' + aChunk); - } - return this; - }; - SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length - 1; i >= 0; i--) { - this.prepend(aChunk[i]); - } - } else if (aChunk instanceof SourceNode || typeof aChunk === 'string') { - this.children.unshift(aChunk); - } else { - throw new TypeError('Expected a SourceNode, string, or an array of SourceNodes and strings. Got ' + aChunk); - } - return this; - }; - SourceNode.prototype.walk = function SourceNode_walk(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walk(aFn); - } else { - if (chunk !== '') { - aFn(chunk, { - source: this.source, - line: this.line, - column: this.column, - name: this.name - }); - } - } - }, this); - }; - SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len - 1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); - } - newChildren.push(this.children[i]); - this.children = newChildren; - } - return this; - }; - SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild instanceof SourceNode) { - lastChild.replaceRight(aPattern, aReplacement); - } else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); - } else { - this.children.push(''.replace(aPattern, aReplacement)); - } - return this; - }; - SourceNode.prototype.setSourceContent = function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; - SourceNode.prototype.walkSourceContents = function SourceNode_walkSourceContents(aFn) { - this.children.forEach(function (chunk) { - if (chunk instanceof SourceNode) { - chunk.walkSourceContents(aFn); - } - }, this); - Object.keys(this.sourceContents).forEach(function (sourceFileKey) { - aFn(util.fromSetString(sourceFileKey), this.sourceContents[sourceFileKey]); - }, this); - }; - SourceNode.prototype.toString = function SourceNode_toString() { - var str = ''; - this.walk(function (chunk) { - str += chunk; - }); - return str; - }; - SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: '', - line: 1, - column: 0 - }; - 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) { - 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({ - generated: { - line: generated.line, - column: generated.column - } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - chunk.split('').forEach(function (ch) { - if (ch === '\n') { - generated.line++; - generated.column = 0; - } else { - generated.column++; - } - }); - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - return { - code: generated.code, - map: map - }; - }; - exports.SourceNode = SourceNode; - }); - }); - require.define('/node_modules/source-map/lib/source-map/util.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } - } - exports.getArg = getArg; - var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; - function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; - } - return { - scheme: match[1], - auth: match[3], - host: match[4], - port: match[6], - path: match[7] - }; - } - exports.urlParse = urlParse; - 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; - if (aPath.match(urlRegexp)) { - return aPath; - } - if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { - url.path = aPath; - return urlGenerate(url); - } - return aRoot.replace(/\/$/, '') + '/' + aPath; - } - exports.join = join; - function toSetString(aStr) { - return '$' + aStr; - } - exports.toSetString = toSetString; - function fromSetString(aStr) { - return aStr.substr(1); - } - exports.fromSetString = fromSetString; - function relative(aRoot, aPath) { - aRoot = aRoot.replace(/\/$/, ''); - var url = urlParse(aRoot); - if (aPath.charAt(0) == '/' && url && url.path == '/') { - return aPath.slice(1); - } - return aPath.indexOf(aRoot + '/') === 0 ? aPath.substr(aRoot.length + 1) : aPath; - } - exports.relative = relative; - }); - }); - require.define('/node_modules/source-map/node_modules/amdefine/amdefine.js', function (module, exports, __dirname, __filename) { - 'use strict'; - function amdefine(module, requireFn) { - 'use strict'; - var defineCache = {}, loaderCache = {}, alreadyCalled = false, path = require('path', module), makeRequire, stringRequire; - 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] === '..')) { - break; - } else if (i > 0) { - ary.splice(i - 1, 2); - i -= 2; - } - } - } - } - function normalize(name, baseName) { - var baseParts; - if (name && name.charAt(0) === '.') { - if (baseName) { - baseParts = baseName.split('/'); - baseParts = baseParts.slice(0, baseParts.length - 1); - baseParts = baseParts.concat(name.split('/')); - trimDots(baseParts); - name = baseParts.join('/'); - } - } - return name; - } - function makeNormalize(relName) { - return function (name) { - return normalize(name, relName); - }; - } - function makeLoad(id) { - function load(value) { - loaderCache[id] = value; - } - load.fromText = function (id, text) { - throw new Error('amdefine does not implement load.fromText'); - }; - return load; - } - makeRequire = function (systemRequire, exports, module, relId) { - function amdRequire(deps, callback) { - if (typeof deps === 'string') { - return stringRequire(systemRequire, exports, module, deps, relId); - } else { - deps = deps.map(function (depName) { - return stringRequire(systemRequire, exports, module, depName, relId); - }); - process.nextTick(function () { - callback.apply(null, deps); - }); - } - } - amdRequire.toUrl = function (filePath) { - if (filePath.indexOf('.') === 0) { - return normalize(filePath, path.dirname(module.filename)); - } else { - return filePath; - } - }; - return amdRequire; - }; - requireFn = requireFn || function req() { - return module.require.apply(module, arguments); - }; - function runFactory(id, deps, factory) { - var r, e, m, result; - if (id) { - e = loaderCache[id] = {}; - m = { - id: id, - uri: __filename, - exports: e - }; - r = makeRequire(requireFn, e, m, id); - } else { - if (alreadyCalled) { - throw new Error('amdefine with no module ID cannot be called more than once per file.'); - } - alreadyCalled = true; - e = module.exports; - m = module; - r = makeRequire(requireFn, e, m, module.id); - } - if (deps) { - deps = deps.map(function (depName) { - return r(depName); - }); - } - if (typeof factory === 'function') { - result = factory.apply(m.exports, deps); - } else { - result = factory; - } - if (result !== undefined) { - m.exports = result; - if (id) { - loaderCache[id] = m.exports; - } - } - } - stringRequire = function (systemRequire, exports, module, id, relId) { - var index = id.indexOf('!'), originalId = id, prefix, plugin; - if (index === -1) { - id = normalize(id, relId); - if (id === 'require') { - return makeRequire(systemRequire, exports, module, relId); - } else if (id === 'exports') { - return exports; - } else if (id === 'module') { - return module; - } else if (loaderCache.hasOwnProperty(id)) { - return loaderCache[id]; - } else if (defineCache[id]) { - runFactory.apply(null, defineCache[id]); - return loaderCache[id]; - } else { - if (systemRequire) { - return systemRequire(originalId); - } else { - throw new Error('No module with ID: ' + id); - } - } - } else { - prefix = id.substring(0, index); - id = id.substring(index + 1, id.length); - plugin = stringRequire(systemRequire, exports, module, prefix, relId); - if (plugin.normalize) { - id = plugin.normalize(id, makeNormalize(relId)); - } else { - id = normalize(id, relId); - } - if (loaderCache[id]) { - return loaderCache[id]; - } else { - plugin.load(id, makeRequire(systemRequire, exports, module, relId), makeLoad(id), {}); - return loaderCache[id]; - } - } - }; - function define(id, deps, factory) { - if (Array.isArray(id)) { - factory = deps; - deps = id; - id = undefined; - } else if (typeof id !== 'string') { - factory = id; - id = deps = undefined; - } - if (deps && !Array.isArray(deps)) { - factory = deps; - deps = undefined; - } - if (!deps) { - deps = [ - 'require', - 'exports', - 'module' - ]; - } - if (id) { - defineCache[id] = [ - id, - deps, - factory - ]; - } else { - runFactory(id, deps, factory); - } - } - define.require = function (id) { - if (loaderCache[id]) { - return loaderCache[id]; - } - if (defineCache[id]) { - runFactory.apply(null, defineCache[id]); - return loaderCache[id]; - } - }; - define.amd = {}; - return define; - } - module.exports = amdefine; - }); - require.define('/node_modules/source-map/lib/source-map/source-map-generator.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var base64VLQ = require('/node_modules/source-map/lib/source-map/base64-vlq.js', module); - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - var ArraySet = require('/node_modules/source-map/lib/source-map/array-set.js', module).ArraySet; - function SourceMapGenerator(aArgs) { - this._file = util.getArg(aArgs, 'file'); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._sources = new ArraySet; - this._names = new ArraySet; - this._mappings = []; - this._sourcesContents = null; - } - SourceMapGenerator.prototype._version = 3; - SourceMapGenerator.fromSourceMap = function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; - if (mapping.source) { - newMapping.source = mapping.source; - if (sourceRoot) { - newMapping.source = util.relative(sourceRoot, newMapping.source); - } - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; - if (mapping.name) { - newMapping.name = mapping.name; - } - } - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - generator.setSourceContent(sourceFile, content); - } - }); - return generator; - }; - SourceMapGenerator.prototype.addMapping = function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); - this._validateMapping(generated, original, source, name); - if (source && !this._sources.has(source)) { - this._sources.add(source); - } - if (name && !this._names.has(name)) { - this._names.add(name); - } - this._mappings.push({ - generated: generated, - original: original, - source: source, - name: name - }); - }; - SourceMapGenerator.prototype.setSourceContent = function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot) { - source = util.relative(this._sourceRoot, source); - } - if (aSourceContent !== null) { - if (!this._sourcesContents) { - this._sourcesContents = {}; - } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else { - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; - } - } - }; - SourceMapGenerator.prototype.applySourceMap = function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { - if (!aSourceFile) { - aSourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - if (sourceRoot) { - aSourceFile = util.relative(sourceRoot, aSourceFile); - } - var newSources = new ArraySet; - var newNames = new ArraySet; - this._mappings.forEach(function (mapping) { - if (mapping.source === aSourceFile && mapping.original) { - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.original.line, - column: mapping.original.column - }); - if (original.source !== null) { - if (sourceRoot) { - mapping.source = util.relative(sourceRoot, original.source); - } else { - mapping.source = original.source; - } - mapping.original.line = original.line; - mapping.original.column = original.column; - if (original.name !== null && mapping.name !== null) { - mapping.name = original.name; - } - } - } - var source = mapping.source; - if (source && !newSources.has(source)) { - newSources.add(source); - } - var name = mapping.name; - if (name && !newNames.has(name)) { - newNames.add(name); - } - }, this); - this._sources = newSources; - this._names = newNames; - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content) { - if (sourceRoot) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - this.setSourceContent(sourceFile, content); - } - }, this); - }; - SourceMapGenerator.prototype._validateMapping = function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, aName) { - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aGenerated.line > 0 && aGenerated.column >= 0 && !aOriginal && !aSource && !aName) { - return; - } else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated && aOriginal && 'line' in aOriginal && 'column' in aOriginal && aGenerated.line > 0 && aGenerated.column >= 0 && aOriginal.line > 0 && aOriginal.column >= 0 && aSource) { - return; - } else { - throw new Error('Invalid mapping.'); - } - }; - 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); - } - SourceMapGenerator.prototype._serializeMappings = function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var mapping; - this._mappings.sort(cmpMapping); - for (var i = 0, len = this._mappings.length; i < len; i++) { - mapping = this._mappings[i]; - if (mapping.generated.line !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generated.line !== previousGeneratedLine) { - result += ';'; - previousGeneratedLine++; - } - } else { - if (i > 0) { - if (!cmpMapping(mapping, this._mappings[i - 1])) { - continue; - } - result += ','; - } - } - result += base64VLQ.encode(mapping.generated.column - previousGeneratedColumn); - previousGeneratedColumn = mapping.generated.column; - if (mapping.source && mapping.original) { - result += base64VLQ.encode(this._sources.indexOf(mapping.source) - previousSource); - previousSource = this._sources.indexOf(mapping.source); - result += base64VLQ.encode(mapping.original.line - 1 - previousOriginalLine); - previousOriginalLine = mapping.original.line - 1; - result += base64VLQ.encode(mapping.original.column - previousOriginalColumn); - previousOriginalColumn = mapping.original.column; - if (mapping.name) { - result += base64VLQ.encode(this._names.indexOf(mapping.name) - previousName); - previousName = this._names.indexOf(mapping.name); - } - } - } - return result; - }; - SourceMapGenerator.prototype.toJSON = function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - file: this._file, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._sourceRoot) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = map.sources.map(function (source) { - if (map.sourceRoot) { - source = util.relative(map.sourceRoot, source); - } - return Object.prototype.hasOwnProperty.call(this._sourcesContents, util.toSetString(source)) ? this._sourcesContents[util.toSetString(source)] : null; - }, this); - } - return map; - }; - SourceMapGenerator.prototype.toString = function SourceMapGenerator_toString() { - return JSON.stringify(this); - }; - exports.SourceMapGenerator = SourceMapGenerator; - }); - }); - require.define('/node_modules/source-map/lib/source-map/array-set.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - function ArraySet() { - this._array = []; - this._set = {}; - } - 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], aAllowDuplicates); - } - return set; - }; - ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var isDuplicate = this.has(aStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - this._set[util.toSetString(aStr)] = idx; - } - }; - ArraySet.prototype.has = function ArraySet_has(aStr) { - return Object.prototype.hasOwnProperty.call(this._set, util.toSetString(aStr)); - }; - ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (this.has(aStr)) { - return this._set[util.toSetString(aStr)]; - } - throw new Error('"' + aStr + '" is not in the set.'); - }; - ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); - }; - ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); - }; - exports.ArraySet = ArraySet; - }); - }); - require.define('/node_modules/source-map/lib/source-map/base64-vlq.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var base64 = require('/node_modules/source-map/lib/source-map/base64.js', module); - var VLQ_BASE_SHIFT = 5; - var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - var VLQ_BASE_MASK = VLQ_BASE - 1; - var VLQ_CONTINUATION_BIT = VLQ_BASE; - function toVLQSigned(aValue) { - return aValue < 0 ? (-aValue << 1) + 1 : (aValue << 1) + 0; - } - function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative ? -shifted : shifted; - } - exports.encode = function base64VLQ_encode(aValue) { - var encoded = ''; - var digit; - var vlq = toVLQSigned(aValue); - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - digit |= VLQ_CONTINUATION_BIT; - } - encoded += base64.encode(digit); - } while (vlq > 0); - return encoded; - }; - exports.decode = function base64VLQ_decode(aStr) { - var i = 0; - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; - do { - if (i >= strLen) { - throw new Error('Expected more digits in base 64 VLQ value.'); - } - digit = base64.decode(aStr.charAt(i++)); - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - return { - value: fromVLQSigned(result), - rest: aStr.slice(i) - }; - }; - }); - }); - require.define('/node_modules/source-map/lib/source-map/base64.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var charToIntMap = {}; - var intToCharMap = {}; - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('').forEach(function (ch, index) { - charToIntMap[ch] = index; - intToCharMap[index] = ch; - }); - exports.encode = function base64_encode(aNumber) { - if (aNumber in intToCharMap) { - return intToCharMap[aNumber]; - } - throw new TypeError('Must be between 0 and 63: ' + aNumber); - }; - exports.decode = function base64_decode(aChar) { - if (aChar in charToIntMap) { - return charToIntMap[aChar]; - } - throw new TypeError('Not a valid base 64 digit: ' + aChar); - }; - }); - }); - require.define('/node_modules/source-map/lib/source-map/source-map-consumer.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - var util = require('/node_modules/source-map/lib/source-map/util.js', module); - var binarySearch = require('/node_modules/source-map/lib/source-map/binary-search.js', module); - var ArraySet = require('/node_modules/source-map/lib/source-map/array-set.js', module).ArraySet; - var base64VLQ = require('/node_modules/source-map/lib/source-map/base64-vlq.js', module); - function SourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - var names = util.getArg(sourceMap, 'names'); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - if (version !== this._version) { - throw new Error('Unsupported version: ' + version); - } - this._names = ArraySet.fromArray(names, true); - this._sources = ArraySet.fromArray(sources, true); - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this.file = file; - this._generatedMappings = []; - this._originalMappings = []; - this._parseMappings(mappings, sourceRoot); - } - SourceMapConsumer.prototype._version = 3; - Object.defineProperty(SourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot ? util.join(this.sourceRoot, s) : s; - }, this); - } - }); - SourceMapConsumer.prototype._parseMappings = function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var mappingSeparator = /^[,;]/; - var str = aStr; - var mapping; - var temp; - while (str.length > 0) { - if (str.charAt(0) === ';') { - generatedLine++; - str = str.slice(1); - previousGeneratedColumn = 0; - } else if (str.charAt(0) === ',') { - str = str.slice(1); - } else { - mapping = {}; - mapping.generatedLine = generatedLine; - temp = base64VLQ.decode(str); - mapping.generatedColumn = previousGeneratedColumn + temp.value; - previousGeneratedColumn = mapping.generatedColumn; - str = temp.rest; - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - temp = base64VLQ.decode(str); - mapping.source = this._sources.at(previousSource + temp.value); - previousSource += temp.value; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source, but no line and column'); - } - temp = base64VLQ.decode(str); - mapping.originalLine = previousOriginalLine + temp.value; - previousOriginalLine = mapping.originalLine; - mapping.originalLine += 1; - str = temp.rest; - if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { - throw new Error('Found a source and line, but no column'); - } - temp = base64VLQ.decode(str); - mapping.originalColumn = previousOriginalColumn + temp.value; - previousOriginalColumn = mapping.originalColumn; - str = temp.rest; - if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { - temp = base64VLQ.decode(str); - mapping.name = this._names.at(previousName + temp.value); - previousName += temp.value; - str = temp.rest; - } - } - this._generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - this._originalMappings.push(mapping); - } - } - } - this._originalMappings.sort(this._compareOriginalPositions); - }; - 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; - } - }; - SourceMapConsumer.prototype._compareGeneratedPositions = function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - return cmp === 0 ? mappingA.generatedColumn - mappingB.generatedColumn : cmp; - }; - SourceMapConsumer.prototype._findMapping = function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, aColumnName, aComparator) { - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' + aNeedle[aColumnName]); - } - return binarySearch.search(aNeedle, aMappings, aComparator); - }; - SourceMapConsumer.prototype.originalPositionFor = function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; - var mapping = this._findMapping(needle, this._generatedMappings, 'generatedLine', 'generatedColumn', this._compareGeneratedPositions); - if (mapping) { - var source = util.getArg(mapping, 'source', null); - if (source && this.sourceRoot) { - source = util.join(this.sourceRoot, source); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: util.getArg(mapping, 'name', null) - }; - } - return { - source: null, - line: null, - column: null, - name: null - }; - }; - SourceMapConsumer.prototype.sourceContentFor = function SourceMapConsumer_sourceContentFor(aSource) { - if (!this.sourcesContent) { - return null; - } - if (this.sourceRoot) { - 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))) { - 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.'); - }; - SourceMapConsumer.prototype.generatedPositionFor = function SourceMapConsumer_generatedPositionFor(aArgs) { - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; - if (this.sourceRoot) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - var mapping = this._findMapping(needle, this._originalMappings, 'originalLine', 'originalColumn', this._compareOriginalPositions); - if (mapping) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null) - }; - } - return { - line: null, - column: null - }; - }; - SourceMapConsumer.GENERATED_ORDER = 1; - SourceMapConsumer.ORIGINAL_ORDER = 2; - SourceMapConsumer.prototype.eachMapping = function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error('Unknown order of iteration.'); - } - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source; - if (source && sourceRoot) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name - }; - }).forEach(aCallback, context); - }; - exports.SourceMapConsumer = SourceMapConsumer; - }); - }); - require.define('/node_modules/source-map/lib/source-map/binary-search.js', function (module, exports, __dirname, __filename) { - if (typeof define !== 'function') { - var define = require('/node_modules/source-map/node_modules/amdefine/amdefine.js', module)(module, require); - } - define(function (require, exports, module) { - function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid]); - if (cmp === 0) { - return aHaystack[mid]; - } else if (cmp > 0) { - if (aHigh - mid > 1) { - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); - } - return aHaystack[mid]; - } else { - if (mid - aLow > 1) { - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); - } - return aLow < 0 ? null : aHaystack[aLow]; - } - } - exports.search = function search(aNeedle, aHaystack, aCompare) { - return aHaystack.length > 0 ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) : null; - }; - }); - }); - require.define('/node_modules/estraverse/estraverse.js', function (module, exports, __dirname, __filename) { - (function (root, factory) { - 'use strict'; - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory(root.estraverse = {}); - } - }(this, function (exports) { - 'use strict'; - var Syntax, isArray, VisitorOption, VisitorKeys, BREAK, SKIP; - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - ArrowFunctionExpression: 'ArrowFunctionExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - function ignoreJSHintError() { - } - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - function deepCopy(obj) { - var ret = {}, key, val; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - ret[key] = deepCopy(val); - } else { - ret[key] = val; - } - } - } - return ret; - } - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - ignoreJSHintError(shallowCopy); - function upperBound(array, func) { - var diff, len, i, current; - len = array.length; - i = 0; - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - len = diff; - } else { - i = current + 1; - len -= diff + 1; - } - } - return i; - } - function lowerBound(array, func) { - var diff, len, i, current; - len = array.length; - i = 0; - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - i = current + 1; - len -= diff + 1; - } else { - len = diff; - } - } - return i; - } - ignoreJSHintError(lowerBound); - VisitorKeys = { - AssignmentExpression: [ - 'left', - 'right' - ], - ArrayExpression: ['elements'], - ArrowFunctionExpression: [ - 'params', - 'body' - ], - BlockStatement: ['body'], - BinaryExpression: [ - 'left', - 'right' - ], - BreakStatement: ['label'], - CallExpression: [ - 'callee', - 'arguments' - ], - CatchClause: [ - 'param', - 'body' - ], - ConditionalExpression: [ - 'test', - 'consequent', - 'alternate' - ], - ContinueStatement: ['label'], - DebuggerStatement: [], - DirectiveStatement: [], - DoWhileStatement: [ - 'body', - 'test' - ], - EmptyStatement: [], - ExpressionStatement: ['expression'], - ForStatement: [ - 'init', - 'test', - 'update', - 'body' - ], - ForInStatement: [ - 'left', - 'right', - 'body' - ], - FunctionDeclaration: [ - 'id', - 'params', - 'body' - ], - FunctionExpression: [ - 'id', - 'params', - 'body' - ], - Identifier: [], - IfStatement: [ - 'test', - 'consequent', - 'alternate' - ], - Literal: [], - LabeledStatement: [ - 'label', - 'body' - ], - LogicalExpression: [ - 'left', - 'right' - ], - MemberExpression: [ - 'object', - 'property' - ], - NewExpression: [ - 'callee', - 'arguments' - ], - ObjectExpression: ['properties'], - Program: ['body'], - Property: [ - 'key', - 'value' - ], - ReturnStatement: ['argument'], - SequenceExpression: ['expressions'], - SwitchStatement: [ - 'discriminant', - 'cases' - ], - SwitchCase: [ - 'test', - 'consequent' - ], - ThisExpression: [], - ThrowStatement: ['argument'], - TryStatement: [ - 'block', - 'handlers', - 'handler', - 'guardedHandlers', - 'finalizer' - ], - UnaryExpression: ['argument'], - UpdateExpression: ['argument'], - VariableDeclaration: ['declarations'], - VariableDeclarator: [ - 'id', - 'init' - ], - WhileStatement: [ - 'test', - 'body' - ], - WithStatement: [ - 'object', - 'body' - ], - YieldExpression: ['argument'] - }; - BREAK = {}; - SKIP = {}; - VisitorOption = { - Break: BREAK, - Skip: SKIP - }; - function Reference(parent, key) { - this.parent = parent; - this.key = key; - } - Reference.prototype.replace = function replace(node) { - this.parent[this.key] = node; - }; - function Element(node, path, wrap, ref) { - this.node = node; - this.path = path; - this.wrap = wrap; - this.ref = ref; - } - function Controller() { - } - Controller.prototype.path = function path() { - var i, iz, j, jz, result, element; - function addToPath(result, path) { - if (isArray(path)) { - for (j = 0, jz = path.length; j < jz; ++j) { - result.push(path[j]); - } - } else { - result.push(path); - } - } - if (!this.__current.path) { - return null; - } - result = []; - for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { - element = this.__leavelist[i]; - addToPath(result, element.path); - } - addToPath(result, this.__current.path); - return result; - }; - Controller.prototype.parents = function parents() { - var i, iz, result; - result = []; - for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { - result.push(this.__leavelist[i].node); - } - return result; - }; - Controller.prototype.current = function current() { - return this.__current.node; - }; - Controller.prototype.__execute = function __execute(callback, element) { - var previous, result; - result = undefined; - previous = this.__current; - this.__current = element; - this.__state = null; - if (callback) { - result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); - } - this.__current = previous; - return result; - }; - Controller.prototype.notify = function notify(flag) { - this.__state = flag; - }; - Controller.prototype.skip = function () { - this.notify(SKIP); - }; - Controller.prototype['break'] = function () { - this.notify(BREAK); - }; - Controller.prototype.__initialize = function (root, visitor) { - this.visitor = visitor; - this.root = root; - this.__worklist = []; - this.__leavelist = []; - this.__current = null; - this.__state = null; - }; - Controller.prototype.traverse = function traverse(root, visitor) { - var worklist, leavelist, element, node, nodeType, ret, key, current, current2, candidates, candidate, sentinel; - this.__initialize(root, visitor); - sentinel = {}; - worklist = this.__worklist; - leavelist = this.__leavelist; - worklist.push(new Element(root, null, null, null)); - leavelist.push(new Element(null, null, null, null)); - while (worklist.length) { - element = worklist.pop(); - if (element === sentinel) { - element = leavelist.pop(); - ret = this.__execute(visitor.leave, element); - if (this.__state === BREAK || ret === BREAK) { - return; - } - continue; - } - if (element.node) { - ret = this.__execute(visitor.enter, element); - if (this.__state === BREAK || ret === BREAK) { - return; - } - worklist.push(sentinel); - leavelist.push(element); - if (this.__state === SKIP || ret === SKIP) { - continue; - } - node = element.node; - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, null)); - continue; - } - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [ - key, - current2 - ], 'Property', null); - } else { - element = new Element(candidate[current2], [ - key, - current2 - ], null, null); - } - worklist.push(element); - } - } - } - } - }; - Controller.prototype.replace = function replace(root, visitor) { - var worklist, leavelist, node, nodeType, target, element, current, current2, candidates, candidate, sentinel, outer, key; - this.__initialize(root, visitor); - sentinel = {}; - worklist = this.__worklist; - leavelist = this.__leavelist; - outer = { root: root }; - element = new Element(root, null, null, new Reference(outer, 'root')); - worklist.push(element); - leavelist.push(element); - while (worklist.length) { - element = worklist.pop(); - if (element === sentinel) { - element = leavelist.pop(); - target = this.__execute(visitor.leave, element); - if (target !== undefined && target !== BREAK && target !== SKIP) { - element.ref.replace(target); - } - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - continue; - } - target = this.__execute(visitor.enter, element); - if (target !== undefined && target !== BREAK && target !== SKIP) { - element.ref.replace(target); - element.node = target; - } - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - node = element.node; - if (!node) { - continue; - } - worklist.push(sentinel); - leavelist.push(element); - if (this.__state === SKIP || target === SKIP) { - continue; - } - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, new Reference(node, key))); - continue; - } - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [ - key, - current2 - ], 'Property', new Reference(candidate, current2)); - } else { - element = new Element(candidate[current2], [ - key, - current2 - ], null, new Reference(candidate, current2)); - } - worklist.push(element); - } - } - } - return outer.root; - }; - function traverse(root, visitor) { - var controller = new Controller; - return controller.traverse(root, visitor); - } - function replace(root, visitor) { - var controller = new Controller; - return controller.replace(root, visitor); - } - function extendCommentRange(comment, tokens) { - var target, token; - target = upperBound(tokens, function search(token) { - return token.range[0] > comment.range[0]; - }); - comment.extendedRange = [ - comment.range[0], - comment.range[1] - ]; - if (target !== tokens.length) { - comment.extendedRange[1] = tokens[target].range[0]; - } - target -= 1; - if (target >= 0) { - if (target < tokens.length) { - comment.extendedRange[0] = tokens[target].range[1]; - } else if (token.length) { - comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; - } - } - return comment; - } - function attachComments(tree, providedComments, tokens) { - var comments = [], comment, len, i, cursor; - if (!tree.range) { - throw new Error('attachComments needs range information'); - } - if (!tokens.length) { - if (providedComments.length) { - for (i = 0, len = providedComments.length; i < len; i += 1) { - comment = deepCopy(providedComments[i]); - comment.extendedRange = [ - 0, - tree.range[0] - ]; - comments.push(comment); - } - tree.leadingComments = comments; - } - return tree; - } - for (i = 0, len = providedComments.length; i < len; i += 1) { - comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); - } - cursor = 0; - traverse(tree, { - enter: function (node) { - var comment; - while (cursor < comments.length) { - comment = comments[cursor]; - if (comment.extendedRange[1] > node.range[0]) { - break; - } - if (comment.extendedRange[1] === node.range[0]) { - if (!node.leadingComments) { - node.leadingComments = []; - } - node.leadingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - if (cursor === comments.length) { - return VisitorOption.Break; - } - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - cursor = 0; - traverse(tree, { - leave: function (node) { - var comment; - while (cursor < comments.length) { - comment = comments[cursor]; - if (node.range[1] < comment.extendedRange[0]) { - break; - } - if (node.range[1] === comment.extendedRange[0]) { - if (!node.trailingComments) { - node.trailingComments = []; - } - node.trailingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - if (cursor === comments.length) { - return VisitorOption.Break; - } - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - return tree; - } - exports.version = '1.3.1'; - exports.Syntax = Syntax; - exports.traverse = traverse; - exports.replace = replace; - exports.attachComments = attachComments; - exports.VisitorKeys = VisitorKeys; - exports.VisitorOption = VisitorOption; - exports.Controller = Controller; - })); - }); - require('/tools/entry-point.js'); -}.call(this, this)); diff --git a/toolkit/devtools/escodegen/estraverse.js b/toolkit/devtools/escodegen/estraverse.js deleted file mode 100644 index 211617d24ef..00000000000 --- a/toolkit/devtools/escodegen/estraverse.js +++ /dev/null @@ -1,678 +0,0 @@ -/* - Copyright (C) 2012-2013 Yusuke Suzuki - Copyright (C) 2012 Ariya Hidayat - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ -/*jslint vars:false*/ -/*jshint indent:4*/ -/*global exports:true, define:true*/ -(function (root, factory) { - 'use strict'; - - // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, - // and plain browser loading, - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.estraverse = {})); - } -}(this, function (exports) { - 'use strict'; - - var Syntax, - isArray, - VisitorOption, - VisitorKeys, - BREAK, - SKIP; - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DebuggerStatement: 'DebuggerStatement', - DirectiveStatement: 'DirectiveStatement', - DoWhileStatement: 'DoWhileStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - YieldExpression: 'YieldExpression' - }; - - function ignoreJSHintError() { } - - isArray = Array.isArray; - if (!isArray) { - isArray = function isArray(array) { - return Object.prototype.toString.call(array) === '[object Array]'; - }; - } - - function deepCopy(obj) { - var ret = {}, key, val; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (typeof val === 'object' && val !== null) { - ret[key] = deepCopy(val); - } else { - ret[key] = val; - } - } - } - return ret; - } - - function shallowCopy(obj) { - var ret = {}, key; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - ret[key] = obj[key]; - } - } - return ret; - } - ignoreJSHintError(shallowCopy); - - // based on LLVM libc++ upper_bound / lower_bound - // MIT License - - function upperBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - len = diff; - } else { - i = current + 1; - len -= diff + 1; - } - } - return i; - } - - function lowerBound(array, func) { - var diff, len, i, current; - - len = array.length; - i = 0; - - while (len) { - diff = len >>> 1; - current = i + diff; - if (func(array[current])) { - i = current + 1; - len -= diff + 1; - } else { - len = diff; - } - } - return i; - } - ignoreJSHintError(lowerBound); - - VisitorKeys = { - AssignmentExpression: ['left', 'right'], - ArrayExpression: ['elements'], - BlockStatement: ['body'], - BinaryExpression: ['left', 'right'], - BreakStatement: ['label'], - CallExpression: ['callee', 'arguments'], - CatchClause: ['param', 'body'], - ConditionalExpression: ['test', 'consequent', 'alternate'], - ContinueStatement: ['label'], - DebuggerStatement: [], - DirectiveStatement: [], - DoWhileStatement: ['body', 'test'], - EmptyStatement: [], - ExpressionStatement: ['expression'], - ForStatement: ['init', 'test', 'update', 'body'], - ForInStatement: ['left', 'right', 'body'], - FunctionDeclaration: ['id', 'params', 'body'], - FunctionExpression: ['id', 'params', 'body'], - Identifier: [], - IfStatement: ['test', 'consequent', 'alternate'], - Literal: [], - LabeledStatement: ['label', 'body'], - LogicalExpression: ['left', 'right'], - MemberExpression: ['object', 'property'], - NewExpression: ['callee', 'arguments'], - ObjectExpression: ['properties'], - Program: ['body'], - Property: ['key', 'value'], - ReturnStatement: ['argument'], - SequenceExpression: ['expressions'], - SwitchStatement: ['discriminant', 'cases'], - SwitchCase: ['test', 'consequent'], - ThisExpression: [], - ThrowStatement: ['argument'], - TryStatement: ['block', 'handlers', 'handler', 'guardedHandlers', 'finalizer'], - UnaryExpression: ['argument'], - UpdateExpression: ['argument'], - VariableDeclaration: ['declarations'], - VariableDeclarator: ['id', 'init'], - WhileStatement: ['test', 'body'], - WithStatement: ['object', 'body'], - YieldExpression: ['argument'] - }; - - // unique id - BREAK = {}; - SKIP = {}; - - VisitorOption = { - Break: BREAK, - Skip: SKIP - }; - - function Reference(parent, key) { - this.parent = parent; - this.key = key; - } - - Reference.prototype.replace = function replace(node) { - this.parent[this.key] = node; - }; - - function Element(node, path, wrap, ref) { - this.node = node; - this.path = path; - this.wrap = wrap; - this.ref = ref; - } - - function Controller() { } - - // API: - // return property path array from root to current node - Controller.prototype.path = function path() { - var i, iz, j, jz, result, element; - - function addToPath(result, path) { - if (isArray(path)) { - for (j = 0, jz = path.length; j < jz; ++j) { - result.push(path[j]); - } - } else { - result.push(path); - } - } - - // root node - if (!this.__current.path) { - return null; - } - - // first node is sentinel, second node is root element - result = []; - for (i = 2, iz = this.__leavelist.length; i < iz; ++i) { - element = this.__leavelist[i]; - addToPath(result, element.path); - } - addToPath(result, this.__current.path); - return result; - }; - - // API: - // return array of parent elements - Controller.prototype.parents = function parents() { - var i, iz, result; - - // first node is sentinel - result = []; - for (i = 1, iz = this.__leavelist.length; i < iz; ++i) { - result.push(this.__leavelist[i].node); - } - - return result; - }; - - // API: - // return current node - Controller.prototype.current = function current() { - return this.__current.node; - }; - - Controller.prototype.__execute = function __execute(callback, element) { - var previous, result; - - result = undefined; - - previous = this.__current; - this.__current = element; - this.__state = null; - if (callback) { - result = callback.call(this, element.node, this.__leavelist[this.__leavelist.length - 1].node); - } - this.__current = previous; - - return result; - }; - - // API: - // notify control skip / break - Controller.prototype.notify = function notify(flag) { - this.__state = flag; - }; - - // API: - // skip child nodes of current node - Controller.prototype.skip = function () { - this.notify(SKIP); - }; - - // API: - // break traversals - Controller.prototype['break'] = function () { - this.notify(BREAK); - }; - - Controller.prototype.__initialize = function(root, visitor) { - this.visitor = visitor; - this.root = root; - this.__worklist = []; - this.__leavelist = []; - this.__current = null; - this.__state = null; - }; - - Controller.prototype.traverse = function traverse(root, visitor) { - var worklist, - leavelist, - element, - node, - nodeType, - ret, - key, - current, - current2, - candidates, - candidate, - sentinel; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - worklist.push(new Element(root, null, null, null)); - leavelist.push(new Element(null, null, null, null)); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - ret = this.__execute(visitor.leave, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - continue; - } - - if (element.node) { - - ret = this.__execute(visitor.enter, element); - - if (this.__state === BREAK || ret === BREAK) { - return; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || ret === SKIP) { - continue; - } - - node = element.node; - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, null)); - continue; - } - - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [key, current2], 'Property', null); - } else { - element = new Element(candidate[current2], [key, current2], null, null); - } - worklist.push(element); - } - } - } - } - }; - - Controller.prototype.replace = function replace(root, visitor) { - var worklist, - leavelist, - node, - nodeType, - target, - element, - current, - current2, - candidates, - candidate, - sentinel, - outer, - key; - - this.__initialize(root, visitor); - - sentinel = {}; - - // reference - worklist = this.__worklist; - leavelist = this.__leavelist; - - // initialize - outer = { - root: root - }; - element = new Element(root, null, null, new Reference(outer, 'root')); - worklist.push(element); - leavelist.push(element); - - while (worklist.length) { - element = worklist.pop(); - - if (element === sentinel) { - element = leavelist.pop(); - - target = this.__execute(visitor.leave, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP) { - // replace - element.ref.replace(target); - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - continue; - } - - target = this.__execute(visitor.enter, element); - - // node may be replaced with null, - // so distinguish between undefined and null in this place - if (target !== undefined && target !== BREAK && target !== SKIP) { - // replace - element.ref.replace(target); - element.node = target; - } - - if (this.__state === BREAK || target === BREAK) { - return outer.root; - } - - // node may be null - node = element.node; - if (!node) { - continue; - } - - worklist.push(sentinel); - leavelist.push(element); - - if (this.__state === SKIP || target === SKIP) { - continue; - } - - nodeType = element.wrap || node.type; - candidates = VisitorKeys[nodeType]; - - current = candidates.length; - while ((current -= 1) >= 0) { - key = candidates[current]; - candidate = node[key]; - if (!candidate) { - continue; - } - - if (!isArray(candidate)) { - worklist.push(new Element(candidate, key, null, new Reference(node, key))); - continue; - } - - current2 = candidate.length; - while ((current2 -= 1) >= 0) { - if (!candidate[current2]) { - continue; - } - if (nodeType === Syntax.ObjectExpression && 'properties' === candidates[current]) { - element = new Element(candidate[current2], [key, current2], 'Property', new Reference(candidate, current2)); - } else { - element = new Element(candidate[current2], [key, current2], null, new Reference(candidate, current2)); - } - worklist.push(element); - } - } - } - - return outer.root; - }; - - function traverse(root, visitor) { - var controller = new Controller(); - return controller.traverse(root, visitor); - } - - function replace(root, visitor) { - var controller = new Controller(); - return controller.replace(root, visitor); - } - - function extendCommentRange(comment, tokens) { - var target, token; - - target = upperBound(tokens, function search(token) { - return token.range[0] > comment.range[0]; - }); - - comment.extendedRange = [comment.range[0], comment.range[1]]; - - if (target !== tokens.length) { - comment.extendedRange[1] = tokens[target].range[0]; - } - - target -= 1; - if (target >= 0) { - if (target < tokens.length) { - comment.extendedRange[0] = tokens[target].range[1]; - } else if (token.length) { - comment.extendedRange[1] = tokens[tokens.length - 1].range[0]; - } - } - - return comment; - } - - function attachComments(tree, providedComments, tokens) { - // At first, we should calculate extended comment ranges. - var comments = [], comment, len, i, cursor; - - if (!tree.range) { - throw new Error('attachComments needs range information'); - } - - // tokens array is empty, we attach comments to tree as 'leadingComments' - if (!tokens.length) { - if (providedComments.length) { - for (i = 0, len = providedComments.length; i < len; i += 1) { - comment = deepCopy(providedComments[i]); - comment.extendedRange = [0, tree.range[0]]; - comments.push(comment); - } - tree.leadingComments = comments; - } - return tree; - } - - for (i = 0, len = providedComments.length; i < len; i += 1) { - comments.push(extendCommentRange(deepCopy(providedComments[i]), tokens)); - } - - // This is based on John Freeman's implementation. - cursor = 0; - traverse(tree, { - enter: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (comment.extendedRange[1] > node.range[0]) { - break; - } - - if (comment.extendedRange[1] === node.range[0]) { - if (!node.leadingComments) { - node.leadingComments = []; - } - node.leadingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - cursor = 0; - traverse(tree, { - leave: function (node) { - var comment; - - while (cursor < comments.length) { - comment = comments[cursor]; - if (node.range[1] < comment.extendedRange[0]) { - break; - } - - if (node.range[1] === comment.extendedRange[0]) { - if (!node.trailingComments) { - node.trailingComments = []; - } - node.trailingComments.push(comment); - comments.splice(cursor, 1); - } else { - cursor += 1; - } - } - - // already out of owned node - if (cursor === comments.length) { - return VisitorOption.Break; - } - - if (comments[cursor].extendedRange[0] > node.range[1]) { - return VisitorOption.Skip; - } - } - }); - - return tree; - } - - exports.version = '1.3.0'; - exports.Syntax = Syntax; - exports.traverse = traverse; - exports.replace = replace; - exports.attachComments = attachComments; - exports.VisitorKeys = VisitorKeys; - exports.VisitorOption = VisitorOption; - exports.Controller = Controller; -})); -/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/toolkit/devtools/escodegen/package.json.js b/toolkit/devtools/escodegen/package.json.js deleted file mode 100644 index 84c83e733a7..00000000000 --- a/toolkit/devtools/escodegen/package.json.js +++ /dev/null @@ -1,57 +0,0 @@ -module.exports = { - "name": "escodegen", - "description": "ECMAScript code generator", - "homepage": "http://github.com/Constellation/escodegen.html", - "main": "escodegen.js", - "bin": { - "esgenerate": "./bin/esgenerate.js", - "escodegen": "./bin/escodegen.js" - }, - "version": "0.0.26", - "engines": { - "node": ">=0.4.0" - }, - "maintainers": [ - { - "name": "Yusuke Suzuki", - "email": "utatane.tea@gmail.com", - "web": "http://github.com/Constellation" - } - ], - "repository": { - "type": "git", - "url": "http://github.com/Constellation/escodegen.git" - }, - "dependencies": { - "esprima": "~1.0.2", - "estraverse": "~1.3.0" - }, - "optionalDependencies": { - "source-map": ">= 0.1.2" - }, - "devDependencies": { - "esprima-moz": "*", - "commonjs-everywhere": "~0.8.0", - "q": "*", - "bower": "*", - "semver": "*", - "chai": "~1.7.2", - "grunt-contrib-jshint": "~0.5.0", - "grunt-cli": "~0.1.9", - "grunt": "~0.4.1", - "grunt-mocha-test": "~0.6.2" - }, - "licenses": [ - { - "type": "BSD", - "url": "http://github.com/Constellation/escodegen/raw/master/LICENSE.BSD" - } - ], - "scripts": { - "test": "grunt travis", - "unit-test": "grunt test", - "lint": "grunt lint", - "release": "node tools/release.js", - "build": "./node_modules/.bin/cjsify -ma path: tools/entry-point.js > escodegen.browser.js" - } -}; diff --git a/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js b/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js deleted file mode 100644 index c7f6ba96bf0..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/test_generate_source_maps.js +++ /dev/null @@ -1,71 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test that we can generate source maps via escodegen. - */ - -Components.utils.import("resource://gre/modules/reflect.jsm"); -Components.utils.import("resource://gre/modules/devtools/SourceMap.jsm"); -const escodegen = require("escodegen/escodegen"); - -const testCode = "" + function main() { - var a = 5 + 3; - var b = 19 * 52; - return a / b; -}; - -function run_test() { - const ast = Reflect.parse(testCode); - const { code, map } = escodegen.generate(ast, { - format: { - indent: { - // Single space indents so we are mapping different locations. - style: " " - } - }, - sourceMap: "testCode.js", - sourceMapWithCode: true - }); - const smc = new SourceMapConsumer(map.toString()); - - let mapping = smc.originalPositionFor({ - line: 2, - column: 1 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 2); - do_check_eq(mapping.column, 2); - - mapping = smc.originalPositionFor({ - line: 2, - column: 5 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 2); - do_check_eq(mapping.column, 6); - - mapping = smc.originalPositionFor({ - line: 3, - column: 1 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 3); - do_check_eq(mapping.column, 2); - - mapping = smc.originalPositionFor({ - line: 3, - column: 5 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 3); - do_check_eq(mapping.column, 6); - - mapping = smc.originalPositionFor({ - line: 4, - column: 1 - }); - do_check_eq(mapping.source, "testCode.js"); - do_check_eq(mapping.line, 4); - do_check_eq(mapping.column, 2); -}; diff --git a/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js b/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js deleted file mode 100644 index a9f76e41fed..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/test_import_escodegen.js +++ /dev/null @@ -1,11 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test that we can require escodegen. - */ - -function run_test() { - const escodegen = require("escodegen/escodegen"); - do_check_eq(typeof escodegen.generate, "function"); -} diff --git a/toolkit/devtools/escodegen/tests/unit/test_same_ast.js b/toolkit/devtools/escodegen/tests/unit/test_same_ast.js deleted file mode 100644 index 72b4200a05d..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/test_same_ast.js +++ /dev/null @@ -1,76 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -/** - * Test that we can go AST -> JS -> AST via escodegen and Reflect. - */ - -const escodegen = require("escodegen/escodegen"); -Components.utils.import("resource://gre/modules/reflect.jsm"); - -const testCode = "" + function main () { - function makeAcc(n) { - return function () { - return ++n; - }; - } - - var acc = makeAcc(10); - - for (var i = 0; i < 10; i++) { - acc(); - } - - console.log(acc()); -}; - -function run_test() { - const originalAST = Reflect.parse(testCode); - const generatedCode = escodegen.generate(originalAST); - const generatedAST = Reflect.parse(generatedCode); - - do_print("Original AST:"); - do_print(JSON.stringify(originalAST, null, 2)); - do_print("Generated AST:"); - do_print(JSON.stringify(generatedAST, null, 2)); - - checkEquivalentASTs(originalAST, generatedAST); -} - -const isObject = (obj) => typeof obj === "object" && obj !== null; -const zip = (a, b) => { - let pairs = []; - for (let i = 0; i < a.length && i < b.length; i++) { - pairs.push([a[i], b[i]]); - } - return pairs; -}; -const isntLoc = k => k !== "loc"; - -function checkEquivalentASTs(expected, actual, prop = []) { - do_print("Checking: " + prop.join(" ")); - - if (!isObject(expected)) { - return void do_check_eq(expected, actual); - } - - do_check_true(isObject(actual)); - - if (Array.isArray(expected)) { - do_check_true(Array.isArray(actual)); - do_check_eq(expected.length, actual.length); - let i = 0; - for (let [e, a] of zip(expected, actual)) { - checkEquivalentASTs(a, e, prop.concat([i++])); - } - return; - } - - const expectedKeys = Object.keys(expected).filter(isntLoc).sort(); - const actualKeys = Object.keys(actual).filter(isntLoc).sort(); - do_check_eq(expectedKeys.length, actualKeys.length); - for (let [ek, ak] of zip(expectedKeys, actualKeys)) { - do_check_eq(ek, ak); - checkEquivalentASTs(expected[ek], actual[ak], prop.concat([ek])); - } -} diff --git a/toolkit/devtools/escodegen/tests/unit/xpcshell.ini b/toolkit/devtools/escodegen/tests/unit/xpcshell.ini deleted file mode 100644 index e8d9f152bae..00000000000 --- a/toolkit/devtools/escodegen/tests/unit/xpcshell.ini +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -head = head_escodegen.js -tail = - -[test_import_escodegen.js] -[test_same_ast.js] -[test_generate_source_maps.js] diff --git a/toolkit/devtools/moz.build b/toolkit/devtools/moz.build index 16897d5e427..20022d77b59 100644 --- a/toolkit/devtools/moz.build +++ b/toolkit/devtools/moz.build @@ -14,6 +14,6 @@ PARALLEL_DIRS += [ 'webconsole', 'apps', 'styleinspector', - 'escodegen', - 'acorn' + 'acorn', + 'pretty-fast' ] diff --git a/toolkit/devtools/pretty-fast/UPGRADING.md b/toolkit/devtools/pretty-fast/UPGRADING.md new file mode 100644 index 00000000000..6ad0071c896 --- /dev/null +++ b/toolkit/devtools/pretty-fast/UPGRADING.md @@ -0,0 +1,7 @@ +# UPGRADING + +1. `git clone https://github.com/mozilla/pretty-fast.git` + +2. Copy `pretty-fast/pretty-fast.js` to `toolkit/devtools/pretty-fast/pretty-fast.js` + +3. Copy `pretty-fast/test.js` to `toolkit/devtools/pretty-fast/tests/unit/test.js` diff --git a/toolkit/devtools/escodegen/moz.build b/toolkit/devtools/pretty-fast/moz.build similarity index 73% rename from toolkit/devtools/escodegen/moz.build rename to toolkit/devtools/pretty-fast/moz.build index 4c70f2f5b6d..1190adac810 100644 --- a/toolkit/devtools/escodegen/moz.build +++ b/toolkit/devtools/pretty-fast/moz.build @@ -6,11 +6,8 @@ XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] -JS_MODULES_PATH = 'modules/devtools/escodegen' +JS_MODULES_PATH = 'modules/devtools' EXTRA_JS_MODULES += [ - 'escodegen.js', - 'escodegen.worker.js', - 'estraverse.js', - 'package.json.js', + 'pretty-fast.js', ] diff --git a/toolkit/devtools/pretty-fast/pretty-fast.js b/toolkit/devtools/pretty-fast/pretty-fast.js new file mode 100644 index 00000000000..33b7f82e6e9 --- /dev/null +++ b/toolkit/devtools/pretty-fast/pretty-fast.js @@ -0,0 +1,781 @@ +/* + * Copyright 2013 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.md or: + * http://opensource.org/licenses/BSD-2-Clause + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.prettyFast = factory(); + } +}(this, function () { + "use strict"; + + var acorn = this.acorn || require("acorn"); + var sourceMap = this.sourceMap || require("source-map"); + var SourceNode = sourceMap.SourceNode; + + // If any of these tokens are seen before a "[" token, we know that "[" token + // is the start of an array literal, rather than a property access. + // + // The only exception is "}", which would need to be disambiguated by + // parsing. The majority of the time, an open bracket following a closing + // curly is going to be an array literal, so we brush the complication under + // the rug, and handle the ambiguity by always assuming that it will be an + // array literal. + var PRE_ARRAY_LITERAL_TOKENS = { + "typeof": true, + "void": true, + "delete": true, + "case": true, + "do": true, + "=": true, + "in": true, + "{": true, + "*": true, + "/": true, + "%": true, + "else": true, + ";": true, + "++": true, + "--": true, + "+": true, + "-": true, + "~": true, + "!": true, + ":": true, + "?": true, + ">>": true, + ">>>": true, + "<<": true, + "||": true, + "&&": true, + "<": true, + ">": true, + "<=": true, + ">=": true, + "instanceof": true, + "&": true, + "^": true, + "|": true, + "==": true, + "!=": true, + "===": true, + "!==": true, + ",": true, + + "}": true + }; + + /** + * Determines if we think that the given token starts an array literal. + * + * @param Object token + * The token we want to determine if it is an array literal. + * @param Object lastToken + * The last token we added to the pretty printed results. + * + * @returns Boolean + * True if we believe it is an array literal, false otherwise. + */ + function isArrayLiteral(token, lastToken) { + if (token.type.type != "[") { + return false; + } + if (!lastToken) { + return true; + } + if (lastToken.type.isAssign) { + return true; + } + return !!PRE_ARRAY_LITERAL_TOKENS[lastToken.type.keyword || lastToken.type.type]; + } + + // If any of these tokens are followed by a token on a new line, we know that + // ASI cannot happen. + var PREVENT_ASI_AFTER_TOKENS = { + // Binary operators + "*": true, + "/": true, + "%": true, + "+": true, + "-": true, + "<<": true, + ">>": true, + ">>>": true, + "<": true, + ">": true, + "<=": true, + ">=": true, + "instanceof": true, + "in": true, + "==": true, + "!=": true, + "===": true, + "!==": true, + "&": true, + "^": true, + "|": true, + "&&": true, + "||": true, + ",": true, + ".": true, + "=": true, + "*=": true, + "/=": true, + "%=": true, + "+=": true, + "-=": true, + "<<=": true, + ">>=": true, + ">>>=": true, + "&=": true, + "^=": true, + "|=": true, + // Unary operators + "delete": true, + "void": true, + "typeof": true, + "~": true, + "!": true, + "new": true, + // Function calls and grouped expressions + "(": true + }; + + // If any of these tokens are on a line after the token before it, we know + // that ASI cannot happen. + var PREVENT_ASI_BEFORE_TOKENS = { + // Binary operators + "*": true, + "/": true, + "%": true, + "<<": true, + ">>": true, + ">>>": true, + "<": true, + ">": true, + "<=": true, + ">=": true, + "instanceof": true, + "in": true, + "==": true, + "!=": true, + "===": true, + "!==": true, + "&": true, + "^": true, + "|": true, + "&&": true, + "||": true, + ",": true, + ".": true, + "=": true, + "*=": true, + "/=": true, + "%=": true, + "+=": true, + "-=": true, + "<<=": true, + ">>=": true, + ">>>=": true, + "&=": true, + "^=": true, + "|=": true, + // Function calls + "(": true + }; + + /** + * Determines if Automatic Semicolon Insertion (ASI) occurs between these + * tokens. + * + * @param Object token + * The token we want to determine if it is an array literal. + * @param Object lastToken + * The last token we added to the pretty printed results. + * + * @returns Boolean + * True if we believe ASI occurs. + */ + function isASI(token, lastToken) { + if (!lastToken) { + return false; + } + if (token.startLoc.line === lastToken.startLoc.line) { + return false; + } + if (PREVENT_ASI_AFTER_TOKENS[lastToken.type.type || lastToken.type.keyword]) { + return false; + } + if (PREVENT_ASI_BEFORE_TOKENS[token.type.type || token.type.keyword]) { + return false; + } + return true; + } + + /** + * Determine if we should add a newline after the given token. + * + * @param Object token + * The token we are looking at. + * @param Array stack + * The stack of open parens/curlies/brackets/etc. + * + * @returns Boolean + * True if we should add a newline. + */ + function isLineDelimiter(token, stack) { + if (token.isArrayLiteral) { + return true; + } + var ttt = token.type.type; + var top = stack[stack.length - 1]; + return ttt == ";" && top != "(" + || ttt == "{" + || ttt == "," && top != "(" + || ttt == ":" && (top == "case" || top == "default"); + } + + /** + * Append the necessary whitespace to the result after we have added the given + * token. + * + * @param Object token + * The token that was just added to the result. + * @param Function write + * The function to write to the pretty printed results. + * @param Array stack + * The stack of open parens/curlies/brackets/etc. + * + * @returns Boolean + * Returns true if we added a newline to result, false in all other + * cases. + */ + function appendNewline(token, write, stack) { + if (isLineDelimiter(token, stack)) { + write("\n", token.startLoc.line, token.startLoc.column); + return true; + } + return false; + } + + /** + * Determines if we need to add a space between the last token we added and + * the token we are about to add. + * + * @param Object token + * The token we are about to add to the pretty printed code. + * @param Object lastToken + * The last token added to the pretty printed code. + */ + function needsSpaceAfter(token, lastToken) { + if (lastToken) { + if (lastToken.type.isLoop) { + return true; + } + if (lastToken.type.isAssign) { + return true; + } + if (lastToken.type.binop != null) { + return true; + } + + var ltt = lastToken.type.type; + if (ltt == "?") { + return true; + } + if (ltt == ":") { + return true; + } + if (ltt == ",") { + return true; + } + if (ltt == ";") { + return true; + } + + var ltk = lastToken.type.keyword; + if (ltk != null + && ltk != "debugger" + && ltk != "null" + && ltk != "true" + && ltk != "false" + && ltk != "this" + && ltk != "break" + && ltk != "continue" + && ltk != "default") { + return true; + } + + if (ltt == ")" && (token.type.type != ")" + && token.type.type != "]" + && token.type.type != ";" + && token.type.type != ",")) { + return true; + } + } + + if (token.type.isAssign) { + return true; + } + if (token.type.binop != null) { + return true; + } + if (token.type.type == "?") { + return true; + } + + return false; + } + + /** + * Add the required whitespace before this token, whether that is a single + * space, newline, and/or the indent on fresh lines. + * + * @param Object token + * The token we are about to add to the pretty printed code. + * @param Object lastToken + * The last token we added to the pretty printed code. + * @param Boolean addedNewline + * Whether we added a newline after adding the last token to the pretty + * printed code. + * @param Function write + * The function to write pretty printed code to the result SourceNode. + * @param Object options + * The options object. + * @param Number indentLevel + * The number of indents deep we are. + * @param Array stack + * The stack of open curlies, brackets, etc. + */ + function prependWhiteSpace(token, lastToken, addedNewline, write, options, + indentLevel, stack) { + var ttk = token.type.keyword; + var ttt = token.type.type; + var newlineAdded = addedNewline; + + // Handle whitespace and newlines after "}" here instead of in + // `isLineDelimiter` because it is only a line delimiter some of the + // time. For example, we don't want to put "else if" on a new line after + // the first if's block. + if (lastToken && lastToken.type.type == "}") { + if (ttk == "while" && stack[stack.length - 1] == "do") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } else if (ttk == "else" || + ttk == "catch" || + ttk == "finally") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } else if (ttt != "(" && + ttt != ";" && + ttt != "," && + ttt != ")" && + ttt != ".") { + write("\n", + lastToken.startLoc.line, + lastToken.startLoc.column); + newlineAdded = true; + } + } + + if (ttt == ":" && stack[stack.length - 1] == "?") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } + + if (lastToken && lastToken.type.type != "}" && ttk == "else") { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } + + function ensureNewline() { + if (!newlineAdded) { + write("\n", + lastToken.startLoc.line, + lastToken.startLoc.column); + newlineAdded = true; + } + } + + if (isASI(token, lastToken)) { + ensureNewline(); + } + + if (decrementsIndent(ttt, stack)) { + ensureNewline(); + } + + if (newlineAdded) { + if (ttk == "case" || ttk == "default") { + write(repeat(options.indent, indentLevel - 1), + token.startLoc.line, + token.startLoc.column); + } else { + write(repeat(options.indent, indentLevel), + token.startLoc.line, + token.startLoc.column); + } + } else if (needsSpaceAfter(token, lastToken)) { + write(" ", + lastToken.startLoc.line, + lastToken.startLoc.column); + } + } + + /** + * Repeat the `str` string `n` times. + * + * @param String str + * The string to be repeated. + * @param Number n + * The number of times to repeat the string. + * + * @returns String + * The repeated string. + */ + function repeat(str, n) { + var result = ""; + while (n > 0) { + if (n & 1) { + result += str; + } + n >>= 1; + str += str; + } + return result; + } + + /** + * Make sure that we put "\n" into the output instead of actual newlines. + */ + function sanitizeNewlines(str) { + return str.replace(/\n/g, "\\n"); + } + + /** + * Add the given token to the pretty printed results. + * + * @param Object token + * The token to add. + * @param Function write + * The function to write pretty printed code to the result SourceNode. + * @param Object options + * The options object. + */ + function addToken(token, write, options) { + if (token.type.type == "string") { + write("'" + sanitizeNewlines(token.value) + "'", + token.startLoc.line, + token.startLoc.column); + } else { + write(String(token.value != null ? token.value : token.type.type), + token.startLoc.line, + token.startLoc.column); + } + } + + /** + * Returns true if the given token type belongs on the stack. + */ + function belongsOnStack(token) { + var ttt = token.type.type; + var ttk = token.type.keyword; + return ttt == "{" + || ttt == "(" + || ttt == "[" + || ttt == "?" + || ttk == "do" + || ttk == "case" + || ttk == "default"; + } + + /** + * Returns true if the given token should cause us to pop the stack. + */ + function shouldStackPop(token, stack) { + var ttt = token.type.type; + var ttk = token.type.keyword; + var top = stack[stack.length - 1]; + return ttt == "]" + || ttt == ")" + || ttt == "}" + || (ttt == ":" && (top == "case" || top == "default" || top == "?")) + || (ttk == "while" && top == "do"); + } + + /** + * Returns true if the given token type should cause us to decrement the + * indent level. + */ + function decrementsIndent(tokenType, stack) { + return tokenType == "}" + || (tokenType == "]" && stack[stack.length - 1] == "[\n") + } + + /** + * Returns true if the given token should cause us to increment the indent + * level. + */ + function incrementsIndent(token) { + return token.type.type == "{" || token.isArrayLiteral; + } + + /** + * Add a comment to the pretty printed code. + * + * @param Function write + * The function to write pretty printed code to the result SourceNode. + * @param Number indentLevel + * The number of indents deep we are. + * @param Object options + * The options object. + * @param Boolean block + * True if the comment is a multiline block style comment. + * @param String text + * The text of the comment. + * @param Number line + * The line number to comment appeared on. + * @param Number column + * The column number the comment appeared on. + */ + function addComment(write, indentLevel, options, block, text, line, column) { + var indentString = repeat(options.indent, indentLevel); + + write(indentString, line, column); + if (block) { + write("/*"); + write(text + .split(new RegExp("/\n" + indentString + "/", "g")) + .join("\n" + indentString)); + write("*/"); + } else { + write("//"); + write(text); + } + write("\n"); + } + + /** + * The main function. + * + * @param String input + * The ugly JS code we want to pretty print. + * @param Object options + * The options object. Provides configurability of the pretty + * printing. Properties: + * - url: The URL string of the ugly JS code. + * - indent: The string to indent code by. + * + * @returns Object + * An object with the following properties: + * - code: The pretty printed code string. + * - map: A SourceMapGenerator instance. + */ + return function prettyFast(input, options) { + // The level of indents deep we are. + var indentLevel = 0; + + // We will accumulate the pretty printed code in this SourceNode. + var result = new SourceNode(); + + /** + * Write a pretty printed string to the result SourceNode. + * + * We buffer our writes so that we only create one mapping for each line in + * the source map. This enhances performance by avoiding extraneous mapping + * serialization, and flattening the tree that + * `SourceNode#toStringWithSourceMap` will have to recursively walk. When + * timing how long it takes to pretty print jQuery, this optimization + * brought the time down from ~390 ms to ~190ms! + * + * @param String str + * The string to be added to the result. + * @param Number line + * The line number the string came from in the ugly source. + * @param Number column + * The column number the string came from in the ugly source. + */ + var write = (function () { + var buffer = []; + var bufferLine = -1; + var bufferColumn = -1; + return function write(str, line, column) { + if (line != null && bufferLine === -1) { + bufferLine = line; + } + if (column != null && bufferColumn === -1) { + bufferColumn = column; + } + buffer.push(str); + + if (str == "\n") { + var lineStr = ""; + for (var i = 0, len = buffer.length; i < len; i++) { + lineStr += buffer[i]; + } + result.add(new SourceNode(bufferLine, bufferColumn, options.url, lineStr)); + buffer.splice(0, buffer.length); + bufferLine = -1; + bufferColumn = -1; + } + } + }()); + + // Whether or not we added a newline on after we added the last token. + var addedNewline = false; + + // The current token we will be adding to the pretty printed code. + var token; + + // Shorthand for token.type.type, so we don't have to repeatedly access + // properties. + var ttt; + + // Shorthand for token.type.keyword, so we don't have to repeatedly access + // properties. + var ttk; + + // The last token we added to the pretty printed code. + var lastToken; + + // Stack of token types/keywords that can affect whether we want to add a + // newline or a space. We can make that decision based on what token type is + // on the top of the stack. For example, a comma in a parameter list should + // be followed by a space, while a comma in an object literal should be + // followed by a newline. + // + // Strings that go on the stack: + // + // - "{" + // - "(" + // - "[" + // - "[\n" + // - "do" + // - "?" + // - "case" + // - "default" + // + // The difference between "[" and "[\n" is that "[\n" is used when we are + // treating "[" and "]" tokens as line delimiters and should increment and + // decrement the indent level when we find them. + var stack = []; + + // Acorn's tokenizer will always yield comments *before* the token they + // follow (unless the very first thing in the source is a comment), so we + // have to queue the comments in order to pretty print them in the correct + // location. For example, the source file: + // + // foo + // // a + // // b + // bar + // + // When tokenized by acorn, gives us the following token stream: + // + // [ '// a', '// b', foo, bar ] + var commentQueue = []; + + var getToken = acorn.tokenize(input, { + locations: true, + sourceFile: options.url, + onComment: function (block, text, start, end, startLoc, endLoc) { + if (lastToken) { + commentQueue.push({ + block: block, + text: text, + line: startLoc.line, + column: startLoc.column + }); + } else { + addComment(write, indentLevel, options, block, text, startLoc.line, + startLoc.column); + addedNewline = true; + } + } + }); + + while (true) { + token = getToken(); + + ttk = token.type.keyword; + ttt = token.type.type; + + if (ttt == "eof") { + if (!addedNewline) { + write("\n"); + } + break; + } + + token.isArrayLiteral = isArrayLiteral(token, lastToken); + + if (belongsOnStack(token)) { + if (token.isArrayLiteral) { + stack.push("[\n"); + } else { + stack.push(ttt || ttk); + } + } + + if (decrementsIndent(ttt, stack)) { + indentLevel--; + } + + prependWhiteSpace(token, lastToken, addedNewline, write, options, + indentLevel, stack); + addToken(token, write, options); + addedNewline = appendNewline(token, write, stack); + + if (shouldStackPop(token, stack)) { + stack.pop(); + } + + if (incrementsIndent(token)) { + indentLevel++; + } + + // Acorn's tokenizer re-uses tokens, so we have to copy the last token on + // every iteration. We follow acorn's lead here, and reuse the lastToken + // object the same way that acorn reuses the token object. This allows us + // to avoid allocations and minimize GC pauses. + if (!lastToken) { + lastToken = { startLoc: {}, endLoc: {} }; + } + lastToken.start = token.start; + lastToken.end = token.end; + lastToken.startLoc.line = token.startLoc.line; + lastToken.startLoc.column = token.startLoc.column; + lastToken.endLoc.line = token.endLoc.line; + lastToken.endLoc.column = token.endLoc.column; + lastToken.type = token.type; + lastToken.value = token.value; + lastToken.isArrayLiteral = token.isArrayLiteral; + + // Apply all the comments that have been queued up. + if (commentQueue.length) { + if (!addedNewline) { + write("\n"); + } + for (var i = 0, n = commentQueue.length; i < n; i++) { + var comment = commentQueue[i]; + addComment(write, indentLevel, options, comment.block, comment.text, + comment.line, comment.column); + } + addedNewline = true; + commentQueue.splice(0, commentQueue.length); + } + } + + return result.toStringWithSourceMap({ file: options.url }); + }; + +}.bind(this))); diff --git a/toolkit/devtools/escodegen/tests/unit/head_escodegen.js b/toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js similarity index 82% rename from toolkit/devtools/escodegen/tests/unit/head_escodegen.js rename to toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js index 1a51912ec72..0dfdca9c59e 100644 --- a/toolkit/devtools/escodegen/tests/unit/head_escodegen.js +++ b/toolkit/devtools/pretty-fast/tests/unit/head_pretty-fast.js @@ -7,6 +7,11 @@ const Cr = Components.results; const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); const { require } = devtools; +this.sourceMap = require("source-map"); +this.acorn = require("acorn"); +this.prettyFast = require("devtools/pretty-fast"); +const { console } = Cu.import("resource://gre/modules/devtools/Console.jsm", {}); + // Register a console listener, so console messages don't just disappear // into the ether. let errorCount = 0; @@ -31,7 +36,7 @@ let listener = { } } - do_throw("head_dbg.js got console message: " + string + "\n"); + do_throw("head_pretty-fast.js got console message: " + string + "\n"); } }; diff --git a/toolkit/devtools/pretty-fast/tests/unit/test.js b/toolkit/devtools/pretty-fast/tests/unit/test.js new file mode 100644 index 00000000000..bada192e487 --- /dev/null +++ b/toolkit/devtools/pretty-fast/tests/unit/test.js @@ -0,0 +1,470 @@ +/* + * Copyright 2013 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.md or: + * http://opensource.org/licenses/BSD-2-Clause + */ +var prettyFast = this.prettyFast || require("./pretty-fast"); + +var testCases = [ + { + name: "Simple function", + input: "function foo() { bar(); }", + output: "function foo() {\n" + + " bar();\n" + + "}\n", + mappings: [ + // function foo() { + { + inputLine: 1, + outputLine: 1 + }, + // bar(); + { + inputLine: 1, + outputLine: 2 + }, + // } + { + inputLine: 1, + outputLine: 3 + }, + ] + }, + + { + name: "Nested function", + input: "function foo() { function bar() { debugger; } bar(); }", + output: "function foo() {\n" + + " function bar() {\n" + + " debugger;\n" + + " }\n" + + " bar();\n" + + "}\n", + mappings: [ + // function bar() { + { + inputLine: 1, + outputLine: 2 + }, + // debugger; + { + inputLine: 1, + outputLine: 3 + }, + // bar(); + { + inputLine: 1, + outputLine: 5 + }, + ] + }, + + { + name: "Immediately invoked function expression", + input: "(function(){thingy()}())", + output: "(function () {\n" + + " thingy()\n" + + "}())\n" + }, + + { + name: "Single line comment", + input: "// Comment\n" + + "function foo() { bar(); }\n", + output: "// Comment\n" + + "function foo() {\n" + + " bar();\n" + + "}\n", + mappings: [ + // // Comment + { + inputLine: 1, + outputLine: 1 + } + ] + }, + + { + name: "Multi line comment", + input: "/* Comment\n" + + "more comment */\n" + + "function foo() { bar(); }\n", + output: "/* Comment\n" + + "more comment */\n" + + "function foo() {\n" + + " bar();\n" + + "}\n", + mappings: [ + // /* Comment + { + inputLine: 1, + outputLine: 1 + }, + // \nmore comment */ + { + inputLine: 1, + outputLine: 2 + } + ] + }, + + { + name: "Null assignment", + input: "var i=null;\n", + output: "var i = null;\n", + mappings: [ + { + inputLine: 1, + outputLine: 1 + } + ] + }, + + { + name: "Undefined assignment", + input: "var i=undefined;\n", + output: "var i = undefined;\n" + }, + + { + name: "Void 0 assignment", + input: "var i=void 0;\n", + output: "var i = void 0;\n" + }, + + { + name: "This property access", + input: "var foo=this.foo;\n", + output: "var foo = this.foo;\n" + }, + + { + name: "True assignment", + input: "var foo=true;\n", + output: "var foo = true;\n" + }, + + { + name: "False assignment", + input: "var foo=false;\n", + output: "var foo = false;\n" + }, + + { + name: "For loop", + input: "for (var i = 0; i < n; i++) { console.log(i); }", + output: "for (var i = 0; i < n; i++) {\n" + + " console.log(i);\n" + + "}\n", + mappings: [ + // for (var i = 0; i < n; i++) { + { + inputLine: 1, + outputLine: 1 + }, + // console.log(i); + { + inputLine: 1, + outputLine: 2 + }, + ] + }, + + { + name: "String with semicolon", + input: "var foo = ';';\n", + output: "var foo = ';';\n" + }, + + { + name: "String with quote", + input: "var foo = \"'\";\n", + output: "var foo = '\'';\n" + }, + + { + name: "Function calls", + input: "var result=func(a,b,c,d);", + output: "var result = func(a, b, c, d);\n" + }, + + { + name: "Regexp", + input: "var r=/foobar/g;", + output: "var r = /foobar/g;\n" + }, + + { + name: "In operator", + input: "if(foo in bar){doThing()}", + output: "if (foo in bar) {\n" + + " doThing()\n" + + "}\n" + }, + + { + name: "With statement", + input: "with(obj){crock()}", + output: "with (obj) {\n" + + " crock()\n" + + "}\n" + }, + + { + name: "New expression", + input: "var foo=new Foo();", + output: "var foo = new Foo();\n" + }, + + { + name: "Continue/break statements", + input: "while(1){if(x){continue}if(y){break}}", + output: "while (1) {\n" + + " if (x) {\n" + + " continue\n" + + " }\n" + + " if (y) {\n" + + " break\n" + + " }\n" + + "}\n" + }, + + { + name: "Instanceof", + input: "var a=x instanceof y;", + output: "var a = x instanceof y;\n" + }, + + { + name: "Binary operators", + input: "var a=5*30;var b=5>>3;", + output: "var a = 5 * 30;\n" + + "var b = 5 >> 3;\n" + }, + + { + name: "Delete", + input: "delete obj.prop;", + output: "delete obj.prop;\n" + }, + + { + name: "Try/catch/finally statement", + input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}", + output: "try {\n" + + " dangerous()\n" + + "} catch (e) {\n" + + " handle(e)\n" + + "} finally {\n" + + " cleanup()\n" + + "}\n" + }, + + { + name: "If/else statement", + input: "if(c){then()}else{other()}", + output: "if (c) {\n" + + " then()\n" + + "} else {\n" + + " other()\n" + + "}\n" + }, + + { + name: "If/else without curlies", + input: "if(c) a else b", + output: "if (c) a else b\n" + }, + + { + name: "Objects", + input: "var o={a:1,\n" + + " b:2};", + output: "var o = {\n" + + " a: 1,\n" + + " b: 2\n" + + "};\n", + mappings: [ + // a: 1, + { + inputLine: 1, + outputLine: 2 + }, + // b: 2 + { + inputLine: 2, + outputLine: 3 + }, + ] + }, + + { + name: "Do/while loop", + input: "do{x}while(y)", + output: "do {\n" + + " x\n" + + "} while (y)\n" + }, + + { + name: "Arrays", + input: "var a=[1,2,3];", + output: "var a = [\n" + + " 1,\n" + + " 2,\n" + + " 3\n" + + "];\n" + }, + + { + name: "Code that relies on ASI", + input: "var foo = 10\n" + + "var bar = 20\n" + + "function g() {\n" + + " a()\n" + + " b()\n" + + "}", + output: "var foo = 10\n" + + "var bar = 20\n" + + "function g() {\n" + + " a()\n" + + " b()\n" + + "}\n" + }, + + { + name: "Ternary operator", + input: "bar?baz:bang;", + output: "bar ? baz : bang;\n" + }, + + { + name: "Switch statements", + input: "switch(x){case a:foo();break;default:bar()}", + output: "switch (x) {\n" + + "case a:\n" + + " foo();\n" + + " break;\n" + + "default:\n" + + " bar()\n" + + "}\n" + }, + + { + name: "Multiple single line comments", + input: "function f() {\n" + + " // a\n" + + " // b\n" + + " // c\n" + + "}\n", + output: "function f() {\n" + + " // a\n" + + " // b\n" + + " // c\n" + + "}\n", + }, + + { + name: "Indented multiline comment", + input: "function foo() {\n" + + " /**\n" + + " * java doc style comment\n" + + " * more comment\n" + + " */\n" + + " bar();\n" + + "}\n", + output: "function foo() {\n" + + " /**\n" + + " * java doc style comment\n" + + " * more comment\n" + + " */\n" + + " bar();\n" + + "}\n", + }, + + { + name: "ASI return", + input: "function f() {\n" + + " return\n" + + " {}\n" + + "}\n", + output: "function f() {\n" + + " return\n" + + " {\n" + + " }\n" + + "}\n", + }, + + { + name: "Non-ASI property access", + input: "[1,2,3]\n" + + "[0]", + output: "[\n" + + " 1,\n" + + " 2,\n" + + " 3\n" + + "]\n" + + "[0]\n" + }, + + { + name: "Non-ASI in", + input: "'x'\n" + + "in foo", + output: "'x' in foo\n" + }, + + { + name: "Non-ASI function call", + input: "f\n" + + "()", + output: "f()\n" + }, + + { + name: "Non-ASI new", + input: "new\n" + + "F()", + output: "new F()\n" + }, + +]; + +var sourceMap = this.sourceMap || require("source-map"); + +function run_test() { + testCases.forEach(function (test) { + console.log(test.name); + + var actual = prettyFast(test.input, { + indent: " ", + url: "test.js" + }); + + if (actual.code !== test.output) { + throw new Error("Expected:\n" + test.output + + "\nGot:\n" + actual.code); + } + + if (test.mappings) { + var smc = new sourceMap.SourceMapConsumer(actual.map.toJSON()); + test.mappings.forEach(function (m) { + var query = { line: m.outputLine, column: 0 }; + var original = smc.originalPositionFor(query); + if (original.line != m.inputLine) { + throw new Error("Querying:\n" + JSON.stringify(query, null, 2) + "\n" + + "Expected line:\n" + m.inputLine + "\n" + + "Got:\n" + JSON.stringify(original, null, 2)); + } + }); + } + }); + console.log("✓ All tests pass!"); +} + +// Only run the tests if this is node and we are running this file +// directly. (Firefox's test runner will import this test file, and then call +// run_test itself.) +if (typeof exports == "object") { + run_test(); +} diff --git a/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini b/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini new file mode 100644 index 00000000000..94833e29289 --- /dev/null +++ b/toolkit/devtools/pretty-fast/tests/unit/xpcshell.ini @@ -0,0 +1,5 @@ +[DEFAULT] +head = head_pretty-fast.js +tail = + +[test.js] diff --git a/toolkit/devtools/server/actors/pretty-print-worker.js b/toolkit/devtools/server/actors/pretty-print-worker.js index 404b24390a8..07fad4eaafe 100644 --- a/toolkit/devtools/server/actors/pretty-print-worker.js +++ b/toolkit/devtools/server/actors/pretty-print-worker.js @@ -8,11 +8,11 @@ * This file is meant to be loaded as a ChromeWorker. It accepts messages which * have data of the form: * - * { id, url, indent, ast } + * { id, url, indent, source } * * Where `id` is a unique ID to identify this request, `url` is the url of the * source being pretty printed, `indent` is the number of spaces to indent the - * code by, and `ast` is the source's abstract syntax tree. + * code by, and `source` is the source text. * * On success, the worker responds with a message of the form: * @@ -20,25 +20,23 @@ * * Where `id` is the same unique ID from the request, `code` is the pretty * printed source text, and `mappings` is an array or source mappings from the - * pretty printed code to the AST's source locations. + * pretty printed code back to the ugly source text. * * In the case of an error, the worker responds with a message of the form: * - * { error } + * { id, error } */ -importScripts("resource://gre/modules/devtools/escodegen/escodegen.worker.js"); +importScripts("resource://gre/modules/devtools/acorn.js"); +importScripts("resource://gre/modules/devtools/source-map.js"); +importScripts("resource://gre/modules/devtools/pretty-fast.js"); -self.onmessage = ({ data: { id, url, indent, ast } }) => { +self.onmessage = (event) => { + const { data: { id, url, indent, source } } = event; try { - const prettified = escodegen.generate(ast, { - format: { - indent: { - style: " ".repeat(indent) - } - }, - sourceMap: url, - sourceMapWithCode: true + const prettified = prettyFast(source, { + url: url, + indent: " ".repeat(indent) }); self.postMessage({ @@ -48,6 +46,7 @@ self.onmessage = ({ data: { id, url, indent, ast } }) => { }); } catch (e) { self.postMessage({ + id: id, error: e.message + "\n" + e.stack }); } diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index f11ceb4870b..715c9d52713 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -497,8 +497,8 @@ ThreadActor.prototype = { return this._prettyPrintWorker; }, - _onPrettyPrintError: function (error) { - reportError(new Error(error)); + _onPrettyPrintError: function ({ message, filename, lineno }) { + reportError(new Error(message + " @ " + filename + ":" + lineno)); }, _onPrettyPrintMsg: function ({ data }) { @@ -2459,7 +2459,6 @@ SourceActor.prototype = { onPrettyPrint: function ({ indent }) { this.threadActor.sources.prettyPrint(this._url, indent); return this._getSourceText() - .then(this._parseAST) .then(this._sendToPrettyPrintWorker(indent)) .then(this._invertSourceMap) .then(this._saveMap) @@ -2480,13 +2479,6 @@ SourceActor.prototype = { }); }, - /** - * Parse the source content into an AST. - */ - _parseAST: function SA__parseAST({ content}) { - return Reflect.parse(content); - }, - /** * Return a function that sends a request to the pretty print worker, waits on * the worker's response, and then returns the pretty printed code. @@ -2500,7 +2492,7 @@ SourceActor.prototype = { * printed code, and `mappings` is an array of source mappings. */ _sendToPrettyPrintWorker: function SA__sendToPrettyPrintWorker(aIndent) { - return aAST => { + return ({ content }) => { const deferred = promise.defer(); const id = Math.random(); @@ -2522,7 +2514,7 @@ SourceActor.prototype = { id: id, url: this._url, indent: aIndent, - ast: aAST + source: content }); return deferred.promise; diff --git a/toolkit/devtools/server/main.js b/toolkit/devtools/server/main.js index dad9ea1106a..a221682c3b8 100644 --- a/toolkit/devtools/server/main.js +++ b/toolkit/devtools/server/main.js @@ -74,7 +74,6 @@ loadSubScript.call(this, "resource://gre/modules/commonjs/sdk/core/promise.js"); this.require = loaderRequire; Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); -const escodegen = localRequire("escodegen/escodegen"); loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js"); diff --git a/toolkit/devtools/sourcemap/Makefile.in b/toolkit/devtools/sourcemap/Makefile.in index aad3588f054..aa6749658d5 100644 --- a/toolkit/devtools/sourcemap/Makefile.in +++ b/toolkit/devtools/sourcemap/Makefile.in @@ -7,3 +7,4 @@ include $(topsrcdir)/config/rules.mk libs:: $(NSINSTALL) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools + $(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools diff --git a/toolkit/devtools/sourcemap/source-map.js b/toolkit/devtools/sourcemap/source-map.js new file mode 100644 index 00000000000..57fe57f02f3 --- /dev/null +++ b/toolkit/devtools/sourcemap/source-map.js @@ -0,0 +1,1929 @@ +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +/** + * Define a module along with a payload. + * @param {string} moduleName Name for the payload + * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec + * @param {function} payload Function with (require, exports, module) params + */ +function define(moduleName, deps, payload) { + if (typeof moduleName != "string") { + throw new TypeError('Expected string, got: ' + moduleName); + } + + if (arguments.length == 2) { + payload = deps; + } + + if (moduleName in define.modules) { + throw new Error("Module already defined: " + moduleName); + } + define.modules[moduleName] = payload; +}; + +/** + * The global store of un-instantiated modules + */ +define.modules = {}; + + +/** + * We invoke require() in the context of a Domain so we can have multiple + * sets of modules running separate from each other. + * This contrasts with JSMs which are singletons, Domains allows us to + * optionally load a CommonJS module twice with separate data each time. + * Perhaps you want 2 command lines with a different set of commands in each, + * for example. + */ +function Domain() { + this.modules = {}; + this._currentModule = null; +} + +(function () { + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * There are 2 ways to call this, either with an array of dependencies and a + * callback to call when the dependencies are found (which can happen + * asynchronously in an in-page context) or with a single string an no callback + * where the dependency is resolved synchronously and returned. + * The API is designed to be compatible with the CommonJS AMD spec and + * RequireJS. + * @param {string[]|string} deps A name, or names for the payload + * @param {function|undefined} callback Function to call when the dependencies + * are resolved + * @return {undefined|object} The module required or undefined for + * array/callback method + */ + Domain.prototype.require = function(deps, callback) { + if (Array.isArray(deps)) { + var params = deps.map(function(dep) { + return this.lookup(dep); + }, this); + if (callback) { + callback.apply(null, params); + } + return undefined; + } + else { + return this.lookup(deps); + } + }; + + function normalize(path) { + var bits = path.split('/'); + var i = 1; + while (i < bits.length) { + if (bits[i] === '..') { + bits.splice(i-1, 1); + } else if (bits[i] === '.') { + bits.splice(i, 1); + } else { + i++; + } + } + return bits.join('/'); + } + + function join(a, b) { + a = a.trim(); + b = b.trim(); + if (/^\//.test(b)) { + return b; + } else { + return a.replace(/\/*$/, '/') + b; + } + } + + function dirname(path) { + var bits = path.split('/'); + bits.pop(); + return bits.join('/'); + } + + /** + * Lookup module names and resolve them by calling the definition function if + * needed. + * @param {string} moduleName A name for the payload to lookup + * @return {object} The module specified by aModuleName or null if not found. + */ + Domain.prototype.lookup = function(moduleName) { + if (/^\./.test(moduleName)) { + moduleName = normalize(join(dirname(this._currentModule), moduleName)); + } + + if (moduleName in this.modules) { + var module = this.modules[moduleName]; + return module; + } + + if (!(moduleName in define.modules)) { + throw new Error("Module not defined: " + moduleName); + } + + var module = define.modules[moduleName]; + + if (typeof module == "function") { + var exports = {}; + var previousModule = this._currentModule; + this._currentModule = moduleName; + module(this.require.bind(this), exports, { id: moduleName, uri: "" }); + this._currentModule = previousModule; + module = exports; + } + + // cache the resulting module object for next time + this.modules[moduleName] = module; + + return module; + }; + +}()); + +define.Domain = Domain; +define.globalDomain = new Domain(); +var require = define.globalDomain.require.bind(define.globalDomain); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-map-generator', ['require', 'exports', 'module' , 'source-map/base64-vlq', 'source-map/util', 'source-map/array-set'], function(require, exports, module) { + + var base64VLQ = require('./base64-vlq'); + var util = require('./util'); + var ArraySet = require('./array-set').ArraySet; + + /** + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. To create a new one, you must pass an object + * with the following properties: + * + * - file: The filename of the generated source. + * - sourceRoot: An optional root for all URLs in this source map. + */ + function SourceMapGenerator(aArgs) { + this._file = util.getArg(aArgs, 'file'); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = []; + this._sourcesContents = null; + } + + SourceMapGenerator.prototype._version = 3; + + /** + * Creates a new SourceMapGenerator based on a SourceMapConsumer + * + * @param aSourceMapConsumer The SourceMap. + */ + SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source) { + newMapping.source = mapping.source; + if (sourceRoot) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + + /** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: + * + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. + */ + SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); + + this._validateMapping(generated, original, source, name); + + if (source && !this._sources.has(source)) { + this._sources.add(source); + } + + if (name && !this._names.has(name)) { + this._names.add(name); + } + + this._mappings.push({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; + + /** + * Set the source content for a source file. + */ + SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent !== null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = {}; + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; + + /** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + */ + SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile) { + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (!aSourceFile) { + aSourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "aSourceFile" relative if an absolute Url is passed. + if (sourceRoot) { + aSourceFile = util.relative(sourceRoot, aSourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + + // Find mappings for the "aSourceFile" + this._mappings.forEach(function (mapping) { + if (mapping.source === aSourceFile && mapping.originalLine) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source !== null) { + // Copy mapping + if (sourceRoot) { + mapping.source = util.relative(sourceRoot, original.source); + } else { + mapping.source = original.source; + } + 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 + mapping.name = original.name; + } + } + } + + var source = mapping.source; + if (source && !newSources.has(source)) { + newSources.add(source); + } + + var name = mapping.name; + if (name && !newNames.has(name)) { + newNames.add(name); + } + + }, this); + this._sources = newSources; + this._names = newNames; + + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + if (sourceRoot) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; + + /** + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. + */ + SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + orginal: aOriginal, + name: aName + })); + } + }; + + /** + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. + */ + SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var mapping; + + // The mappings must be guaranteed to be in sorted order before we start + // serializing them or else the generated line numbers (which are defined + // via the ';' separators) will be all messed up. Note: it might be more + // performant to maintain the sorting as we insert them, rather than as we + // serialize them, but the big O is the same either way. + this._mappings.sort(util.compareByGeneratedPositions); + + for (var i = 0, len = this._mappings.length; i < len; i++) { + mapping = this._mappings[i]; + + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + result += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositions(mapping, this._mappings[i - 1])) { + continue; + } + result += ','; + } + } + + result += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; + + 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.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; + + result += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; + + if (mapping.name) { + result += base64VLQ.encode(this._names.indexOf(mapping.name) + - previousName); + previousName = this._names.indexOf(mapping.name); + } + } + } + + 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. + */ + SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + file: this._file, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._sourceRoot) { + map.sourceRoot = this._sourceRoot; + } + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); + } + + return map; + }; + + /** + * Render the source map being generated to a string. + */ + SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this); + }; + + exports.SourceMapGenerator = SourceMapGenerator; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + * + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +define('source-map/base64-vlq', ['require', 'exports', 'module' , 'source-map/base64'], function(require, exports, module) { + + var base64 = require('./base64'); + + // A single base 64 digit can contain 6 bits of data. For the base 64 variable + // length quantities we use in the source map spec, the first bit is the sign, + // the next four bits are the actual value, and the 6th bit is the + // continuation bit. The continuation bit tells us whether there are more + // digits in this value following this digit. + // + // Continuation + // | Sign + // | | + // V V + // 101011 + + var VLQ_BASE_SHIFT = 5; + + // binary: 100000 + var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + + // binary: 011111 + var VLQ_BASE_MASK = VLQ_BASE - 1; + + // binary: 100000 + var VLQ_CONTINUATION_BIT = VLQ_BASE; + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ + function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ + function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; + } + + /** + * Returns the base 64 VLQ encoded value. + */ + exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; + + var vlq = toVLQSigned(aValue); + + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; + } + encoded += base64.encode(digit); + } while (vlq > 0); + + return encoded; + }; + + /** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string. + */ + exports.decode = function base64VLQ_decode(aStr) { + var i = 0; + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; + + do { + if (i >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } + digit = base64.decode(aStr.charAt(i++)); + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); + + return { + value: fromVLQSigned(result), + rest: aStr.slice(i) + }; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/base64', ['require', 'exports', 'module' , ], function(require, exports, module) { + + var charToIntMap = {}; + var intToCharMap = {}; + + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + .split('') + .forEach(function (ch, index) { + charToIntMap[ch] = index; + intToCharMap[index] = ch; + }); + + /** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ + exports.encode = function base64_encode(aNumber) { + if (aNumber in intToCharMap) { + return intToCharMap[aNumber]; + } + throw new TypeError("Must be between 0 and 63: " + aNumber); + }; + + /** + * Decode a single base 64 digit to an integer. + */ + exports.decode = function base64_decode(aChar) { + if (aChar in charToIntMap) { + return charToIntMap[aChar]; + } + throw new TypeError("Not a valid base 64 digit: " + aChar); + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/util', ['require', 'exports', 'module' , ], function(require, exports, module) { + + /** + * This is a helper function for getting values from parameter/options + * objects. + * + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. + */ + function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } + } + exports.getArg = getArg; + + var urlRegexp = /([\w+\-.]+):\/\/((\w+:\w+)@)?([\w.]+)?(:(\d+))?(\S+)?/; + var dataUrlRegexp = /^data:.+\,.+/; + + function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; + } + return { + scheme: match[1], + auth: match[3], + host: match[4], + port: match[6], + path: match[7] + }; + } + exports.urlParse = urlParse; + + 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; + + if (aPath.match(urlRegexp) || aPath.match(dataUrlRegexp)) { + return aPath; + } + + if (aPath.charAt(0) === '/' && (url = urlParse(aRoot))) { + url.path = aPath; + return urlGenerate(url); + } + + return aRoot.replace(/\/$/, '') + '/' + aPath; + } + exports.join = join; + + /** + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. + * + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 + * + * @param String aStr + */ + function toSetString(aStr) { + return '$' + aStr; + } + exports.toSetString = toSetString; + + function fromSetString(aStr) { + return aStr.substr(1); + } + exports.fromSetString = fromSetString; + + function relative(aRoot, aPath) { + aRoot = aRoot.replace(/\/$/, ''); + + var url = urlParse(aRoot); + if (aPath.charAt(0) == "/" && url && url.path == "/") { + return aPath.slice(1); + } + + return aPath.indexOf(aRoot + '/') === 0 + ? aPath.substr(aRoot.length + 1) + : aPath; + } + exports.relative = relative; + + 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; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/array-set', ['require', 'exports', 'module' , 'source-map/util'], function(require, exports, module) { + + var util = require('./util'); + + /** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ + function ArraySet() { + this._array = []; + this._set = {}; + } + + /** + * Static method for creating ArraySet instances from an existing array. + */ + ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); + } + return set; + }; + + /** + * Add the given string to this set. + * + * @param String aStr + */ + ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var isDuplicate = this.has(aStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + this._set[util.toSetString(aStr)] = idx; + } + }; + + /** + * Is the given string a member of this set? + * + * @param String aStr + */ + ArraySet.prototype.has = function ArraySet_has(aStr) { + return Object.prototype.hasOwnProperty.call(this._set, + util.toSetString(aStr)); + }; + + /** + * What is the index of the given string in the array? + * + * @param String aStr + */ + ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (this.has(aStr)) { + return this._set[util.toSetString(aStr)]; + } + throw new Error('"' + aStr + '" is not in the set.'); + }; + + /** + * What is the element at the given index? + * + * @param Number aIdx + */ + ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); + }; + + /** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. + */ + ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); + }; + + exports.ArraySet = ArraySet; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-map-consumer', ['require', 'exports', 'module' , 'source-map/util', 'source-map/binary-search', 'source-map/array-set', 'source-map/base64-vlq'], function(require, exports, module) { + + var util = require('./util'); + var binarySearch = require('./binary-search'); + var ArraySet = require('./array-set').ArraySet; + var base64VLQ = require('./base64-vlq'); + + /** + * A SourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. + * + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + */ + function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + var names = util.getArg(sourceMap, 'names'); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); + + if (version !== this._version) { + throw new Error('Unsupported version: ' + version); + } + + // 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._mappings = mappings; + this.file = file; + } + + /** + * 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. + */ + SourceMapConsumer.prototype._version = 3; + + /** + * The list of original sources. + */ + Object.defineProperty(SourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot ? util.join(this.sourceRoot, s) : s; + }, this); + } + }); + + // `__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 (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). + */ + SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var mappingSeparator = /^[,;]/; + var str = aStr; + var mapping; + var temp; + + while (str.length > 0) { + if (str.charAt(0) === ';') { + generatedLine++; + str = str.slice(1); + previousGeneratedColumn = 0; + } + else if (str.charAt(0) === ',') { + str = str.slice(1); + } + else { + mapping = {}; + mapping.generatedLine = generatedLine; + + // Generated column. + temp = base64VLQ.decode(str); + mapping.generatedColumn = previousGeneratedColumn + temp.value; + previousGeneratedColumn = mapping.generatedColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original source. + temp = base64VLQ.decode(str); + mapping.source = this._sources.at(previousSource + temp.value); + previousSource += temp.value; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source, but no line and column'); + } + + // Original line. + temp = base64VLQ.decode(str); + mapping.originalLine = previousOriginalLine + temp.value; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; + str = temp.rest; + if (str.length === 0 || mappingSeparator.test(str.charAt(0))) { + throw new Error('Found a source and line, but no column'); + } + + // Original column. + temp = base64VLQ.decode(str); + mapping.originalColumn = previousOriginalColumn + temp.value; + previousOriginalColumn = mapping.originalColumn; + str = temp.rest; + + if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) { + // Original name. + temp = base64VLQ.decode(str); + mapping.name = this._names.at(previousName + temp.value); + previousName += temp.value; + str = temp.rest; + } + } + + this.__generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + this.__originalMappings.push(mapping); + } + } + } + + this.__originalMappings.sort(util.compareByOriginalPositions); + }; + + /** + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. + */ + SourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. + + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } + + return binarySearch.search(aNeedle, aMappings, aComparator); + }; + + /** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ + SourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; + + var mapping = this._findMapping(needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositions); + + if (mapping) { + var source = util.getArg(mapping, 'source', null); + if (source && this.sourceRoot) { + source = util.join(this.sourceRoot, source); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: util.getArg(mapping, 'name', null) + }; + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; + + /** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * availible. + */ + SourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource) { + if (!this.sourcesContent) { + return null; + } + + if (this.sourceRoot) { + 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.'); + }; + + /** + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. + */ + SourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; + + if (this.sourceRoot) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + + var mapping = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions); + + if (mapping) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null) + }; + } + + return { + line: null, + column: null + }; + }; + + SourceMapConsumer.GENERATED_ORDER = 1; + SourceMapConsumer.ORIGINAL_ORDER = 2; + + /** + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. + * + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. + */ + SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; + + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } + + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source; + if (source && sourceRoot) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name + }; + }).forEach(aCallback, context); + }; + + exports.SourceMapConsumer = SourceMapConsumer; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/binary-search', ['require', 'exports', 'module' , ], function(require, exports, module) { + + /** + * Recursive implementation of binary search. + * + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + */ + function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the next + // closest element that is less than that element. + // + // 3. We did not find the exact element, and there is no next-closest + // element which is less than the one we are searching for, so we + // return null. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return aHaystack[mid]; + } + else if (cmp > 0) { + // aHaystack[mid] is greater than our needle. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare); + } + // We did not find an exact match, return the next closest one + // (termination case 2). + return aHaystack[mid]; + } + else { + // aHaystack[mid] is less than our needle. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare); + } + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (2) or (3) and return the appropriate thing. + return aLow < 0 + ? null + : aHaystack[aLow]; + } + } + + /** + * This is an implementation of binary search which will always try and return + * the next lowest value checked if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + */ + exports.search = function search(aNeedle, aHaystack, aCompare) { + return aHaystack.length > 0 + ? recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, aCompare) + : null; + }; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +define('source-map/source-node', ['require', 'exports', 'module' , 'source-map/source-map-generator', 'source-map/util'], function(require, exports, module) { + + var SourceMapGenerator = require('./source-map-generator').SourceMapGenerator; + var util = require('./util'); + + /** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. + * + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ + function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine === undefined ? null : aLine; + this.column = aColumn === undefined ? null : aColumn; + this.source = aSource === undefined ? null : aSource; + this.name = aName === undefined ? null : aName; + if (aChunks != null) this.add(aChunks); + } + + /** + * Creates a SourceNode from generated code and a SourceMapConsumer. + * + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + */ + SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); + + // The generated code + // Processed fragments are removed from this array. + var remainingLines = aGeneratedCode.split('\n'); + + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; + + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; + + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping === null) { + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(remainingLines.shift() + "\n"); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + } else { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + var code = ""; + // Associate full lines with "lastMapping" + do { + code += remainingLines.shift() + "\n"; + lastGeneratedLine++; + lastGeneratedColumn = 0; + } while (lastGeneratedLine < mapping.generatedLine); + // When we reached the correct line, we add code until we + // reach the correct column too. + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[0]; + code += nextLine.substr(0, mapping.generatedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + // Create the SourceNode. + addMappingWithCode(lastMapping, code); + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[0]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[0] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + } + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + // Associate the remaining code in the current line with "lastMapping" + // and add the remaining lines without any mapping + addMappingWithCode(lastMapping, remainingLines.join("\n")); + + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content) { + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + mapping.source, + code, + mapping.name)); + } + } + }; + + /** + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. + */ + SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk instanceof SourceNode || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; + }; + + /** + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk instanceof SourceNode) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } + }; + + /** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ + SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); + } + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; + }; + + /** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ + SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild instanceof SourceNode) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; + }; + + /** + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file + */ + SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; + + /** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ + SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i] instanceof SourceNode) { + this.children[i].walkSourceContents(aFn); + } + } + + 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]]); + } + }; + + /** + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. + */ + SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; + }; + + /** + * Returns the string representation of this source node along with a source + * map. + */ + SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + 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) { + 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({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + chunk.split('').forEach(function (ch) { + if (ch === '\n') { + generated.line++; + generated.column = 0; + } else { + generated.column++; + } + }); + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); + + return { code: generated.code, map: map }; + }; + + exports.SourceNode = SourceNode; + +}); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/////////////////////////////////////////////////////////////////////////////// + +this.sourceMap = { + SourceMapConsumer: require('source-map/source-map-consumer').SourceMapConsumer, + SourceMapGenerator: require('source-map/source-map-generator').SourceMapGenerator, + SourceNode: require('source-map/source-node').SourceNode +}; From 7901827956d13febe533e295409ffb84718abf4b Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Wed, 6 Nov 2013 08:40:37 +0100 Subject: [PATCH 52/53] Backed out changeset 48ba597444e8 (bug 934091) for linux build bustage on a CLOSED TREE --- docshell/base/nsDocShell.cpp | 19 ++++--------------- dom/base/nsGlobalWindow.cpp | 25 +++++++------------------ 2 files changed, 11 insertions(+), 33 deletions(-) diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 68775674ed1..b7f782de70a 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -194,11 +194,6 @@ static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID); #define DEBUG_PAGE_CACHE #endif -#ifdef XP_WIN -#include -#define getpid _getpid -#endif - using namespace mozilla; using namespace mozilla::dom; @@ -800,11 +795,8 @@ nsDocShell::nsDocShell(): // We're counting the number of |nsDocShells| to help find leaks ++gNumberOfDocShells; if (!PR_GetEnv("MOZ_QUIET")) { - printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n", - (void*) this, - gNumberOfDocShells, - getpid(), - SafeCast(mHistoryID)); + printf("++DOCSHELL %p == %ld [id = %llu]\n", (void*) this, + gNumberOfDocShells, SafeCast(mHistoryID)); } #endif } @@ -832,11 +824,8 @@ nsDocShell::~nsDocShell() // We're counting the number of |nsDocShells| to help find leaks --gNumberOfDocShells; if (!PR_GetEnv("MOZ_QUIET")) { - printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %llu]\n", - (void*) this, - gNumberOfDocShells, - getpid(), - SafeCast(mHistoryID)); + printf("--DOCSHELL %p == %ld [id = %llu]\n", (void*) this, + gNumberOfDocShells, SafeCast(mHistoryID)); } #endif } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f37871724d2..8431f2d0017 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -237,11 +237,6 @@ class nsIScriptTimeoutHandler; static PRLogModuleInfo* gDOMLeakPRLog; #endif -#ifdef XP_WIN -#include -#define getpid _getpid -#endif - static const char kStorageEnabled[] = "dom.storage.enabled"; using namespace mozilla; @@ -1126,12 +1121,10 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) #ifdef DEBUG if (!PR_GetEnv("MOZ_QUIET")) { - printf_stderr("++DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p]\n", - gRefCnt, - static_cast(static_cast(this)), - getpid(), - gSerialCounter, - static_cast(static_cast(aOuterWindow))); + printf("++DOMWINDOW == %d (%p) [serial = %d] [outer = %p]\n", gRefCnt, + static_cast(static_cast(this)), + gSerialCounter, + static_cast(static_cast(aOuterWindow))); } #endif @@ -1204,13 +1197,9 @@ nsGlobalWindow::~nsGlobalWindow() } nsGlobalWindow* outer = static_cast(mOuterWindow.get()); - printf_stderr("--DOMWINDOW == %d (%p) [pid = %d] [serial = %d] [outer = %p] [url = %s]\n", - gRefCnt, - static_cast(static_cast(this)), - getpid(), - mSerial, - static_cast(static_cast(outer)), - url.get()); + printf("--DOMWINDOW == %d (%p) [serial = %d] [outer = %p] [url = %s]\n", + gRefCnt, static_cast(static_cast(this)), + mSerial, static_cast(static_cast(outer)), url.get()); } #endif From 8e4b141726781f14ec302282dbe7dba3b79ebb6e Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Tue, 5 Nov 2013 23:50:30 -0800 Subject: [PATCH 53/53] Bumping gaia.json for 2 gaia-central revision(s) a=gaia-bump ======== https://hg.mozilla.org/integration/gaia-central/rev/5cc807be4ece Author: George Desc: Merge pull request #11985 from cctuan/911676 Bug 911676 - check navigator.mozTelephony statements robustness ======== https://hg.mozilla.org/integration/gaia-central/rev/171659274531 Author: cctuan Desc: Bug 911676 - check navigator.mozTelephony statements robustness --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 3ee49b9b29a..43bf0724e46 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "6debe3af1446cfa0e3057762e5e491d81599806f", + "revision": "5cc807be4ece02c364c1d7f1cd2becbe1a1b441e", "repo_path": "/integration/gaia-central" }