From f9d0caa11263fb606033eb5e2fc6c101e0e36e45 Mon Sep 17 00:00:00 2001 From: Christopher Allen Date: Tue, 14 Sep 2021 14:39:29 +0100 Subject: [PATCH] Migrate core.global.js to named exports (#5451) This is part of #5153 but is being prioritised because we want remove the declareLegacyNamespace calls from the core/utils/*.js modules and then reexport them explicitly via utils.js, and it turns out that doing so results in the exports object of this module being passed to Object.freeze - which fails on the global object, which can't be made non-extensible! The new name chosen for the former default export is globalThis, since it is intended to have the same value as the global variable of that name; see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis --- core/browser_events.js | 6 +++--- core/msg.js | 10 +++++----- core/touch.js | 14 +++++++------- core/utils.js | 6 +++--- core/utils/global.js | 9 +++++---- core/utils/useragent.js | 6 +++--- core/workspace_audio.js | 6 +++--- generators/javascript.js | 2 +- scripts/migration/renamings.js | 3 +++ scripts/package/node/core.js | 7 ++++--- tests/deps.js | 2 +- 11 files changed, 38 insertions(+), 33 deletions(-) diff --git a/core/browser_events.js b/core/browser_events.js index b7ce3a61e..fc03c6028 100644 --- a/core/browser_events.js +++ b/core/browser_events.js @@ -14,7 +14,7 @@ goog.module('Blockly.browserEvents'); goog.module.declareLegacyNamespace(); const Touch = goog.require('Blockly.Touch'); -const global = goog.require('Blockly.utils.global'); +const {globalThis} = goog.require('Blockly.utils.global'); /** @@ -69,7 +69,7 @@ const conditionalBind = function( }; const bindData = []; - if (global['PointerEvent'] && (name in Touch.TOUCH_MAP)) { + if (globalThis['PointerEvent'] && (name in Touch.TOUCH_MAP)) { for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { const type = Touch.TOUCH_MAP[name][i]; node.addEventListener(type, wrapFunc, false); @@ -124,7 +124,7 @@ const bind = function(node, name, thisObject, func) { }; const bindData = []; - if (global['PointerEvent'] && (name in Touch.TOUCH_MAP)) { + if (globalThis['PointerEvent'] && (name in Touch.TOUCH_MAP)) { for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) { const type = Touch.TOUCH_MAP[name][i]; node.addEventListener(type, wrapFunc, false); diff --git a/core/msg.js b/core/msg.js index 506473094..ff2de0fc3 100644 --- a/core/msg.js +++ b/core/msg.js @@ -17,16 +17,16 @@ goog.module('Blockly.Msg'); goog.module.declareLegacyNamespace(); -const global = goog.require('Blockly.utils.global'); +const {globalThis} = goog.require('Blockly.utils.global'); /** * Exported so that if Blockly is compiled with ADVANCED_COMPILATION, * the Blockly.Msg object exists for message files included in script tags. */ -if (!global['Blockly']) { - global['Blockly'] = {}; +if (!globalThis['Blockly']) { + globalThis['Blockly'] = {}; } -if (!global['Blockly']['Msg']) { - global['Blockly']['Msg'] = exports; +if (!globalThis['Blockly']['Msg']) { + globalThis['Blockly']['Msg'] = exports; } diff --git a/core/touch.js b/core/touch.js index daa95722f..f17667fff 100644 --- a/core/touch.js +++ b/core/touch.js @@ -16,7 +16,7 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const Gesture = goog.requireType('Blockly.Gesture'); const internalConstants = goog.require('Blockly.internalConstants'); -const utilsGlobal = goog.require('Blockly.utils.global'); +const {globalThis} = goog.require('Blockly.utils.global'); const utilsString = goog.require('Blockly.utils.string'); @@ -26,13 +26,13 @@ const utilsString = goog.require('Blockly.utils.string'); * @const */ const TOUCH_ENABLED = - ('ontouchstart' in utilsGlobal || - !!(utilsGlobal['document'] && document.documentElement && + ('ontouchstart' in globalThis || + !!(globalThis['document'] && document.documentElement && 'ontouchstart' in document.documentElement) || // IE10 uses non-standard touch events, so it has a different check. - !!(utilsGlobal['navigator'] && - (utilsGlobal['navigator']['maxTouchPoints'] || - utilsGlobal['navigator']['msMaxTouchPoints']))); + !!(globalThis['navigator'] && + (globalThis['navigator']['maxTouchPoints'] || + globalThis['navigator']['msMaxTouchPoints']))); exports.TOUCH_ENABLED = TOUCH_ENABLED; /** @@ -47,7 +47,7 @@ let touchIdentifier_ = null; * @type {Object} */ let TOUCH_MAP = {}; -if (utilsGlobal['PointerEvent']) { +if (globalThis['PointerEvent']) { TOUCH_MAP = { 'mousedown': ['pointerdown'], 'mouseenter': ['pointerenter'], diff --git a/core/utils.js b/core/utils.js index 33b7587a8..cb711e1a8 100644 --- a/core/utils.js +++ b/core/utils.js @@ -28,7 +28,7 @@ const Rect = goog.require('Blockly.utils.Rect'); const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); const colourUtils = goog.require('Blockly.utils.colour'); const deprecation = goog.require('Blockly.utils.deprecation'); -const global = goog.require('Blockly.utils.global'); +const {globalThis} = goog.require('Blockly.utils.global'); const idGenerator = goog.require('Blockly.utils.idGenerator'); const internalConstants = goog.require('Blockly.internalConstants'); const stringUtils = goog.require('Blockly.utils.string'); @@ -433,7 +433,7 @@ const is3dSupported = function() { } // CC-BY-SA Lorenzo Polidori // stackoverflow.com/questions/5661671/detecting-transform-translate3d-support - if (!global['getComputedStyle']) { + if (!globalThis['getComputedStyle']) { return false; } @@ -453,7 +453,7 @@ const is3dSupported = function() { for (let t in transforms) { if (el.style[t] !== undefined) { el.style[t] = 'translate3d(1px,1px,1px)'; - const computedStyle = global['getComputedStyle'](el); + const computedStyle = globalThis['getComputedStyle'](el); if (!computedStyle) { // getComputedStyle in Firefox returns null when Blockly is loaded // inside an iframe with display: none. Returning false and not diff --git a/core/utils/global.js b/core/utils/global.js index 7474f77c9..75b9241bf 100644 --- a/core/utils/global.js +++ b/core/utils/global.js @@ -20,7 +20,10 @@ goog.module.declareLegacyNamespace(); * More info on this implementation here: * https://docs.google.com/document/d/1NAeW4Wk7I7FV0Y2tcUFvQdGMc89k2vdgSXInw8_nvCI */ -const utilsGlobal = function() { +exports.globalThis = (function() { // Not "let globalThis" to avoid shadowing. + if (typeof globalThis === 'object') { + return globalThis; + } if (typeof self === 'object') { return self; } @@ -31,6 +34,4 @@ const utilsGlobal = function() { return global; } return this; -}(); - -exports = utilsGlobal; +})(); diff --git a/core/utils/useragent.js b/core/utils/useragent.js index 8ae95381d..011e72eb0 100644 --- a/core/utils/useragent.js +++ b/core/utils/useragent.js @@ -19,7 +19,7 @@ goog.module('Blockly.utils.userAgent'); goog.module.declareLegacyNamespace(); -const global = goog.require('Blockly.utils.global'); +const {globalThis} = goog.require('Blockly.utils.global'); /** @@ -100,7 +100,7 @@ isGecko = has('Gecko') && !isWebKit && !isIe && !isEdge; // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/extra.js isAndroid = has('Android'); const maxTouchPoints = - global['navigator'] && global['navigator']['maxTouchPoints']; + globalThis['navigator'] && globalThis['navigator']['maxTouchPoints']; isIPad = has('iPad') || has('Macintosh') && maxTouchPoints > 0; isIPod = has('iPod'); isIPhone = has('iPhone') && !isIPad && !isIPod; @@ -110,7 +110,7 @@ isMac = has('Macintosh'); // https://github.com/google/closure-library/blob/master/closure/goog/labs/useragent/device.js isTablet = isIPad || (isAndroid && !has('Mobile')) || has('Silk'); isMobile = !isTablet && (isIPod || isIPhone || isAndroid || has('IEMobile')); -})((global['navigator'] && global['navigator']['userAgent']) || ''); +})((globalThis['navigator'] && globalThis['navigator']['userAgent']) || ''); /** @const {string} */ exports.raw = rawUserAgent; diff --git a/core/workspace_audio.js b/core/workspace_audio.js index ba1da0c95..178657baf 100644 --- a/core/workspace_audio.js +++ b/core/workspace_audio.js @@ -16,7 +16,7 @@ goog.module.declareLegacyNamespace(); /* eslint-disable-next-line no-unused-vars */ const WorkspaceSvg = goog.requireType('Blockly.WorkspaceSvg'); -const global = goog.require('Blockly.utils.global'); +const {globalThis} = goog.require('Blockly.utils.global'); const internalConstants = goog.require('Blockly.internalConstants'); const userAgent = goog.require('Blockly.utils.userAgent'); @@ -72,7 +72,7 @@ WorkspaceAudio.prototype.load = function(filenames, name) { } let audioTest; try { - audioTest = new global['Audio'](); + audioTest = new globalThis['Audio'](); } catch (e) { // No browser support for Audio. // IE can throw an error even if the Audio object exists. @@ -84,7 +84,7 @@ WorkspaceAudio.prototype.load = function(filenames, name) { const ext = filename.match(/\.(\w+)$/); if (ext && audioTest.canPlayType('audio/' + ext[1])) { // Found an audio format we can play. - sound = new global['Audio'](filename); + sound = new globalThis['Audio'](filename); break; } } diff --git a/generators/javascript.js b/generators/javascript.js index 0c1cbe7cb..48255c077 100644 --- a/generators/javascript.js +++ b/generators/javascript.js @@ -42,7 +42,7 @@ Blockly.JavaScript.addReservedWords( // Magic variable. 'arguments,' + // Everything in the current environment (835 items in Chrome, 104 in Node). - Object.getOwnPropertyNames(Blockly.utils.global).join(',')); + Object.getOwnPropertyNames(Blockly.utils.global.globalThis).join(',')); /** * Order of operation ENUMs. diff --git a/scripts/migration/renamings.js b/scripts/migration/renamings.js index 0454816f8..15c0a07f7 100644 --- a/scripts/migration/renamings.js +++ b/scripts/migration/renamings.js @@ -72,6 +72,9 @@ const renamings = { genUid: {module: 'Blockly.utils.idGenerator'}, } }, + 'Blockly.utils.global': { + export: 'globalThis', // Previous default export now named. + }, 'Blockly.utils.IdGenerator': { module: 'Blockly.utils.idGenerator', } diff --git a/scripts/package/node/core.js b/scripts/package/node/core.js index 7935f0cc5..21c2ac812 100644 --- a/scripts/package/node/core.js +++ b/scripts/package/node/core.js @@ -22,9 +22,10 @@ Blockly.setLocale = function (locale) { // Override textToDomDocument and provide Node.js alternatives to DOMParser and // XMLSerializer. -if (typeof Blockly.utils.global.document !== 'object') { - Blockly.utils.global.DOMParser = require('jsdom/lib/jsdom/living').DOMParser; - Blockly.utils.global.XMLSerializer = require('jsdom/lib/jsdom/living').XMLSerializer; +const globalThis = Blockly.utils.global.globalThis; +if (typeof globalThis.document !== 'object') { + globalThis.DOMParser = require('jsdom/lib/jsdom/living').DOMParser; + globalThis.XMLSerializer = require('jsdom/lib/jsdom/living').XMLSerializer; var doc = Blockly.utils.xml.textToDomDocument( ''); Blockly.utils.xml.document = function() { diff --git a/tests/deps.js b/tests/deps.js index 71227ec70..8dd1373ea 100644 --- a/tests/deps.js +++ b/tests/deps.js @@ -215,7 +215,7 @@ goog.addDependency('../../core/utils/colour.js', ['Blockly.utils.colour'], [], { goog.addDependency('../../core/utils/coordinate.js', ['Blockly.utils.Coordinate'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/deprecation.js', ['Blockly.utils.deprecation'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/dom.js', ['Blockly.utils.dom'], ['Blockly.utils.userAgent'], {'lang': 'es6', 'module': 'goog'}); -goog.addDependency('../../core/utils/global.js', ['Blockly.utils.global'], [], {'lang': 'es6', 'module': 'goog'}); +goog.addDependency('../../core/utils/global.js', ['Blockly.utils.global'], [], {'module': 'goog'}); goog.addDependency('../../core/utils/idgenerator.js', ['Blockly.utils.idGenerator'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/keycodes.js', ['Blockly.utils.KeyCodes'], [], {'lang': 'es6', 'module': 'goog'}); goog.addDependency('../../core/utils/math.js', ['Blockly.utils.math'], [], {'lang': 'es6', 'module': 'goog'});