Skip to content

Commit

Permalink
defineGlobally can be reverted
Browse files Browse the repository at this point in the history
  • Loading branch information
fasttime committed Sep 27, 2024
1 parent 49102e8 commit fd05b91
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 24 deletions.
16 changes: 12 additions & 4 deletions src/polytype-esm.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
18 changes: 13 additions & 5 deletions src/polytype.d.ts.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -129,20 +129,28 @@ Polytype.ClusteredConstructor<T>;
{{> 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}}
Expand Down
10 changes: 6 additions & 4 deletions test/spec-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@
{
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;

before
(
() =>
{
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');
Expand All @@ -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);
Expand Down
65 changes: 54 additions & 11 deletions test/spec/common/define-globally.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
);
},
);
},
Expand Down

0 comments on commit fd05b91

Please sign in to comment.