Skip to content

Commit

Permalink
Move to TypeScript (#683)
Browse files Browse the repository at this point in the history
* Convert first file to TypeScript

* Transpile using TypeScript

* Remove Babel

* Add back missing dependencies for ESLint

* Move eslint exceptions into .eslintrc

* Move logger.js to TypeScript

* Rename tsconfig-base.json to tsconfig.json

* Move upload.js to TypeScript

* Move all node-related source files to TypeScript

* Move browser source code to TypeScript

* Lint

* Add linting rules for TypeScript

* Remove obsolete type definitions

* Properly transpile to ESM and CJS

* Fix build command

* Restructure exports in `package.json`

I mainly followed the recommendations from https://github.com/frehner/modern-guide-to-packaging-js-library with one exception: We don't use `browser` anymore, but consider the browser-versions the default. Node 12+ will automatically resolve to the node-version as it supports the new `exports` syntax.

`arethetypeswrong` and `publint` are also happy:

```
$ npx @arethetypeswrong/cli --pack .
tus-js-client v4.1.0

Build tools:
- typescript@^5.4.5

 No problems found 🌟

┌───────────────────┬─────────────────┬──────────────────────────────┐
│                   │ "tus-js-client" │ "tus-js-client/package.json" │
├───────────────────┼─────────────────┼──────────────────────────────┤
│ node10            │ 🟢              │ 🟢 (JSON)                    │
├───────────────────┼─────────────────┼──────────────────────────────┤
│ node16 (from CJS) │ 🟢 (CJS)        │ 🟢 (JSON)                    │
├───────────────────┼─────────────────┼──────────────────────────────┤
│ node16 (from ESM) │ 🟢 (ESM)        │ 🟢 (JSON)                    │
├───────────────────┼─────────────────┼──────────────────────────────┤
│ bundler           │ 🟢              │ 🟢 (JSON)                    │
└───────────────────┴─────────────────┴──────────────────────────────┘
$ npx publint
tus-js-client lint results:
All good!
```

* Keep main pointing to Node index

* Remove ESLint comments

* Remove typescript-eslint

* Remove Babel (again)

* Remove empty line

* Revert to original structure in `package.json`

* Remove `tsd`

* Rename `lib.es5` to more appropriate `lib.cjs`

* Explicitly install `types/node`

It was previously only provided through a transitive dependency on puppeteer and karma

* Move types and values for options in own file

* Remove `unknown` type for timeout value

* Remove generics to unify the types for Browser and Node.js

* Better detect input types for fingerprinting

* Move to TypeScript: Upload, StreamSource (#734)

* browser StreamSource TS

* TS upload and options

* Remove whitespace

* Fix type of default options

* Only pass strings to `HttpRequest#setHeader` (#709)

* setHeader value arg should be string

* Explicit casting of header values, number to string

* Fix syntax

* Fix lint

---------

Co-Authored-By: Marius Kleidl <[email protected]>

* Fix error emission

Co-Authored-By: Marius Kleidl <[email protected]>

* Allows `bytesTotal` to be null for progress events

Co-Authored-By: Marius Kleidl <[email protected]>

---------

Co-authored-by: Matthew Holloway <Matthew Holloway>
Co-authored-by: Marius Kleidl <[email protected]>
Co-authored-by: dragan_d_dragon <[email protected]>

* Error message for React Native environments

* Comment for TODO

* Rename classes and files for file sources

* Remove comment about exports syntax

That comment is no longer valid since we switched from CommonJS exports to ESM exports in bdb6144.

---------

Co-authored-by: Matthew Holloway <[email protected]>
Co-authored-by: dragan_d_dragon <[email protected]>
  • Loading branch information
3 people authored Jan 14, 2025
1 parent 783deaf commit d8b01d8
Show file tree
Hide file tree
Showing 60 changed files with 1,283 additions and 2,882 deletions.
12 changes: 0 additions & 12 deletions .babelrc

This file was deleted.

2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ jobs:
suite: 'browserstack'
- desc: 'Puppeteer'
suite: 'puppeteer'
- desc: 'Types'
suite: 'types'
- desc: 'Node.js 18'
suite: 'node'
node: 18
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.vscode/settings.json
node_modules
demos/reactnative/.expo
lib.es5
lib.cjs
lib.esm
dist
.DS_Store
Expand Down
4 changes: 4 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@
{
"include": ["demos/browser/**", "demos/cordova/**"],
"javascript": { "globals": ["tus", "Camera"] }
},
{
"include": ["tsconfig*.json"],
"json": { "parser": { "allowComments": true } }
}
]
}
51 changes: 0 additions & 51 deletions lib/browser/fileReader.js

This file was deleted.

58 changes: 58 additions & 0 deletions lib/browser/fileReader.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { isReactNativeFile, isReactNativePlatform } from './isReactNative.js'
import uriToBlob from './uriToBlob.js'

import type { FileReader, FileSource, UploadInput } from '../options.js'
import BlobFileSource from './sources/BlobFileSource.js'
import StreamFileSource from './sources/StreamFileSource.js'

function isWebStream(input: UploadInput): input is Pick<ReadableStreamDefaultReader, 'read'> {
return 'read' in input && typeof input.read === 'function'
}

// TODO: Make sure that we support ArrayBuffers, TypedArrays, DataViews and Blobs
export default class BrowserFileReader implements FileReader {
async openFile(input: UploadInput, chunkSize: number): Promise<FileSource> {
// In React Native, when user selects a file, instead of a File or Blob,
// you usually get a file object {} with a uri property that contains
// a local path to the file. We use XMLHttpRequest to fetch
// the file blob, before uploading with tus.
if (isReactNativeFile(input)) {
if (!isReactNativePlatform()) {
throw new Error('tus: file objects with `uri` property is only supported in React Native')
}

try {
const blob = await uriToBlob(input.uri)
return new BlobFileSource(blob)
} catch (err) {
throw new Error(
`tus: cannot fetch \`file.uri\` as Blob, make sure the uri is correct and accessible. ${err}`,
)
}
}

// File is a subtype of Blob, so we can check for Blob here.
if (input instanceof Blob) {
return Promise.resolve(new BlobFileSource(input))
}

if (isWebStream(input)) {
chunkSize = Number(chunkSize)
if (!Number.isFinite(chunkSize)) {
return Promise.reject(
new Error(
'cannot create source for stream without a finite value for the `chunkSize` option',
),
)
}

return Promise.resolve(new StreamFileSource(input))
}

return Promise.reject(
new Error(
'source object may only be an instance of File, Blob, or Reader in this environment',
),
)
}
}
41 changes: 0 additions & 41 deletions lib/browser/fileSignature.js

This file was deleted.

42 changes: 42 additions & 0 deletions lib/browser/fileSignature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { ReactNativeFile, UploadInput, UploadOptions } from '../options.js'
import { isReactNativeFile, isReactNativePlatform } from './isReactNative.js'

/**
* Generate a fingerprint for a file which will be used the store the endpoint
*/
export default function fingerprint(file: UploadInput, options: UploadOptions) {
if (isReactNativePlatform() && isReactNativeFile(file)) {
return Promise.resolve(reactNativeFingerprint(file, options))
}

if (file instanceof Blob) {
return Promise.resolve(
//@ts-expect-error TODO: We have to check the input type here
// This can be fixed by moving the fingerprint function to the FileReader class
['tus-br', file.name, file.type, file.size, file.lastModified, options.endpoint].join('-'),
)
}

return Promise.resolve(null)
}

function reactNativeFingerprint(file: ReactNativeFile, options: UploadOptions): string {
const exifHash = file.exif ? hashCode(JSON.stringify(file.exif)) : 'noexif'
return ['tus-rn', file.name || 'noname', file.size || 'nosize', exifHash, options.endpoint].join(
'/',
)
}

function hashCode(str: string): number {
// from https://stackoverflow.com/a/8831937/151666
let hash = 0
if (str.length === 0) {
return hash
}
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i)
hash = (hash << 5) - hash + char
hash &= hash // Convert to 32bit integer
}
return hash
}
97 changes: 0 additions & 97 deletions lib/browser/httpStack.js

This file was deleted.

Loading

0 comments on commit d8b01d8

Please sign in to comment.