Skip to content

Instantly share code, notes, and snippets.

@ksm2
Created April 25, 2018 13:29
Show Gist options
  • Save ksm2/76bd39ce41935c8299a13436ae430964 to your computer and use it in GitHub Desktop.
Save ksm2/76bd39ce41935c8299a13436ae430964 to your computer and use it in GitHub Desktop.
WHATWG Transform Streams
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Text Lines Transform Stream</title>
<script src="Uint8ArrayToLinesOfTextTransformer.js"></script>
</head>
<body>
<script>
async function main() {
const ts = new TransformStream(new Uint8ArrayToLinesOfTextTransformer())
const response = await fetch('https://gist.githubusercontent.com/silveira/5504078/raw/a74e3f11d33e327a100792392871186323f9b515/the_raven_by_edgar_allan_poe')
const rs = response.body
const lineStream = rs.pipeThrough(ts)
const reader = lineStream.getReader()
while (true) {
const { done, value } = await reader.read()
if (done) {
break
}
const p = document.createElement('p')
p.textContent = value
document.getElementById('section').appendChild(p)
}
}
main()
</script>
<h1>The Raven by Edgar Allan Poe</h1>
<section id="section"></section>
</body>
</html>
declare interface Transformer<R, W> {
start?(controller: TransformStreamDefaultController<W>): void
transform?(chunk: R, controller: TransformStreamDefaultController<W>): void
flush?(controller: TransformStreamDefaultController<W>): void
}
declare class TransformStream<R, W> {
constructor(transformer: Transformer<R, W>, writableStrategy?: any, readableStrategy?: any)
readonly readable: ReadableStream
readonly writable: WritableStream
}
declare class TransformStreamDefaultController<W> {
enqueue(chunk: W): void
error(reason: Error): void
terminate(): void
readonly desiredSize: number
}
{
"compilerOptions": {
"target": "es2017",
"lib": ["es2017", "dom"]
}
}
class Uint8ArrayToLinesOfTextTransformer implements Transformer<Uint8Array, string> {
private readonly decoder: TextDecoder
private lastString: string
constructor() {
this.decoder = new TextDecoder()
this.lastString = ''
}
transform(chunk: Uint8Array, controller: TransformStreamDefaultController<string>): void {
// Decode the current chunk
const string = `${this.lastString}${this.decoder.decode(chunk)}`
// Extract lines from chunk
const lines = string.split(/\r\n|[\r\n]/g)
// Save last line
this.lastString = lines.pop() || ''
// Enqueue each line in the next chunk
for (const line of lines) {
controller.enqueue(line)
}
}
flush(controller: TransformStreamDefaultController<string>): void {
// Is there still a line left? Enqueue it
if (this.lastString) {
controller.enqueue(this.lastString)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment