Skip to content

Commit

Permalink
@uppy/utils: refactor to TS (#4699)
Browse files Browse the repository at this point in the history

Co-authored-by: Mikael Finstad <[email protected]>
Co-authored-by: Nick Rutten <[email protected]>
Co-authored-by: Murderlon <[email protected]>
Co-authored-by: Artur Paikin <[email protected]>
  • Loading branch information
5 people authored Nov 6, 2023
1 parent 43178f1 commit 51ecc66
Show file tree
Hide file tree
Showing 99 changed files with 1,083 additions and 703 deletions.
3 changes: 3 additions & 0 deletions packages/@uppy/core/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// This references the old types on purpose, to make sure to not create breaking changes for TS consumers.
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
/// <reference path="../../utils/types/index.d.ts"/>
import * as UppyUtils from '@uppy/utils'

// Utility types
Expand Down
1 change: 1 addition & 0 deletions packages/@uppy/utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"preact": "^10.5.13"
},
"devDependencies": {
"@types/lodash": "^4.14.199",
"vitest": "^0.34.5"
}
}
13 changes: 0 additions & 13 deletions packages/@uppy/utils/src/AbortController.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { describe, expect, it, vi } from 'vitest'
import { AbortController, AbortSignal } from './AbortController.js'
import { AbortController, AbortSignal } from './AbortController.ts'

