Skip to content

Commit

Permalink
Merge branch 'main' into provider-views-ts
Browse files Browse the repository at this point in the history
* main:
  Image editor: make compressor work after the image editor, too (#4918)
  meta: exclude `tsconfig` files from npm bundles (#4916)
  @uppy/compressor: migrate to TS (#4907)
  Update uppy-ProviderBrowser-viewType--list.scss (#4913)
  @uppy/tus: migrate to TS (#4899)
  • Loading branch information
Murderlon committed Feb 14, 2024
2 parents bfa4e96 + 3c0140a commit c679f80
Show file tree
Hide file tree
Showing 30 changed files with 470 additions and 194 deletions.
1 change: 1 addition & 0 deletions packages/@uppy/audio/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
1 change: 1 addition & 0 deletions packages/@uppy/companion-client/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
1 change: 1 addition & 0 deletions packages/@uppy/compressor/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import Core from '@uppy/core'
import getFileNameAndExtension from '@uppy/utils/lib/getFileNameAndExtension'
import fs from 'node:fs'
import path from 'node:path'
import CompressorPlugin from './index.js'
import CompressorPlugin from './index.ts'

// Compressor uses browser canvas API, so need to mock compress()
CompressorPlugin.prototype.compress = (blob) => {
// @ts-expect-error mocked
CompressorPlugin.prototype.compress = async (blob: Blob) => {
return {
name: `${getFileNameAndExtension(blob.name).name}.webp`,
type: 'image/webp',
Expand All @@ -16,11 +17,28 @@ CompressorPlugin.prototype.compress = (blob) => {
}

// eslint-disable-next-line no-restricted-globals
const sampleImage = fs.readFileSync(path.join(__dirname, '../../../../e2e/cypress/fixtures/images/image.jpg'))
const sampleImage = fs.readFileSync(
path.join(__dirname, '../../../../e2e/cypress/fixtures/images/image.jpg'),
)

const file1 = { source: 'jest', name: 'image-1.jpeg', type: 'image/jpeg', data: new File([sampleImage], 'image-1.jpeg', { type: 'image/jpeg' }) }
const file2 = { source: 'jest', name: 'yolo', type: 'image/jpeg', data: new File([sampleImage], 'yolo', { type: 'image/jpeg' }) }
const file3 = { source: 'jest', name: 'my.file.is.weird.png', type: 'image/png', data: new File([sampleImage], 'my.file.is.weird.png', { type: 'image/png' }) }
const file1 = {
source: 'jest',
name: 'image-1.jpeg',
type: 'image/jpeg',
data: new File([sampleImage], 'image-1.jpeg', { type: 'image/jpeg' }),
}
const file2 = {
source: 'jest',
name: 'yolo',
type: 'image/jpeg',
data: new File([sampleImage], 'yolo', { type: 'image/jpeg' }),
}
const file3 = {
source: 'jest',
name: 'my.file.is.weird.png',
type: 'image/png',
data: new File([sampleImage], 'my.file.is.weird.png', { type: 'image/png' }),
}

describe('CompressorPlugin', () => {
it('should change update extension in file.name and file.meta.name', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import { BasePlugin } from '@uppy/core'
import { BasePlugin, Uppy } from '@uppy/core'
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import { RateLimitedQueue } from '@uppy/utils/lib/RateLimitedQueue'
import getFileNameAndExtension from '@uppy/utils/lib/getFileNameAndExtension'
import prettierBytes from '@transloadit/prettier-bytes'
import CompressorJS from 'compressorjs'
import locale from './locale.js'

export default class Compressor extends BasePlugin {
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
import type { PluginOpts } from '@uppy/core/lib/BasePlugin.ts'

import locale from './locale.ts'

declare module '@uppy/core' {
export interface UppyEventMap<M extends Meta, B extends Body> {
'compressor:complete': (file: UppyFile<M, B>[]) => void
}
}

export interface CompressorOpts extends PluginOpts, CompressorJS.Options {
quality: number
limit?: number
}

export default class Compressor<
M extends Meta,
B extends Body,
> extends BasePlugin<CompressorOpts, M, B> {
#RateLimitedQueue

constructor (uppy, opts) {
constructor(uppy: Uppy<M, B>, opts: CompressorOpts) {
super(uppy, opts)
this.id = this.opts.id || 'Compressor'
this.type = 'modifier'
Expand All @@ -30,7 +50,7 @@ export default class Compressor extends BasePlugin {
this.compress = this.compress.bind(this)
}

compress (blob) {
compress(blob: Blob): Promise<Blob | File> {
return new Promise((resolve, reject) => {
/* eslint-disable no-new */
new CompressorJS(blob, {
Expand All @@ -41,15 +61,17 @@ export default class Compressor extends BasePlugin {
})
}

async prepareUpload (fileIDs) {
async prepareUpload(fileIDs: string[]): Promise<void> {
let totalCompressedSize = 0
const compressedFiles = []
const compressedFiles: UppyFile<M, B>[] = []
const compressAndApplyResult = this.#RateLimitedQueue.wrapPromiseFunction(
async (file) => {
async (file: UppyFile<M, B>) => {
try {
const compressedBlob = await this.compress(file.data)
const compressedSavingsSize = file.data.size - compressedBlob.size
this.uppy.log(`[Image Compressor] Image ${file.id} compressed by ${prettierBytes(compressedSavingsSize)}`)
this.uppy.log(
`[Image Compressor] Image ${file.id} compressed by ${prettierBytes(compressedSavingsSize)}`,
)
totalCompressedSize += compressedSavingsSize
const { name, type, size } = compressedBlob

Expand All @@ -61,7 +83,9 @@ export default class Compressor extends BasePlugin {

this.uppy.setFileState(file.id, {
...(name && { name }),
...(compressedFileName.extension && { extension: compressedFileName.extension }),
...(compressedFileName.extension && {
extension: compressedFileName.extension,
}),
...(type && { type }),
...(size && { size }),
data: compressedBlob,
Expand All @@ -73,7 +97,10 @@ export default class Compressor extends BasePlugin {
})
compressedFiles.push(file)
} catch (err) {
this.uppy.log(`[Image Compressor] Failed to compress ${file.id}:`, 'warning')
this.uppy.log(
`[Image Compressor] Failed to compress ${file.id}:`,
'warning',
)
this.uppy.log(err, 'warning')
}
},
Expand All @@ -97,7 +124,7 @@ export default class Compressor extends BasePlugin {
file.data = file.data.slice(0, file.data.size, file.type)
}

if (!file.type.startsWith('image/')) {
if (!file.type?.startsWith('image/')) {
return Promise.resolve()
}

Expand Down Expand Up @@ -128,11 +155,11 @@ export default class Compressor extends BasePlugin {
}
}

install () {
install(): void {
this.uppy.addPreProcessor(this.prepareUpload)
}

uninstall () {
uninstall(): void {
this.uppy.removePreProcessor(this.prepareUpload)
}
}
File renamed without changes.
25 changes: 25 additions & 0 deletions packages/@uppy/compressor/tsconfig.build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"extends": "../../../tsconfig.shared",
"compilerOptions": {
"noImplicitAny": false,
"outDir": "./lib",
"paths": {
"@uppy/utils/lib/*": ["../utils/src/*"],
"@uppy/core": ["../core/src/index.js"],
"@uppy/core/lib/*": ["../core/src/*"]
},
"resolveJsonModule": false,
"rootDir": "./src",
"skipLibCheck": true
},
"include": ["./src/**/*.*"],
"exclude": ["./src/**/*.test.ts"],
"references": [
{
"path": "../utils/tsconfig.build.json"
},
{
"path": "../core/tsconfig.build.json"
}
]
}
21 changes: 21 additions & 0 deletions packages/@uppy/compressor/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"extends": "../../../tsconfig.shared",
"compilerOptions": {
"emitDeclarationOnly": false,
"noEmit": true,
"paths": {
"@uppy/utils/lib/*": ["../utils/src/*"],
"@uppy/core": ["../core/src/index.js"],
"@uppy/core/lib/*": ["../core/src/*"],
},
},
"include": ["./package.json", "./src/**/*.*"],
"references": [
{
"path": "../utils/tsconfig.build.json",
},
{
"path": "../core/tsconfig.build.json",
},
],
}
1 change: 1 addition & 0 deletions packages/@uppy/core/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
1 change: 1 addition & 0 deletions packages/@uppy/drop-target/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
1 change: 1 addition & 0 deletions packages/@uppy/image-editor/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
4 changes: 2 additions & 2 deletions packages/@uppy/image-editor/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export default class Editor<M extends Meta, B extends Body> extends Component<
prevCropboxData,
)
if (newCropboxData) this.cropper.setCropBoxData(newCropboxData)
// When we stretch the cropbox by one of its sides
// 2. When we stretch the cropbox by one of its sides
} else {
const newCropboxData = limitCropboxMovementOnResize(
canvasData,
Expand Down Expand Up @@ -120,7 +120,7 @@ export default class Editor<M extends Meta, B extends Body> extends Component<
}

onRotateGranular = (ev: ChangeEvent<HTMLInputElement>): void => {
// 1. Set state
// 1. Set state
const newGranularAngle = Number(ev.target.value)
this.setState({ angleGranular: newGranularAngle })

Expand Down
3 changes: 2 additions & 1 deletion packages/@uppy/image-editor/src/ImageEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ export default class ImageEditor<
const { currentImage } = this.getPluginState()

this.uppy.setFileState(currentImage!.id, {
data: blob!,
// Reinserting image's name and type, because .toBlob loses both.
data: new File([blob!], currentImage!.name, { type: blob!.type }),
size: blob!.size,
preview: undefined,
})
Expand Down
1 change: 1 addition & 0 deletions packages/@uppy/locales/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
.uppy-ProviderBrowserItem-inner {
display: flex;
align-items: center;
color: inherit;

// For better outline
padding: 2px;
Expand Down
1 change: 1 addition & 0 deletions packages/@uppy/status-bar/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
1 change: 1 addition & 0 deletions packages/@uppy/store-default/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
1 change: 1 addition & 0 deletions packages/@uppy/tus/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tsconfig.*
39 changes: 0 additions & 39 deletions packages/@uppy/tus/src/getFingerprint.js

This file was deleted.

44 changes: 44 additions & 0 deletions packages/@uppy/tus/src/getFingerprint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Body, Meta, UppyFile } from '@uppy/utils/lib/UppyFile'
import * as tus from 'tus-js-client'

function isCordova() {
return (
typeof window !== 'undefined' &&
// @ts-expect-error may exist
(typeof window.PhoneGap !== 'undefined' ||
// @ts-expect-error may exist
typeof window.Cordova !== 'undefined' ||
// @ts-expect-error may exist
typeof window.cordova !== 'undefined')
)
}

function isReactNative() {
return (
typeof navigator !== 'undefined' &&
typeof navigator.product === 'string' &&
navigator.product.toLowerCase() === 'reactnative'
)
}

// We override tus fingerprint to uppy’s `file.id`, since the `file.id`
// now also includes `relativePath` for files added from folders.
// This means you can add 2 identical files, if one is in folder a,
// the other in folder b — `a/file.jpg` and `b/file.jpg`, when added
// together with a folder, will be treated as 2 separate files.
//
// For React Native and Cordova, we let tus-js-client’s default
// fingerprint handling take charge.
export default function getFingerprint<M extends Meta, B extends Body>(
uppyFile: UppyFile<M, B>,
): tus.UploadOptions['fingerprint'] {
return (file, options) => {
if (isCordova() || isReactNative()) {
return tus.defaultOptions.fingerprint!(file, options)
}

const uppyFingerprint = ['tus', uppyFile.id, options!.endpoint].join('-')

return Promise.resolve(uppyFingerprint)
}
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,38 @@
import { describe, expect, it } from 'vitest'
import Core from '@uppy/core'
import Tus from './index.js'
import Tus from './index.ts'

describe('Tus', () => {
it('Throws errors if autoRetry option is true', () => {
const uppy = new Core()

expect(() => {
// @ts-expect-error removed
uppy.use(Tus, { autoRetry: true })
}).toThrowError(/The `autoRetry` option was deprecated and has been removed/)
}).toThrowError(
/The `autoRetry` option was deprecated and has been removed/,
)
})

it('Throws errors if autoRetry option is false', () => {
const uppy = new Core()

expect(() => {
// @ts-expect-error removed
uppy.use(Tus, { autoRetry: false })
}).toThrowError(/The `autoRetry` option was deprecated and has been removed/)
}).toThrowError(
/The `autoRetry` option was deprecated and has been removed/,
)
})

it('Throws errors if autoRetry option is `undefined`', () => {
const uppy = new Core()

expect(() => {
// @ts-expect-error removed
uppy.use(Tus, { autoRetry: undefined })
}).toThrowError(/The `autoRetry` option was deprecated and has been removed/)
}).toThrowError(
/The `autoRetry` option was deprecated and has been removed/,
)
})
})
Loading

0 comments on commit c679f80

Please sign in to comment.