Skip to content

node:buffer: namespace-bound Blob and File constructors lose native behavior #3385

Description

@andrewtdiz

Summary

node:buffer should expose Blob and File as usable constructor values on the module namespace object. Perry supports direct named/global constructor forms, but namespace-bound constructor values lose native Blob/File behavior.

Node Behavior

./run_parity_tests.sh --filter test_parity_buffer exercises the namespace form:

import * as buffer from "node:buffer";

const BlobCtor: any = (buffer as any).Blob;
const blob = new BlobCtor(["hello"]);
console.log("Blob size:", blob.size);
console.log("Blob text:", await blob.text());

const FileCtor: any = (buffer as any).File;
const f = new FileCtor(["hello"], "greeting.txt", { lastModified: 1700000000000 });
console.log("File.name:", f.name);
console.log("File.lastModified:", f.lastModified);

Node output includes:

Blob size: 5
Blob text: hello
File.name: greeting.txt
File.lastModified: 1700000000000

Perry Behavior

The same targeted parity run currently reports test_parity_buffer as an output mismatch. The namespace-bound constructor section prints:

Blob size: <unsupported>
Blob text: <unsupported>
File.name: undefined
File.lastModified: undefined

The granular ./run_parity_tests.sh --suite node-suite --module buffer run passed 124/124, including direct import { Blob } / import { File } fixtures. That narrows this to namespace/dynamic constructor binding rather than the direct constructor runtime path.

Source evidence: direct new Blob(...) / new File(...) lowers through the built-in constructor arms in crates/perry-codegen/src/lower_call/builtin.rs. HIR tagging also recognizes direct named imports and selected globalThis.File forms in crates/perry-hir/src/destructuring/var_decl.rs, but a constructor value obtained through (buffer as any).Blob / (buffer as any).File is not preserved as the native Blob/File class identity.

Suggested PR Cut

Batch this with related issues in:
node:buffer: module namespace and backing property parity cut

Good batch candidates:

Do not batch with:

  • unrelated Buffer byte/numeric API work
  • node:fs.openAsBlob() file-backed Blob support
  • broad Blob/File coercion changes beyond constructor value exposure unless they are required by the same tests

Acceptance

  • parity/regression test proves const BlobCtor = buffer.Blob; new BlobCtor([...]) behaves like Node
  • parity/regression test proves const FileCtor = buffer.File; new FileCtor([...], name, opts) exposes Node-compatible name, lastModified, size, and text behavior
  • existing direct named/global Blob/File fixtures continue passing
  • related known-failure/docs/manifest entries updated if touched

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions