fix(memory): charge rendered output to memoryLimit at emission

Move output-length accounting into the emitters, which charge each
written chunk against ctx.memoryLimit right before it reaches the
result string or stream. Filters/tags now only pre-charge the extra
working memory they allocate apart from that output, so join drops its
bespoke output-size counting and charges array.length like its siblings.

The block.super capture emitter intentionally omits the limiter to
avoid double-counting content that is re-emitted through the final
emitter.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Yang Jun
2026-07-06 22:34:38 +08:00
co-authored by Cursor
parent bb7df7f0a8
commit 2f343f0631
8 changed files with 33 additions and 22 deletions
+2 -2
View File
@@ -6,14 +6,14 @@ import { Emitter, KeepingTypeEmitter, StreamedEmitter, SimpleEmitter } from '../
export class Render {
public renderTemplatesToNodeStream (templates: Template[], ctx: Context): NodeJS.ReadableStream {
const emitter = new StreamedEmitter()
const emitter = new StreamedEmitter(ctx.memoryLimit)
Promise.resolve().then(() => toPromise(this.renderTemplates(templates, ctx, emitter)))
.then(() => emitter.end(), err => emitter.error(err))
return emitter.stream
}
public * renderTemplates (templates: Template[], ctx: Context, emitter?: Emitter): IterableIterator<any> {
if (!emitter) {
emitter = ctx.opts.keepOutputType ? new KeepingTypeEmitter() : new SimpleEmitter()
emitter = ctx.opts.keepOutputType ? new KeepingTypeEmitter(ctx.memoryLimit) : new SimpleEmitter(ctx.memoryLimit)
}
ctx.renderLimit.check(getPerformance().now())
const errors = []