Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(js-runtime): new Blob implementation * feat: enable more tests * chore: add changesets * feat(docs): add docs for Blob & File * fix(js-runtime): complete Blob & File APIs * test(js-runtime): add Blob & File APIs
- Loading branch information
Showing
14 changed files
with
316 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
'@lagon/docs': minor | ||
'@lagon/js-runtime': minor | ||
--- | ||
|
||
Add Blob and File APIs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
[submodule "tools/wpt"] | ||
path = tools/wpt | ||
url = git@github.com:web-platform-tests/wpt.git | ||
ignore = dirty |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import '../'; | ||
|
||
describe('Blob', () => { | ||
it('should allow empty blobs', () => { | ||
const blob = new Blob(); | ||
expect(blob.size).toEqual(0); | ||
expect(blob.type).toEqual(''); | ||
}); | ||
|
||
it('should set the type', () => { | ||
const blob = new Blob([], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(0); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should init with string', () => { | ||
const blob = new Blob(['hello'], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(5); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should init with multiple strings', () => { | ||
const blob = new Blob(['hello', 'world'], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(10); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should init with Blob', () => { | ||
const blob = new Blob([new Blob(['hello'])], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(5); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should init with multiple Blobs', () => { | ||
const blob = new Blob([new Blob(['hello']), new Blob(['world'])], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(10); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should init with ArrayBuffer', () => { | ||
const blob = new Blob([new ArrayBuffer(5)], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(5); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should init with different types', () => { | ||
const blob = new Blob(['hello', new ArrayBuffer(5), new Blob(['world'])], { type: 'text/plain' }); | ||
expect(blob.size).toEqual(15); | ||
expect(blob.type).toEqual('text/plain'); | ||
}); | ||
|
||
it('should transform to ArrayBuffer', async () => { | ||
const blob = new Blob(['hello']); | ||
const buffer = await blob.arrayBuffer(); | ||
expect(buffer).toBeInstanceOf(ArrayBuffer); | ||
expect(buffer.byteLength).toEqual(5); | ||
expect(buffer).toEqual(new TextEncoder().encode('hello').buffer); | ||
}); | ||
|
||
it('should slice', async () => { | ||
const blob = new Blob(['hello world']); | ||
const sliced = blob.slice(6); | ||
expect(sliced.size).toEqual(5); | ||
expect(await sliced.text()).toEqual('world'); | ||
}); | ||
|
||
it('should slice with start', async () => { | ||
const blob = new Blob(['hello world']); | ||
const sliced = blob.slice(6, 11); | ||
expect(sliced.size).toEqual(5); | ||
expect(await sliced.text()).toEqual('world'); | ||
}); | ||
|
||
it('should slice with start and end', async () => { | ||
const blob = new Blob(['hello world']); | ||
const sliced = blob.slice(0, 5); | ||
expect(sliced.size).toEqual(5); | ||
expect(await sliced.text()).toEqual('hello'); | ||
}); | ||
|
||
it('should slice with negative start', async () => { | ||
const blob = new Blob(['hello world']); | ||
const sliced = blob.slice(-5); | ||
expect(sliced.size).toEqual(5); | ||
expect(await sliced.text()).toEqual('world'); | ||
}); | ||
|
||
it('should slice with negative start and end', async () => { | ||
const blob = new Blob(['hello world']); | ||
const sliced = blob.slice(-5, -1); | ||
expect(sliced.size).toEqual(4); | ||
expect(await sliced.text()).toEqual('worl'); | ||
}); | ||
|
||
it('should transform to text', async () => { | ||
const blob = new Blob(['hello']); | ||
const text = await blob.text(); | ||
expect(text).toEqual('hello'); | ||
}); | ||
|
||
it('should transform to ReadableStream', async () => { | ||
const blob = new Blob(['hello']); | ||
const stream = blob.stream(); | ||
const reader = stream.getReader(); | ||
const { done, value } = await reader.read(); | ||
expect(done).toEqual(false); | ||
expect(value).toEqual(new TextEncoder().encode('hello')); | ||
const { done: done2 } = await reader.read(); | ||
expect(done2).toEqual(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { describe, it, expect } from 'vitest'; | ||
import '../'; | ||
|
||
describe('File', () => { | ||
it('should be an instanceof Blob', () => { | ||
const file = new File([], 'file.txt'); | ||
expect(file).toBeInstanceOf(Blob); | ||
}); | ||
|
||
it('should allow empty files', () => { | ||
const file = new File([], 'file.txt'); | ||
expect(file.size).toEqual(0); | ||
expect(file.type).toEqual(''); | ||
expect(file.name).toEqual('file.txt'); | ||
expect(file.lastModified).toBeGreaterThan(0); | ||
}); | ||
|
||
it('should set the type', () => { | ||
const file = new File([], 'file.txt', { type: 'text/plain' }); | ||
expect(file.size).toEqual(0); | ||
expect(file.type).toEqual('text/plain'); | ||
expect(file.name).toEqual('file.txt'); | ||
expect(file.lastModified).toBeGreaterThan(0); | ||
}); | ||
|
||
it('should init with string', () => { | ||
const file = new File(['hello'], 'file.txt', { type: 'text/plain' }); | ||
expect(file.size).toEqual(5); | ||
expect(file.type).toEqual('text/plain'); | ||
expect(file.name).toEqual('file.txt'); | ||
expect(file.lastModified).toBeGreaterThan(0); | ||
}); | ||
|
||
it('should set lastModified', () => { | ||
const file = new File([], 'file.txt', { lastModified: 123 }); | ||
expect(file.size).toEqual(0); | ||
expect(file.type).toEqual(''); | ||
expect(file.name).toEqual('file.txt'); | ||
expect(file.lastModified).toEqual(123); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,69 @@ | ||
// @ts-expect-error blob-polyfill isn't typed | ||
import { Blob } from 'blob-polyfill'; | ||
|
||
(globalThis => { | ||
globalThis.Blob = Blob; | ||
globalThis.Blob = class { | ||
readonly size: number; | ||
readonly type: string; | ||
readonly buffer: Uint8Array; | ||
|
||
constructor(blobParts?: BlobPart[], options?: BlobPropertyBag) { | ||
if (blobParts) { | ||
const chunks = blobParts.map(blobPart => { | ||
if (typeof blobPart === 'string') { | ||
return globalThis.__lagon__.TEXT_ENCODER.encode(blobPart); | ||
} else if (blobPart instanceof ArrayBuffer || blobPart instanceof Uint8Array) { | ||
return new Uint8Array(blobPart); | ||
} else if (blobPart instanceof Blob) { | ||
return blobPart.buffer as Uint8Array; | ||
} else { | ||
return new Uint8Array(0); | ||
} | ||
}); | ||
|
||
const totalSize = chunks.reduce((acc, chunk) => acc + chunk.byteLength, 0); | ||
const buffer = new Uint8Array(totalSize); | ||
let offset = 0; | ||
|
||
for (const chunk of chunks) { | ||
buffer.set(chunk, offset); | ||
offset += chunk.byteLength; | ||
} | ||
|
||
this.size = buffer.byteLength; | ||
this.buffer = buffer; | ||
} else { | ||
this.size = 0; | ||
this.buffer = new Uint8Array(0); | ||
} | ||
|
||
this.type = options?.type || ''; | ||
} | ||
|
||
arrayBuffer(): Promise<ArrayBuffer> { | ||
return Promise.resolve(this.buffer.buffer); | ||
} | ||
|
||
slice(start?: number, end?: number, contentType?: string): Blob { | ||
let type = contentType; | ||
|
||
if (type === undefined) { | ||
type = this.type; | ||
} else if (type === null) { | ||
type = 'null'; | ||
} | ||
|
||
return new Blob([this.buffer.slice(start, end)], { type }); | ||
} | ||
|
||
stream(): ReadableStream<Uint8Array> { | ||
return new ReadableStream({ | ||
pull: async controller => { | ||
controller.enqueue(this.buffer); | ||
controller.close(); | ||
}, | ||
}); | ||
} | ||
|
||
text(): Promise<string> { | ||
return Promise.resolve(globalThis.__lagon__.TEXT_DECODER.decode(this.buffer)); | ||
} | ||
}; | ||
})(globalThis); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
(globalThis => { | ||
globalThis.File = class extends Blob { | ||
readonly lastModified: number; | ||
readonly name: string; | ||
readonly webkitRelativePath: string; | ||
|
||
constructor(fileBits: BlobPart[], fileName: string, options?: FilePropertyBag) { | ||
super(fileBits, options); | ||
|
||
this.lastModified = options?.lastModified || Date.now(); | ||
this.name = fileName; | ||
this.webkitRelativePath = ''; | ||
} | ||
}; | ||
|
||
// TODO: properly implement FileReader. It should extends Event | ||
// @ts-expect-errore to fix | ||
globalThis.FileReader = class { | ||
// @ts-expect-errore to fix | ||
readonly DONE: number; | ||
// @ts-expect-errore to fix | ||
readonly EMPTY: number; | ||
// @ts-expect-errore to fix | ||
readonly LOADING: number; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
constructor() {} | ||
|
||
// @ts-expect-errore to fix | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
onerror(): ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null {} | ||
// @ts-expect-errore to fix | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
onload(): ((this: FileReader, ev: ProgressEvent<FileReader>) => any) | null {} | ||
|
||
readAsText(blob: Blob, encoding?: string) { | ||
blob.text().then(text => { | ||
// @ts-expect-errore to fix | ||
this.result = text; | ||
// @ts-expect-errore to fix | ||
this.onload(this); | ||
}); | ||
} | ||
}; | ||
})(globalThis); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
5e2ca1b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
www – ./www
www-lagon.vercel.app
www-git-main-lagon.vercel.app
lagon.app
5e2ca1b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
docs – ./packages/docs
docs-lagon.vercel.app
lagon-docs.vercel.app
docs-git-main-lagon.vercel.app
docs.lagon.app
5e2ca1b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
dashboard – ./packages/dashboard
dashboard-git-main-lagon.vercel.app
dashboard-lagon.vercel.app
dash.lagon.app
5e2ca1b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
storybook – ./packages/ui
storybook-lagon.vercel.app
storybook-swart-eight.vercel.app
storybook-git-main-lagon.vercel.app
ui.lagon.app