From eeaa482e46da838f483c5fee3996619f5086c928 Mon Sep 17 00:00:00 2001 From: Edward Faulkner Date: Thu, 4 Mar 2021 15:19:35 -0500 Subject: [PATCH] Build: Restore strict mode compatibility When bundling qunit as a library in another build, the use of `this` would cause an error strict mode due to being undefined there. Adopt [ES2020 globalThis](https://github.com/tc39/proposal-global), and polyfill it for environments that don't implement it yet. Fixes https://github.com/qunitjs/qunit/issues/1557. Closes https://github.com/qunitjs/qunit/pull/1558. --- lib/global-this-polyfill.js | 49 +++++++++++++++++++++++++++++++++++++ rollup.config.js | 7 ------ src/export.js | 4 +-- src/globals.js | 18 +++++++------- src/test.js | 7 +++--- 5 files changed, 63 insertions(+), 22 deletions(-) create mode 100644 lib/global-this-polyfill.js diff --git a/lib/global-this-polyfill.js b/lib/global-this-polyfill.js new file mode 100644 index 000000000..046eac61b --- /dev/null +++ b/lib/global-this-polyfill.js @@ -0,0 +1,49 @@ +/* +https://github.com/ungap/global-this/blob/v0.4.4/esm/index.js + +Copyright (c) 2020, Andrea Giammarchi, @WebReflection + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +------- + +Patches for use in QUnit: + +- 2021-02-25: Export as module only, don't change global scope as QUnit must not + affect the host context (e.g. people may test their application intentionally + with different or no polyfills and we must not affect that). + +*/ + +let foundGlobalThis; + +(function (Object) { + if (typeof globalThis === "object") { + foundGlobalThis = globalThis; + } else { + this + ? get() + : (Object.defineProperty(Object.prototype, "_T_", { + configurable: true, + get: get, + }), + _T_); + + function get() { + foundGlobalThis = this || self; + delete Object.prototype._T_; + } + } +})(Object); + +export default foundGlobalThis; diff --git a/rollup.config.js b/rollup.config.js index 1d0f7a364..65b4bdabf 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -40,10 +40,6 @@ module.exports = { __dirname + "/src/html-reporter/es6-map.js", "utf8" ).toString().trim(); - }, - - globals: { - global: "(function() { return this; }())" } }, plugins: [ @@ -57,8 +53,5 @@ module.exports = { babelHelpers: "bundled", babelrc: true } ) - ], - external: [ - "global" ] }; diff --git a/src/export.js b/src/export.js index fb90b37da..50699cd98 100644 --- a/src/export.js +++ b/src/export.js @@ -1,6 +1,6 @@ /* global module, exports, define */ import { window, document, self } from "./globals"; -import global from "global"; +import globalThis from "../lib/global-this-polyfill"; export default function exportQUnit( QUnit ) { let exportedModule = false; @@ -54,6 +54,6 @@ export default function exportQUnit( QUnit ) { // For other environments, such as SpiderMonkey (mozjs) and other // embedded JavaScript engines if ( !exportedModule ) { - global.QUnit = QUnit; + globalThis.QUnit = QUnit; } } diff --git a/src/globals.js b/src/globals.js index 1544028ad..e36e8de75 100644 --- a/src/globals.js +++ b/src/globals.js @@ -1,10 +1,10 @@ -import global from "global"; +import globalThis from "../lib/global-this-polyfill"; -export const window = global.window; -export const self = global.self; -export const console = global.console; -export const setTimeout = global.setTimeout; -export const clearTimeout = global.clearTimeout; +export const window = globalThis.window; +export const self = globalThis.self; +export const console = globalThis.console; +export const setTimeout = globalThis.setTimeout; +export const clearTimeout = globalThis.clearTimeout; export const document = window && window.document; export const navigator = window && window.navigator; @@ -12,9 +12,9 @@ export const navigator = window && window.navigator; export const localSessionStorage = ( function() { const x = "qunit-test-string"; try { - global.sessionStorage.setItem( x, x ); - global.sessionStorage.removeItem( x ); - return global.sessionStorage; + globalThis.sessionStorage.setItem( x, x ); + globalThis.sessionStorage.removeItem( x ); + return globalThis.sessionStorage; } catch ( e ) { return undefined; } diff --git a/src/test.js b/src/test.js index 3bd4abc04..55a5d8e77 100644 --- a/src/test.js +++ b/src/test.js @@ -1,5 +1,4 @@ -import global from "global"; - +import globalThis from "../lib/global-this-polyfill"; import { begin } from "./core"; import { setTimeout, clearTimeout } from "./globals"; import { emit } from "./events"; @@ -648,8 +647,8 @@ function saveGlobal() { config.pollution = []; if ( config.noglobals ) { - for ( const key in global ) { - if ( hasOwn.call( global, key ) ) { + for ( const key in globalThis ) { + if ( hasOwn.call( globalThis, key ) ) { // In Opera sometimes DOM element ids show up here, ignore them if ( /^qunit-test-output/.test( key ) ) {