UNPKG

2.13 kBJavaScriptView Raw
1/* @flow */
2
3/**
4 * Original RenderStream implementation by Sasha Aickin (@aickin)
5 * Licensed under the Apache License, Version 2.0
6 * http://www.apache.org/licenses/LICENSE-2.0
7 *
8 * Modified by Evan You (@yyx990803)
9 */
10
11const stream = require('stream')
12
13import { isTrue, isUndef } from 'shared/util'
14import { createWriteFunction } from './write'
15
16export default class RenderStream extends stream.Readable {
17 buffer: string;
18 render: (write: Function, done: Function) => void;
19 expectedSize: number;
20 write: Function;
21 next: Function;
22 end: Function;
23 done: boolean;
24
25 constructor (render: Function) {
26 super()
27 this.buffer = ''
28 this.render = render
29 this.expectedSize = 0
30
31 this.write = createWriteFunction((text, next) => {
32 const n = this.expectedSize
33 this.buffer += text
34 if (this.buffer.length >= n) {
35 this.next = next
36 this.pushBySize(n)
37 return true // we will decide when to call next
38 }
39 return false
40 }, err => {
41 this.emit('error', err)
42 })
43
44 this.end = () => {
45 // the rendering is finished; we should push out the last of the buffer.
46 this.done = true
47 this.push(this.buffer)
48 }
49 }
50
51 pushBySize (n: number) {
52 const bufferToPush = this.buffer.substring(0, n)
53 this.buffer = this.buffer.substring(n)
54 this.push(bufferToPush)
55 }
56
57 tryRender () {
58 try {
59 this.render(this.write, this.end)
60 } catch (e) {
61 this.emit('error', e)
62 }
63 }
64
65 tryNext () {
66 try {
67 this.next()
68 } catch (e) {
69 this.emit('error', e)
70 }
71 }
72
73 _read (n: number) {
74 this.expectedSize = n
75 // it's possible that the last chunk added bumped the buffer up to > 2 * n,
76 // which means we will need to go through multiple read calls to drain it
77 // down to < n.
78 if (isTrue(this.done)) {
79 this.push(null)
80 return
81 }
82 if (this.buffer.length >= n) {
83 this.pushBySize(n)
84 return
85 }
86 if (isUndef(this.next)) {
87 // start the rendering chain.
88 this.tryRender()
89 } else {
90 // continue with the rendering.
91 this.tryNext()
92 }
93 }
94}