Skip to content

Commit 9913798

Browse files
authored
fix: remove implicit global references (#932)
1 parent 31a808b commit 9913798

File tree

4 files changed

+99
-90
lines changed

4 files changed

+99
-90
lines changed

src/setup/setup.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function createConfig(
1919
defaults: Required<Options> = defaultOptionsSetup,
2020
node?: Node,
2121
): Config {
22-
const document = getDocument(options, node)
22+
const document = getDocument(options, node, defaults)
2323

2424
const {
2525
keyboardState = createKeyboardState(),
@@ -43,7 +43,8 @@ export function setupMain(options: Options = {}) {
4343
const config = createConfig(options)
4444
prepareDocument(config.document)
4545

46-
const view = config.document.defaultView ?? /* istanbul ignore next */ window
46+
const view =
47+
config.document.defaultView ?? /* istanbul ignore next */ globalThis.window
4748
attachClipboardStubToView(view)
4849

4950
return doSetup(config)
@@ -103,6 +104,12 @@ function doSetup(config: Config): UserEvent {
103104
}
104105
}
105106

106-
function getDocument(options: Partial<Config>, node?: Node) {
107-
return options.document ?? (node && getDocumentFromNode(node)) ?? document
107+
function getDocument(
108+
options: Partial<Config>,
109+
node: Node | undefined,
110+
defaults: Required<Options>,
111+
) {
112+
return (
113+
options.document ?? (node && getDocumentFromNode(node)) ?? defaults.document
114+
)
108115
}

src/utils/dataTransfer/Clipboard.ts

+83-83
Original file line numberDiff line numberDiff line change
@@ -5,103 +5,105 @@ import {getWindow} from '../misc/getWindow'
55

66
// Clipboard API is only fully available in secure context or for browser extensions.
77

8-
const Window = Symbol('Window reference')
9-
108
type ItemData = Record<string, Blob | string | Promise<Blob | string>>
119

12-
class ClipboardItemStub implements ClipboardItem {
13-
private data: ItemData
14-
constructor(data: ItemData) {
15-
this.data = data
16-
}
10+
// MDN lists string|Blob|Promise<Blob|string> as possible types in ClipboardItemData
11+
// lib.dom.d.ts lists only Promise<Blob|string>
12+
// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#syntax
13+
export function createClipboardItem(
14+
window: Window & typeof globalThis,
15+
...blobs: Array<Blob | string>
16+
) {
17+
const dataMap = Object.fromEntries(
18+
blobs.map(b => [
19+
typeof b === 'string' ? 'text/plain' : b.type,
20+
Promise.resolve(b),
21+
]),
22+
)
1723

18-
get types() {
19-
return Array.from(Object.keys(this.data))
24+
// use real ClipboardItem if available
25+
/* istanbul ignore if */
26+
if (typeof window.ClipboardItem !== 'undefined') {
27+
return new window.ClipboardItem(dataMap)
2028
}
2129

22-
async getType(type: string) {
23-
const data = await this.data[type]
30+
return new (class ClipboardItem implements ClipboardItem {
31+
private data: ItemData
32+
constructor(d: ItemData) {
33+
this.data = d
34+
}
2435

25-
if (!data) {
26-
throw new Error(
27-
`${type} is not one of the available MIME types on this item.`,
28-
)
36+
get types() {
37+
return Array.from(Object.keys(this.data))
2938
}
3039

31-
return data instanceof this[Window].Blob
32-
? data
33-
: new this[Window].Blob([data], {type})
34-
}
40+
async getType(type: string) {
41+
const value = await this.data[type]
3542

36-
[Window] = window
43+
if (!value) {
44+
throw new Error(
45+
`${type} is not one of the available MIME types on this item.`,
46+
)
47+
}
48+
49+
return value instanceof window.Blob
50+
? value
51+
: new window.Blob([value], {type})
52+
}
53+
})(dataMap)
3754
}
3855

3956
const ClipboardStubControl = Symbol('Manage ClipboardSub')
4057

41-
class ClipboardStub extends window.EventTarget implements Clipboard {
42-
private items: ClipboardItem[] = []
58+
function createClipboardStub(window: Window & typeof globalThis) {
59+
return new (class Clipboard extends window.EventTarget {
60+
private items: ClipboardItem[] = []
4361

44-
async read() {
45-
return Array.from(this.items)
46-
}
62+
async read() {
63+
return Array.from(this.items)
64+
}
4765

48-
async readText() {
49-
let text = ''
50-
for (const item of this.items) {
51-
const type = item.types.includes('text/plain')
52-
? 'text/plain'
53-
: item.types.find(t => t.startsWith('text/'))
54-
if (type) {
55-
text += await item
56-
.getType(type)
57-
.then(b => readBlobText(b, this[Window].FileReader))
66+
async readText() {
67+
let text = ''
68+
for (const item of this.items) {
69+
const type = item.types.includes('text/plain')
70+
? 'text/plain'
71+
: item.types.find(t => t.startsWith('text/'))
72+
if (type) {
73+
text += await item
74+
.getType(type)
75+
.then(b => readBlobText(b, window.FileReader))
76+
}
5877
}
78+
return text
5979
}
60-
return text
61-
}
6280

63-
async write(data: ClipboardItem[]) {
64-
this.items = data
65-
}
81+
async write(data: ClipboardItem[]) {
82+
this.items = data
83+
}
6684

67-
async writeText(text: string) {
68-
this.items = [createClipboardItem(this[Window], text)]
69-
}
85+
async writeText(text: string) {
86+
this.items = [createClipboardItem(window, text)]
87+
}
7088

71-
[Window] = window;
72-
[ClipboardStubControl]: {
73-
resetClipboardStub: () => void
74-
detachClipboardStub: () => void
75-
}
89+
[ClipboardStubControl]: {
90+
resetClipboardStub: () => void
91+
detachClipboardStub: () => void
92+
}
93+
})()
7694
}
77-
78-
// MDN lists string|Blob|Promise<Blob|string> as possible types in ClipboardItemData
79-
// lib.dom.d.ts lists only Promise<Blob|string>
80-
// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#syntax
81-
export function createClipboardItem(
82-
window: Window & typeof globalThis,
83-
...blobs: Array<Blob | string>
84-
): ClipboardItem {
85-
const data = Object.fromEntries(
86-
blobs.map(b => [
87-
typeof b === 'string' ? 'text/plain' : b.type,
88-
Promise.resolve(b),
89-
]),
90-
)
91-
92-
// use real ClipboardItem if available
93-
/* istanbul ignore else */
94-
if (typeof window.ClipboardItem === 'undefined') {
95-
const item = new ClipboardItemStub(data)
96-
item[Window] = window
97-
return item
98-
} else {
99-
return new window.ClipboardItem(data)
100-
}
95+
type ClipboardStub = ReturnType<typeof createClipboardStub>
96+
97+
function isClipboardStub(
98+
clipboard: Clipboard | ClipboardStub | undefined,
99+
): clipboard is ClipboardStub {
100+
return !!(clipboard as {[ClipboardStubControl]?: object} | undefined)?.[
101+
ClipboardStubControl
102+
]
101103
}
102104

103105
export function attachClipboardStubToView(window: Window & typeof globalThis) {
104-
if (window.navigator.clipboard instanceof ClipboardStub) {
106+
if (isClipboardStub(window.navigator.clipboard)) {
105107
return window.navigator.clipboard[ClipboardStubControl]
106108
}
107109

@@ -110,12 +112,10 @@ export function attachClipboardStubToView(window: Window & typeof globalThis) {
110112
'clipboard',
111113
)
112114

113-
let stub = new ClipboardStub()
114-
stub[Window] = window
115+
let stub = createClipboardStub(window)
115116
const control = {
116117
resetClipboardStub: () => {
117-
stub = new ClipboardStub()
118-
stub[Window] = window
118+
stub = createClipboardStub(window)
119119
stub[ClipboardStubControl] = control
120120
},
121121
detachClipboardStub: () => {
@@ -141,15 +141,15 @@ export function attachClipboardStubToView(window: Window & typeof globalThis) {
141141
}
142142

143143
export function resetClipboardStubOnView(window: Window & typeof globalThis) {
144-
if (window.navigator.clipboard instanceof ClipboardStub) {
144+
if (isClipboardStub(window.navigator.clipboard)) {
145145
window.navigator.clipboard[ClipboardStubControl].resetClipboardStub()
146146
}
147147
}
148148

149149
export function detachClipboardStubFromView(
150150
window: Window & typeof globalThis,
151151
) {
152-
if (window.navigator.clipboard instanceof ClipboardStub) {
152+
if (isClipboardStub(window.navigator.clipboard)) {
153153
window.navigator.clipboard[ClipboardStubControl].detachClipboardStub()
154154
}
155155
}
@@ -204,11 +204,11 @@ export async function writeDataTransferToClipboard(
204204
}
205205

206206
/* istanbul ignore else */
207-
if (typeof afterEach === 'function') {
208-
afterEach(() => resetClipboardStubOnView(window))
207+
if (typeof globalThis.afterEach === 'function') {
208+
globalThis.afterEach(() => resetClipboardStubOnView(globalThis.window))
209209
}
210210

211211
/* istanbul ignore else */
212-
if (typeof afterAll === 'function') {
213-
afterAll(() => detachClipboardStubFromView(window))
212+
if (typeof globalThis.afterAll === 'function') {
213+
globalThis.afterAll(() => detachClipboardStubFromView(globalThis.window))
214214
}

src/utils/edit/buildTimeValue.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const parseInt = globalThis.parseInt
2+
13
export function buildTimeValue(value: string): string {
24
const onlyDigitsValue = value.replace(/\D/g, '')
35
if (onlyDigitsValue.length < 2) {
@@ -26,7 +28,7 @@ function build(onlyDigitsValue: string, index: number): string {
2628
const minuteCharacters = onlyDigitsValue.slice(index)
2729
const parsedMinutes = parseInt(minuteCharacters, 10)
2830
const validMinutes = Math.min(parsedMinutes, 59)
29-
return `${validHours
31+
return `${validHours.toString().padStart(2, '0')}:${validMinutes
3032
.toString()
31-
.padStart(2, '0')}:${validMinutes.toString().padStart(2, '0')}`
33+
.padStart(2, '0')}`
3234
}

src/utils/misc/wait.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export function wait(config: Config) {
66
return
77
}
88
return Promise.all([
9-
new Promise<void>(resolve => setTimeout(() => resolve(), delay)),
9+
new Promise<void>(resolve => globalThis.setTimeout(() => resolve(), delay)),
1010
config.advanceTimers(delay),
1111
])
1212
}

0 commit comments

Comments
 (0)