diff --git a/src/polytype-esm.js b/src/polytype-esm.js index 161ba10..c443dba 100644 --- a/src/polytype-esm.js +++ b/src/polytype-esm.js @@ -460,12 +460,20 @@ const createUnionProxy = }; const defineGlobally = -() => +undo => { - if (globalThis.hasOwnProperty('classes')) + if (globalThis.hasOwnProperty('classes') === !undo) return false; - defineMutableDataProperty(globalThis, 'classes', classes); - defineMutableDataProperty(_Object, 'getPrototypeListOf', getPrototypeListOf); + if (undo) + { + delete globalThis.classes; + delete _Object.getPrototypeListOf; + } + else + { + defineMutableDataProperty(globalThis, 'classes', classes); + defineMutableDataProperty(_Object, 'getPrototypeListOf', getPrototypeListOf); + } return true; }; diff --git a/src/polytype.d.ts.hbs b/src/polytype.d.ts.hbs index 19eff28..46dff86 100644 --- a/src/polytype.d.ts.hbs +++ b/src/polytype.d.ts.hbs @@ -129,20 +129,28 @@ Polytype.ClusteredConstructor; {{> classes q="export function "}} /** - * Globally defines `classes` and `Object.getPrototypeListOf`. + * Globally defines or undefines `classes` and `Object.getPrototypeListOf`. * - * Calling this function allows using Polytype everywhere inside the current JavaScript realm - * without imports. + * Calling this function without arguments or with a falsy argument allows using Polytype everywhere + * inside the current JavaScript realm without imports. + * Calling it again with a truthy argument reverts the changes made by the previous call. * * This function is only available in the module versions of Polytype. * For most purposes it is better to import the global version of Polytype directly rather than * calling this function. * + * @param undo + * + * If this argument is falsy or unspecified, `classes` and `Object.getPrototypeListOf` will be + * defined globally. + * If this argument is truthy, the globals `classes` and `Object.getPrototypeListOf` will be + * deleted. + * * @returns * - * `true` on success; `false` otherwise. + * `true` if any changes were made; `false` otherwise. */ -export function defineGlobally(): boolean; +export function defineGlobally(uninstall?: boolean): boolean; {{> getPrototypeListOf q="export function "}} {{else}} diff --git a/test/spec-helper.js b/test/spec-helper.js index 3ab317f..508d090 100644 --- a/test/spec-helper.js +++ b/test/spec-helper.js @@ -7,12 +7,13 @@ { function backupGlobals() { - const globalThisDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'globalThis'); + const _globalThis = globalThis; let bindDescriptor; let classesDescriptor; let fnHasInstanceDescriptor; let getPrototypeListOfDescriptor; + let globalThisDescriptor; let isPrototypeOfDescriptor; let objHasInstanceDescriptor; @@ -20,7 +21,8 @@ ( () => { - classesDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'classes'); + classesDescriptor = Object.getOwnPropertyDescriptor(_globalThis, 'classes'); + globalThisDescriptor = Object.getOwnPropertyDescriptor(_globalThis, 'globalThis'); fnHasInstanceDescriptor = Object.getOwnPropertyDescriptor(Function, Symbol.hasInstance); bindDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, 'bind'); @@ -37,8 +39,8 @@ ( () => { - setPropertyDescriptor(globalThis, 'globalThis', globalThisDescriptor); - Object.defineProperty(globalThis, 'classes', classesDescriptor); + Object.defineProperty(_globalThis, 'classes', classesDescriptor); + Object.defineProperty(_globalThis, 'globalThis', globalThisDescriptor); setPropertyDescriptor(Function, Symbol.hasInstance, fnHasInstanceDescriptor); // eslint-disable-next-line no-extend-native Object.defineProperty(Function.prototype, 'bind', bindDescriptor); diff --git a/test/spec/common/define-globally.spec.js b/test/spec/common/define-globally.spec.js index db96002..9b07412 100644 --- a/test/spec/common/define-globally.spec.js +++ b/test/spec/common/define-globally.spec.js @@ -9,26 +9,69 @@ maybeDescribe 'defineGlobally', () => { + let defineGlobally; + + before + (async () => { defineGlobally = await loadPolytype(); }); + + after + (() => { defineGlobally = null; }); + backupGlobals(); - it + describe ( - 'returns true', - async () => + 'with a falsy argument', + () => { - const defineGlobally = await loadPolytype(); - delete globalThis.classes; - assert.strictEqual(defineGlobally(), true); + it + ( + 'returns true', + () => + { + delete globalThis.classes; + assert.strictEqual(defineGlobally(), true); + assert.isFunction(globalThis.classes); + assert.isFunction(Object.getPrototypeListOf); + }, + ); + + it + ( + 'returns false', + () => + { + assert.strictEqual(defineGlobally(), false); + }, + ); }, ); - it + describe ( - 'returns false', - async () => + 'with a truthy argument', + () => { - const defineGlobally = await loadPolytype(); - assert.strictEqual(defineGlobally(), false); + it + ( + 'returns true', + () => + { + assert.strictEqual(defineGlobally(true), true); + assert.isNotFunction(globalThis.classes); + assert.isNotFunction(Object.getPrototypeListOf); + }, + ); + + it + ( + 'returns false', + () => + { + delete globalThis.classes; + assert.strictEqual(defineGlobally(true), false); + }, + ); }, ); },