function flushInstantTimeouts () {
return new Promise(resolve => setTimeout(resolve, 0))
function flushInstantTimeouts() {
return new Promise((resolve) => setTimeout(resolve, 0))
}

describe('AbortController', () => {
Expand Down
22 changes: 22 additions & 0 deletions packages/@uppy/utils/src/AbortController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import hasOwnProperty from './hasProperty.ts'
/**
* Little AbortController proxy module so we can swap out the implementation easily later.
*/
export const { AbortController } = globalThis
export const { AbortSignal } = globalThis
export const createAbortError = (
message = 'Aborted',
options?: Parameters<typeof Error>[1],
): DOMException => {
const err = new DOMException(message, 'AbortError')
if (options != null && hasOwnProperty(options, 'cause')) {
Object.defineProperty(err, 'cause', {
// @ts-expect-error TS is drunk
__proto__: null,
configurable: true,
writable: true,
value: options.cause,
})
}
return err
}
13 changes: 0 additions & 13 deletions packages/@uppy/utils/src/ErrorWithCause.js

This file was deleted.

21 changes: 0 additions & 21 deletions packages/@uppy/utils/src/ErrorWithCause.test.js

This file was deleted.

24 changes: 24 additions & 0 deletions packages/@uppy/utils/src/ErrorWithCause.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest'
import ErrorWithCause from './ErrorWithCause.ts'
import NetworkError from './NetworkError.ts'

describe('ErrorWithCause', () => {
it('should support a `{ cause }` option', () => {
const cause = new Error('cause')
expect(new ErrorWithCause('message').cause).toEqual(undefined)
expect(new ErrorWithCause('message', {}).cause).toEqual(undefined)
expect(new ErrorWithCause('message', { cause }).cause).toEqual(cause)
})
it('should propagate isNetworkError', () => {
const regularError = new Error('cause')
const networkError = new NetworkError('cause')
expect(
new ErrorWithCause('message', { cause: networkError }).isNetworkError,
).toEqual(true)
expect(
new ErrorWithCause('message', { cause: regularError }).isNetworkError,
).toEqual(false)
expect(new ErrorWithCause('message', {}).isNetworkError).toEqual(false)
expect(new ErrorWithCause('message').isNetworkError).toEqual(false)
})
})
23 changes: 23 additions & 0 deletions packages/@uppy/utils/src/ErrorWithCause.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type NetworkError from './NetworkError.ts'
import hasProperty from './hasProperty.ts'

class ErrorWithCause extends Error {
public isNetworkError: boolean

public cause: Error['cause']

constructor(
message?: ConstructorParameters<ErrorConstructor>[0],
options?: ConstructorParameters<ErrorConstructor>[1],
) {
super(message)
this.cause = options?.cause
if (this.cause && hasProperty(this.cause, 'isNetworkError')) {
this.isNetworkError = (this.cause as NetworkError).isNetworkError
} else {
this.isNetworkError = false
}
}
}

export default ErrorWithCause
83 changes: 0 additions & 83 deletions packages/@uppy/utils/src/EventManager.js

This file was deleted.

115 changes: 115 additions & 0 deletions packages/@uppy/utils/src/EventManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import type {
Uppy,
UploadPauseCallback,
FileRemovedCallback,
UploadRetryCallback,
GenericEventCallback,
} from '@uppy/core'
import type { UppyFile } from './UppyFile'
/**
* Create a wrapper around an event emitter with a `remove` method to remove
* all events that were added using the wrapped emitter.
*/
export default class EventManager {
#uppy: Uppy

#events: Array<Parameters<typeof Uppy.prototype.on>> = []

constructor(uppy: Uppy) {
this.#uppy = uppy
}

on(
event: Parameters<typeof Uppy.prototype.on>[0],
fn: Parameters<typeof Uppy.prototype.on>[1],
): Uppy {
this.#events.push([event, fn])
return this.#uppy.on(event, fn)
}

remove(): void {
for (const [event, fn] of this.#events.splice(0)) {
this.#uppy.off(event, fn)
}
}

onFilePause(fileID: UppyFile['id'], cb: (isPaused: boolean) => void): void {
this.on(
'upload-pause',
(
targetFileID: Parameters<UploadPauseCallback>[0],
isPaused: Parameters<UploadPauseCallback>[1],
) => {
if (fileID === targetFileID) {
cb(isPaused)
}
},
)
}

onFileRemove(
fileID: UppyFile['id'],
cb: (isPaused: UppyFile['id']) => void,
): void {
this.on('file-removed', (file: Parameters<FileRemovedCallback<any>>[0]) => {
if (fileID === file.id) cb(file.id)
})
}

onPause(fileID: UppyFile['id'], cb: (isPaused: boolean) => void): void {
this.on(
'upload-pause',
(
targetFileID: Parameters<UploadPauseCallback>[0],
isPaused: Parameters<UploadPauseCallback>[1],
) => {
if (fileID === targetFileID) {
// const isPaused = this.#uppy.pauseResume(fileID)
cb(isPaused)
}
},
)
}

onRetry(fileID: UppyFile['id'], cb: () => void): void {
this.on(
'upload-retry',
(targetFileID: Parameters<UploadRetryCallback>[0]) => {
if (fileID === targetFileID) {
cb()
}
},
)
}

onRetryAll(fileID: UppyFile['id'], cb: () => void): void {
this.on('retry-all', () => {
if (!this.#uppy.getFile(fileID)) return
cb()
})
}

onPauseAll(fileID: UppyFile['id'], cb: () => void): void {
this.on('pause-all', () => {
if (!this.#uppy.getFile(fileID)) return
cb()
})
}

onCancelAll(
fileID: UppyFile['id'],
eventHandler: GenericEventCallback,
): void {
this.on('cancel-all', (...args: Parameters<GenericEventCallback>) => {
if (!this.#uppy.getFile(fileID)) return
eventHandler(...args)
})
}

onResumeAll(fileID: UppyFile['id'], cb: () => void): void {
this.on('resume-all', () => {
if (!this.#uppy.getFile(fileID)) return
cb()
})
}
}
18 changes: 18 additions & 0 deletions packages/@uppy/utils/src/FileProgress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
interface FileProgressBase {
progress: number
uploadComplete: boolean
percentage: number
bytesTotal: number
}

// FileProgress is either started or not started. We want to make sure TS doesn't
// let us mix the two cases, and for that effect, we have one type for each case:
export type FileProgressStarted = FileProgressBase & {
uploadStarted: number
bytesUploaded: number
}
export type FileProgressNotStarted = FileProgressBase & {
uploadStarted: null
bytesUploaded: false
}
export type FileProgress = FileProgressStarted | FileProgressNotStarted
11 changes: 0 additions & 11 deletions packages/@uppy/utils/src/NetworkError.js

This file was deleted.

19 changes: 19 additions & 0 deletions packages/@uppy/utils/src/NetworkError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
class NetworkError extends Error {
public cause: unknown

public isNetworkError: true

public request: null | XMLHttpRequest

constructor(error: unknown, xhr: null | XMLHttpRequest = null) {
super(
`This looks like a network error, the endpoint might be blocked by an internet provider or a firewall.`,
)

this.cause = error
this.isNetworkError = true
this.request = xhr
}
}

export default NetworkError
Loading

0 comments on commit 51ecc66

Please sign in to comment.