diff --git a/scopes/scope/objects/models/source.spec.ts b/scopes/scope/objects/models/source.spec.ts new file mode 100644 index 000000000000..0c05b269b3ba --- /dev/null +++ b/scopes/scope/objects/models/source.spec.ts @@ -0,0 +1,13 @@ +import { expect } from 'chai'; +import { deflateSync } from 'zlib'; +import { BitObject } from '../objects'; +import Source from './source'; + +describe('Source', () => { + it('should not keep the whole inflated buffer when the file is small', async () => { + const file = Source.from(Buffer.from('const a = 1;')); + const parsed = (await BitObject.parseObject(deflateSync(file.serialize()))) as Source; + expect(parsed.contents.toString()).to.equal('const a = 1;'); + expect(parsed.contents.buffer.byteLength).to.be.below(16 * 1024); + }); +}); diff --git a/scopes/scope/objects/models/source.ts b/scopes/scope/objects/models/source.ts index 4f14025f9c15..5fbac96caf21 100644 --- a/scopes/scope/objects/models/source.ts +++ b/scopes/scope/objects/models/source.ts @@ -22,6 +22,9 @@ export default class Source extends BitObject { } static parse(contents: Buffer): Source { + // zlib returns small results as a slice of a bigger (16KB) buffer. unlike other objects, which are parsed and dropped, + // a Source keeps these bytes, often for long (e.g. as a component file), so it copies them instead of pinning 16KB. + if (contents.byteLength < contents.buffer.byteLength / 2) contents = Buffer.from(contents); return new Source(contents); }