From ce68e5eb23148f3ee8b503189e9502095b85daa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Sat, 11 Jan 2025 04:50:08 +0100 Subject: [PATCH 1/6] Improve HTMLRewriterTypes.Element.attributes type (#16319) --- packages/bun-types/html-rewriter.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bun-types/html-rewriter.d.ts b/packages/bun-types/html-rewriter.d.ts index 4db17decb630da..6ff37fa0fe080b 100644 --- a/packages/bun-types/html-rewriter.d.ts +++ b/packages/bun-types/html-rewriter.d.ts @@ -50,7 +50,7 @@ declare namespace HTMLRewriterTypes { interface Element { tagName: string; - readonly attributes: IterableIterator; + readonly attributes: IterableIterator<[string, string]>; readonly removed: boolean; /** Whether the element is explicitly self-closing, e.g. `` */ readonly selfClosing: boolean; From 83decec19770ce8bf3cb813b8b75ec38686010cb Mon Sep 17 00:00:00 2001 From: Bryce Cain Date: Fri, 10 Jan 2025 20:50:23 -0700 Subject: [PATCH 2/6] types: Add 'stat' and 'delete' methods to BunFile type (#16307) Co-authored-by: cainba --- packages/bun-types/bun.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index e7ef78f9a97746..a2c2cc914fe7eb 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1230,6 +1230,16 @@ declare module "bun" { * Deletes the file. */ unlink(): Promise; + + /** + * Deletes the file. ( same as unlink ) + */ + delete(): Promise + + /** + * Provides useful information about the file. + */ + stat(): Promise } interface NetworkSink extends FileSink { /** From d9ed436321ac5229a91dbf5d42cee328c54089bb Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Fri, 10 Jan 2025 19:50:42 -0800 Subject: [PATCH 3/6] fix(test) re-enable autobahn test (#16301) --- test/js/web/websocket/autobahn.test.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/js/web/websocket/autobahn.test.ts b/test/js/web/websocket/autobahn.test.ts index 931db2794fef9a..edc472883da709 100644 --- a/test/js/web/websocket/autobahn.test.ts +++ b/test/js/web/websocket/autobahn.test.ts @@ -1,16 +1,20 @@ import { which } from "bun"; import { afterAll, describe, expect, it } from "bun:test"; import child_process from "child_process"; -import { tempDirWithFiles } from "harness"; - +import { tempDirWithFiles, isLinux } from "harness"; const dockerCLI = which("docker") as string; function isDockerEnabled(): boolean { if (!dockerCLI) { return false; } + // TODO: investigate why its not starting on Linux arm64 + if (isLinux && process.arch === "arm64") { + return false; + } + try { - const info = child_process.execSync(`${dockerCLI} info`, { stdio: "ignore" }); + const info = child_process.execSync(`${dockerCLI} info`, { stdio: ["ignore", "pipe", "inherit"] }); return info.toString().indexOf("Server Version:") !== -1; } catch { return false; @@ -19,7 +23,7 @@ function isDockerEnabled(): boolean { if (isDockerEnabled()) { describe("autobahn", async () => { - const url = "ws://localhost:9001"; + const url = "ws://localhost:9002"; const agent = encodeURIComponent("bun/1.0.0"); let docker: child_process.ChildProcessWithoutNullStreams | null = null; const { promise, resolve } = Promise.withResolvers(); @@ -29,7 +33,7 @@ if (isDockerEnabled()) { // ], const CWD = tempDirWithFiles("autobahn", { "fuzzingserver.json": `{ - "url": "ws://127.0.0.1:9001", + "url": "ws://127.0.0.1:9002", "outdir": "./", "cases": ["*"], "exclude-agent-cases": {} @@ -48,7 +52,7 @@ if (isDockerEnabled()) { "-v", `${CWD}:/reports`, "-p", - "9001:9001", + "9002:9002", "--name", "fuzzingserver", "crossbario/autobahn-testsuite", From 1e67665d33c5c8a22bae4f3f446cdc185e3fce06 Mon Sep 17 00:00:00 2001 From: pfg Date: Fri, 10 Jan 2025 19:51:30 -0800 Subject: [PATCH 4/6] More node tests passing (#16269) --- src/js/internal/util/inspect.js | 16 +- src/js/node/util.ts | 72 +++-- .../test/parallel/test-util-callbackify.js | 296 ++++++++++++++++++ .../test-util-deprecate-invalid-code.js | 14 + .../node/test/parallel/test-util-deprecate.js | 57 ++++ .../test-util-emit-experimental-warning.js | 19 ++ .../node/test/parallel/test-util-inherits.js | 105 +++++++ .../test-util-inspect-long-running.js | 20 ++ .../test/parallel/test-util-inspect-proxy.js | 183 +++++++++++ .../test-util-stripvtcontrolcharacters.js | 26 ++ test/js/node/test/parallel/test-util-types.js | 296 ++++++++++++++++++ 11 files changed, 1075 insertions(+), 29 deletions(-) create mode 100644 test/js/node/test/parallel/test-util-callbackify.js create mode 100644 test/js/node/test/parallel/test-util-deprecate-invalid-code.js create mode 100644 test/js/node/test/parallel/test-util-deprecate.js create mode 100644 test/js/node/test/parallel/test-util-emit-experimental-warning.js create mode 100644 test/js/node/test/parallel/test-util-inherits.js create mode 100644 test/js/node/test/parallel/test-util-inspect-long-running.js create mode 100644 test/js/node/test/parallel/test-util-inspect-proxy.js create mode 100644 test/js/node/test/parallel/test-util-stripvtcontrolcharacters.js create mode 100644 test/js/node/test/parallel/test-util-types.js diff --git a/src/js/internal/util/inspect.js b/src/js/internal/util/inspect.js index a67c9dd49cd026..f7dbe104e2e3b6 100644 --- a/src/js/internal/util/inspect.js +++ b/src/js/internal/util/inspect.js @@ -2607,14 +2607,18 @@ function getStringWidth(str, removeControlChars = true) { } // Regex used for ansi escape code splitting -// Adopted from https://github.com/chalk/ansi-regex/blob/HEAD/index.js -// License: MIT, authors: @sindresorhus, Qix-, arjunmehta and LitoMore +// Ref: https://github.com/chalk/ansi-regex/blob/f338e1814144efb950276aac84135ff86b72dc8e/index.js +// License: MIT by Sindre Sorhus // Matches all ansi escape code sequences in a string -const ansiPattern = +const ansiPattern = new RegExp( "[\\u001B\\u009B][[\\]()#;?]*" + - "(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*" + - "|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)" + - "|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))"; + "(?:(?:(?:(?:;[-a-zA-Z\\d\\/\\#&.:=?%@~_]+)*" + + "|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/\\#&.:=?%@~_]*)*)?" + + "(?:\\u0007|\\u001B\\u005C|\\u009C))" + + "|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?" + + "[\\dA-PR-TZcf-nq-uy=><~]))", + "g", +); const ansi = new RegExp(ansiPattern, "g"); /** Remove all VT control characters. Use to estimate displayed string width. */ function stripVTControlCharacters(str) { diff --git a/src/js/node/util.ts b/src/js/node/util.ts index a9ddd44135d437..8023c24647c4ce 100644 --- a/src/js/node/util.ts +++ b/src/js/node/util.ts @@ -31,10 +31,12 @@ const formatWithOptions = utl.formatWithOptions; const format = utl.format; const stripVTControlCharacters = utl.stripVTControlCharacters; +const codesWarned = new Set(); function deprecate(fn, msg, code) { if (process.noDeprecation === true) { return fn; } + if (code !== undefined) validateString(code, "code"); var warned = false; function deprecated() { @@ -46,7 +48,15 @@ function deprecate(fn, msg, code) { } else if (process.traceDeprecation) { console.trace(msg); } else { - console.error(msg); + if (code !== undefined) { + // only warn for each code once + if (codesWarned.has(code)) { + process.emitWarning(msg, "DeprecationWarning", code); + } + codesWarned.add(code); + } else { + process.emitWarning(msg, "DeprecationWarning"); + } } warned = true; } @@ -149,7 +159,13 @@ var inherits = function inherits(ctor, superCtor) { if (superCtor.prototype === undefined) { throw $ERR_INVALID_ARG_TYPE("superCtor.prototype", "object", superCtor.prototype); } - ctor.super_ = superCtor; + Object.defineProperty(ctor, "super_", { + // @ts-ignore + __proto__: null, + value: superCtor, + writable: true, + configurable: true, + }); Object.setPrototypeOf(ctor.prototype, superCtor.prototype); }; var _extend = function (origin, add) { @@ -172,30 +188,40 @@ function callbackifyOnRejected(reason, cb) { return cb(reason); } function callbackify(original) { - if (typeof original !== "function") { - throw new TypeError('The "original" argument must be of type Function'); - } - function callbackified() { - var args = Array.prototype.slice.$call(arguments); - var maybeCb = args.pop(); - if (typeof maybeCb !== "function") { - throw new TypeError("The last argument must be of type Function"); - } - var self = this; - var cb = function () { - return maybeCb.$apply(self, arguments); - }; + const { validateFunction } = require("internal/validators"); + validateFunction(original, "original"); + + // We DO NOT return the promise as it gives the user a false sense that + // the promise is actually somehow related to the callback's execution + // and that the callback throwing will reject the promise. + function callbackified(...args) { + const maybeCb = Array.prototype.pop.$call(args); + validateFunction(maybeCb, "last argument"); + const cb = Function.prototype.bind.$call(maybeCb, this); + // In true node style we process the callback on `nextTick` with all the + // implications (stack, `uncaughtException`, `async_hooks`) original.$apply(this, args).then( - function (ret) { - process.nextTick(cb, null, ret); - }, - function (rej) { - process.nextTick(callbackifyOnRejected, rej, cb); - }, + ret => process.nextTick(cb, null, ret), + rej => process.nextTick(callbackifyOnRejected, rej, cb), ); } - Object.setPrototypeOf(callbackified, Object.getPrototypeOf(original)); - Object.defineProperties(callbackified, getOwnPropertyDescriptors(original)); + + const descriptors = Object.getOwnPropertyDescriptors(original); + // It is possible to manipulate a functions `length` or `name` property. This + // guards against the manipulation. + if (typeof descriptors.length.value === "number") { + descriptors.length.value++; + } + if (typeof descriptors.name.value === "string") { + descriptors.name.value += "Callbackified"; + } + const propertiesValues = Object.values(descriptors); + for (let i = 0; i < propertiesValues.length; i++) { + // We want to use null-prototype objects to not rely on globally mutable + // %Object.prototype%. + Object.setPrototypeOf(propertiesValues[i], null); + } + Object.defineProperties(callbackified, descriptors); return callbackified; } var toUSVString = input => { diff --git a/test/js/node/test/parallel/test-util-callbackify.js b/test/js/node/test/parallel/test-util-callbackify.js new file mode 100644 index 00000000000000..7f7afb6407b2a3 --- /dev/null +++ b/test/js/node/test/parallel/test-util-callbackify.js @@ -0,0 +1,296 @@ +'use strict'; +const common = require('../common'); + +// This test checks that the semantics of `util.callbackify` are as described in +// the API docs + +const assert = require('assert'); +const { callbackify } = require('util'); +const { execFile } = require('child_process'); +const fixtures = require('../common/fixtures'); + +const values = [ + 'hello world', + null, + undefined, + false, + 0, + {}, + { key: 'value' }, + Symbol('I am a symbol'), + function ok() {}, + ['array', 'with', 4, 'values'], + new Error('boo'), +]; + +{ + // Test that the resolution value is passed as second argument to callback + for (const value of values) { + // Test and `async function` + async function asyncFn() { + return value; + } + + const cbAsyncFn = callbackify(asyncFn); + cbAsyncFn(common.mustSucceed((ret) => { + assert.strictEqual(ret, value); + })); + + // Test Promise factory + function promiseFn() { + return Promise.resolve(value); + } + + const cbPromiseFn = callbackify(promiseFn); + cbPromiseFn(common.mustSucceed((ret) => { + assert.strictEqual(ret, value); + })); + + // Test Thenable + function thenableFn() { + return { + then(onRes, onRej) { + onRes(value); + } + }; + } + + const cbThenableFn = callbackify(thenableFn); + cbThenableFn(common.mustSucceed((ret) => { + assert.strictEqual(ret, value); + })); + } +} + +{ + // Test that rejection reason is passed as first argument to callback + for (const value of values) { + // Test an `async function` + async function asyncFn() { + return Promise.reject(value); + } + + const cbAsyncFn = callbackify(asyncFn); + assert.strictEqual(cbAsyncFn.length, 1); + assert.strictEqual(cbAsyncFn.name, 'asyncFnCallbackified'); + cbAsyncFn(common.mustCall((err, ret) => { + assert.strictEqual(ret, undefined); + if (err instanceof Error) { + if ('reason' in err) { + assert(!value); + assert.strictEqual(err.code, 'ERR_FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, value); + } else { + assert.strictEqual(String(value).endsWith(err.message), true); + } + } else { + assert.strictEqual(err, value); + } + })); + + // Test a Promise factory + function promiseFn() { + return Promise.reject(value); + } + const obj = {}; + Object.defineProperty(promiseFn, 'name', { + value: obj, + writable: false, + enumerable: false, + configurable: true + }); + + const cbPromiseFn = callbackify(promiseFn); + assert.strictEqual(promiseFn.name, obj); + cbPromiseFn(common.mustCall((err, ret) => { + assert.strictEqual(ret, undefined); + if (err instanceof Error) { + if ('reason' in err) { + assert(!value); + assert.strictEqual(err.code, 'ERR_FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, value); + } else { + assert.strictEqual(String(value).endsWith(err.message), true); + } + } else { + assert.strictEqual(err, value); + } + })); + + // Test Thenable + function thenableFn() { + return { + then(onRes, onRej) { + onRej(value); + } + }; + } + + const cbThenableFn = callbackify(thenableFn); + cbThenableFn(common.mustCall((err, ret) => { + assert.strictEqual(ret, undefined); + if (err instanceof Error) { + if ('reason' in err) { + assert(!value); + assert.strictEqual(err.code, 'ERR_FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, value); + } else { + assert.strictEqual(String(value).endsWith(err.message), true); + } + } else { + assert.strictEqual(err, value); + } + })); + } +} + +{ + // Test that arguments passed to callbackified function are passed to original + for (const value of values) { + async function asyncFn(arg) { + assert.strictEqual(arg, value); + return arg; + } + + const cbAsyncFn = callbackify(asyncFn); + assert.strictEqual(cbAsyncFn.length, 2); + assert.notStrictEqual( + Object.getPrototypeOf(cbAsyncFn), + Object.getPrototypeOf(asyncFn) + ); + assert.strictEqual(Object.getPrototypeOf(cbAsyncFn), Function.prototype); + cbAsyncFn(value, common.mustSucceed((ret) => { + assert.strictEqual(ret, value); + })); + + function promiseFn(arg) { + assert.strictEqual(arg, value); + return Promise.resolve(arg); + } + const obj = {}; + Object.defineProperty(promiseFn, 'length', { + value: obj, + writable: false, + enumerable: false, + configurable: true + }); + + const cbPromiseFn = callbackify(promiseFn); + assert.strictEqual(promiseFn.length, obj); + cbPromiseFn(value, common.mustSucceed((ret) => { + assert.strictEqual(ret, value); + })); + } +} + +{ + // Test that `this` binding is the same for callbackified and original + for (const value of values) { + const iAmThis = { + fn(arg) { + assert.strictEqual(this, iAmThis); + return Promise.resolve(arg); + }, + }; + iAmThis.cbFn = callbackify(iAmThis.fn); + iAmThis.cbFn(value, common.mustSucceed(function(ret) { + assert.strictEqual(ret, value); + assert.strictEqual(this, iAmThis); + })); + + const iAmThat = { + async fn(arg) { + assert.strictEqual(this, iAmThat); + return arg; + }, + }; + iAmThat.cbFn = callbackify(iAmThat.fn); + iAmThat.cbFn(value, common.mustSucceed(function(ret) { + assert.strictEqual(ret, value); + assert.strictEqual(this, iAmThat); + })); + } +} + +{ + // Test that callback that throws emits an `uncaughtException` event + const fixture = fixtures.path('uncaught-exceptions', 'callbackify1.js'); + execFile( + process.execPath, + [fixture], + common.mustCall((err, stdout, stderr) => { + assert.strictEqual(err.code, 1); + assert.strictEqual(Object.getPrototypeOf(err).name, 'Error'); + assert.strictEqual(stdout, ''); + const errLines = stderr.trim().split(/[\r\n]+/); + const errLine = errLines.find((l) => /^error/.exec(l)); + assert.strictEqual(errLine, `error: ${fixture}`); + }) + ); +} + +{ + // Test that handled `uncaughtException` works and passes rejection reason + const fixture = fixtures.path('uncaught-exceptions', 'callbackify2.js'); + execFile( + process.execPath, + [fixture], + common.mustSucceed((stdout, stderr) => { + assert.strictEqual( + stdout.trim(), + `ifError got unwanted exception: ${fixture}`); + assert.strictEqual(stderr, ''); + }) + ); +} + +{ + // Verify that non-function inputs throw. + ['foo', null, undefined, false, 0, {}, Symbol(), []].forEach((value) => { + assert.throws(() => { + callbackify(value); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "original" argument must be of type function.' + + common.invalidArgTypeHelper(value) + }); + }); +} + +{ + async function asyncFn() { + return 42; + } + + const cb = callbackify(asyncFn); + const args = []; + + // Verify that the last argument to the callbackified function is a function. + ['foo', null, undefined, false, 0, {}, Symbol(), []].forEach((value) => { + args.push(value); + assert.throws(() => { + cb(...args); + }, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }); + }); +} + +{ + // Test Promise factory + function promiseFn(value) { + return Promise.reject(value); + } + + const cbPromiseFn = callbackify(promiseFn); + + cbPromiseFn(null, (err) => { + assert.strictEqual(err.code, 'ERR_FALSY_VALUE_REJECTION'); + assert.strictEqual(err.reason, null); + // skipped, bun doesn't hide callbackifyOnRejected from the stack trace + // const stack = err.stack.split(/[\r\n]+/); + // assert.match(stack[1], /at process\.processTicksAndRejections/); + }); +} diff --git a/test/js/node/test/parallel/test-util-deprecate-invalid-code.js b/test/js/node/test/parallel/test-util-deprecate-invalid-code.js new file mode 100644 index 00000000000000..7e68c18817c0ca --- /dev/null +++ b/test/js/node/test/parallel/test-util-deprecate-invalid-code.js @@ -0,0 +1,14 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const util = require('util'); + +[1, true, false, null, {}].forEach((notString) => { + assert.throws(() => util.deprecate(() => {}, 'message', notString), { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + message: 'The "code" argument must be of type string.' + + common.invalidArgTypeHelper(notString) + }); +}); diff --git a/test/js/node/test/parallel/test-util-deprecate.js b/test/js/node/test/parallel/test-util-deprecate.js new file mode 100644 index 00000000000000..1b4a5e76623743 --- /dev/null +++ b/test/js/node/test/parallel/test-util-deprecate.js @@ -0,0 +1,57 @@ +'use strict'; + +require('../common'); + +// Tests basic functionality of util.deprecate(). + +const assert = require('assert'); +const util = require('util'); + +const expectedWarnings = new Map(); + +// Emits deprecation only once if same function is called. +{ + const msg = 'fhqwhgads'; + const fn = util.deprecate(() => {}, msg); + expectedWarnings.set(msg, { code: undefined, count: 1 }); + fn(); + fn(); +} + +// Emits deprecation twice for different functions. +{ + const msg = 'sterrance'; + const fn1 = util.deprecate(() => {}, msg); + const fn2 = util.deprecate(() => {}, msg); + expectedWarnings.set(msg, { code: undefined, count: 2 }); + fn1(); + fn2(); +} + +// Emits deprecation only once if optional code is the same, even for different +// functions. +{ + const msg = 'cannonmouth'; + const code = 'deprecatesque'; + const fn1 = util.deprecate(() => {}, msg, code); + const fn2 = util.deprecate(() => {}, msg, code); + expectedWarnings.set(msg, { code, count: 1 }); + fn1(); + fn2(); + fn1(); + fn2(); +} + +process.on('warning', (warning) => { + assert.strictEqual(warning.name, 'DeprecationWarning'); + assert.ok(expectedWarnings.has(warning.message)); + const expected = expectedWarnings.get(warning.message); + assert.strictEqual(warning.code, expected.code); + expected.count = expected.count - 1; + if (expected.count === 0) + expectedWarnings.delete(warning.message); +}); + +process.on('exit', () => { + assert.deepStrictEqual(expectedWarnings, new Map()); +}); diff --git a/test/js/node/test/parallel/test-util-emit-experimental-warning.js b/test/js/node/test/parallel/test-util-emit-experimental-warning.js new file mode 100644 index 00000000000000..6b6a45ec03b289 --- /dev/null +++ b/test/js/node/test/parallel/test-util-emit-experimental-warning.js @@ -0,0 +1,19 @@ +'use strict'; +// emitExperimentalWarning is a node internal not used by bun, so this test is skipped + +// // Flags: --expose-internals +// const common = require('../common'); +// const assert = require('assert'); +// const { emitExperimentalWarning } = require('internal/util'); + +// This test ensures that the emitExperimentalWarning in internal/util emits a +// warning when passed an unsupported feature and that it simply returns +// when passed the same feature multiple times. + +// process.on('warning', common.mustCall((warning) => { +// assert.match(warning.message, /is an experimental feature/); +// }, 2)); + +// emitExperimentalWarning('feature1'); +// emitExperimentalWarning('feature1'); // should not warn +// emitExperimentalWarning('feature2'); diff --git a/test/js/node/test/parallel/test-util-inherits.js b/test/js/node/test/parallel/test-util-inherits.js new file mode 100644 index 00000000000000..2ff8a844460179 --- /dev/null +++ b/test/js/node/test/parallel/test-util-inherits.js @@ -0,0 +1,105 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const { inherits } = require('util'); + +// Super constructor +function A() { + this._a = 'a'; +} +A.prototype.a = function() { return this._a; }; + +// One level of inheritance +function B(value) { + A.call(this); + this._b = value; +} +inherits(B, A); +B.prototype.b = function() { return this._b; }; + +assert.deepStrictEqual( + Object.getOwnPropertyDescriptor(B, 'super_'), + { + value: A, + enumerable: false, + configurable: true, + writable: true + } +); + +const b = new B('b'); +assert.strictEqual(b.a(), 'a'); +assert.strictEqual(b.b(), 'b'); +assert.strictEqual(b.constructor, B); + +// Two levels of inheritance +function C() { + B.call(this, 'b'); + this._c = 'c'; +} +inherits(C, B); +C.prototype.c = function() { return this._c; }; +C.prototype.getValue = function() { return this.a() + this.b() + this.c(); }; + +assert.strictEqual(C.super_, B); + +const c = new C(); +assert.strictEqual(c.getValue(), 'abc'); +assert.strictEqual(c.constructor, C); + +// Inherits can be called after setting prototype properties +function D() { + C.call(this); + this._d = 'd'; +} + +D.prototype.d = function() { return this._d; }; +inherits(D, C); + +assert.strictEqual(D.super_, C); + +const d = new D(); +assert.strictEqual(d.c(), 'c'); +assert.strictEqual(d.d(), 'd'); +assert.strictEqual(d.constructor, D); + +// ES6 classes can inherit from a constructor function +class E { + constructor() { + D.call(this); + this._e = 'e'; + } + e() { return this._e; } +} +inherits(E, D); + +assert.strictEqual(E.super_, D); + +const e = new E(); +assert.strictEqual(e.getValue(), 'abc'); +assert.strictEqual(e.d(), 'd'); +assert.strictEqual(e.e(), 'e'); +assert.strictEqual(e.constructor, E); + +// Should throw with invalid arguments +assert.throws(() => { + inherits(A, {}); +}, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', +}); + +assert.throws(() => { + inherits(A, null); +}, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', +}); + +assert.throws(() => { + inherits(null, A); +}, { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', +}); diff --git a/test/js/node/test/parallel/test-util-inspect-long-running.js b/test/js/node/test/parallel/test-util-inspect-long-running.js new file mode 100644 index 00000000000000..167f72ba64631a --- /dev/null +++ b/test/js/node/test/parallel/test-util-inspect-long-running.js @@ -0,0 +1,20 @@ +'use strict'; + +require('../common'); + +// Test that huge objects don't crash due to exceeding the maximum heap size. + +const util = require('util'); + +// Create a difficult to stringify object. Without the artificial limitation +// this would crash or throw an maximum string size error. +let last = {}; +const obj = last; + +for (let i = 0; i < 1000; i++) { + last.next = { circular: obj, last, obj: { a: 1, b: 2, c: true } }; + last = last.next; + obj[i] = last; +} + +util.inspect(obj, { depth: Infinity }); diff --git a/test/js/node/test/parallel/test-util-inspect-proxy.js b/test/js/node/test/parallel/test-util-inspect-proxy.js new file mode 100644 index 00000000000000..054a544d622369 --- /dev/null +++ b/test/js/node/test/parallel/test-util-inspect-proxy.js @@ -0,0 +1,183 @@ +// Flags: --expose-internals +'use strict'; + +// tests testing proxy internals are skipped, as getProxyDetails is not available in bun + +require('../common'); +const assert = require('assert'); +const util = require('util'); +// const { internalBinding } = require('internal/test/binding'); +// const processUtil = internalBinding('util'); +const opts = { showProxy: true }; + +let proxyObj; +let called = false; +const target = { + [util.inspect.custom](depth, { showProxy }) { + if (showProxy === false) { + called = true; + if (proxyObj !== this) { + throw new Error('Failed'); + } + } + return [1, 2, 3]; + } +}; +const handler = { + getPrototypeOf() { throw new Error('getPrototypeOf'); }, + setPrototypeOf() { throw new Error('setPrototypeOf'); }, + isExtensible() { throw new Error('isExtensible'); }, + preventExtensions() { throw new Error('preventExtensions'); }, + getOwnPropertyDescriptor() { throw new Error('getOwnPropertyDescriptor'); }, + defineProperty() { throw new Error('defineProperty'); }, + has() { throw new Error('has'); }, + get() { throw new Error('get'); }, + set() { throw new Error('set'); }, + deleteProperty() { throw new Error('deleteProperty'); }, + ownKeys() { throw new Error('ownKeys'); }, + apply() { throw new Error('apply'); }, + construct() { throw new Error('construct'); } +}; +proxyObj = new Proxy(target, handler); + +// Inspecting the proxy should not actually walk it's properties +util.inspect(proxyObj, opts); + +// Make sure inspecting object does not trigger any proxy traps. +util.format('%s', proxyObj); + +// getProxyDetails is an internal method, not intended for public use. +// This is here to test that the internals are working correctly. +// let details = processUtil.getProxyDetails(proxyObj, true); +// assert.strictEqual(target, details[0]); +// assert.strictEqual(handler, details[1]); + +// details = processUtil.getProxyDetails(proxyObj); +// assert.strictEqual(target, details[0]); +// assert.strictEqual(handler, details[1]); + +// details = processUtil.getProxyDetails(proxyObj, false); +// assert.strictEqual(target, details); + +// details = processUtil.getProxyDetails({}, true); +// assert.strictEqual(details, undefined); + +const r = Proxy.revocable({}, {}); +r.revoke(); + +// details = processUtil.getProxyDetails(r.proxy, true); +// assert.strictEqual(details[0], null); +// assert.strictEqual(details[1], null); + +// details = processUtil.getProxyDetails(r.proxy, false); +// assert.strictEqual(details, null); + +assert.strictEqual(util.inspect(r.proxy), ''); +assert.strictEqual( + util.inspect(r, { showProxy: true }), + '{ proxy: , revoke: [Function (anonymous)] }', +); + +assert.strictEqual(util.format('%s', r.proxy), ''); + +assert.strictEqual( + util.inspect(proxyObj, opts), + 'Proxy [\n' + + ' [ 1, 2, 3 ],\n' + + ' {\n' + + ' getPrototypeOf: [Function: getPrototypeOf],\n' + + ' setPrototypeOf: [Function: setPrototypeOf],\n' + + ' isExtensible: [Function: isExtensible],\n' + + ' preventExtensions: [Function: preventExtensions],\n' + + ' getOwnPropertyDescriptor: [Function: getOwnPropertyDescriptor],\n' + + ' defineProperty: [Function: defineProperty],\n' + + ' has: [Function: has],\n' + + ' get: [Function: get],\n' + + ' set: [Function: set],\n' + + ' deleteProperty: [Function: deleteProperty],\n' + + ' ownKeys: [Function: ownKeys],\n' + + ' apply: [Function: apply],\n' + + ' construct: [Function: construct]\n' + + ' }\n' + + ']' +); + +// // Using getProxyDetails with non-proxy returns undefined +// assert.strictEqual(processUtil.getProxyDetails({}), undefined); + +// Inspecting a proxy without the showProxy option set to true should not +// trigger any proxy handlers. +assert.strictEqual(util.inspect(proxyObj), '[ 1, 2, 3 ]'); +assert(called); + +// Yo dawg, I heard you liked Proxy so I put a Proxy +// inside your Proxy that proxies your Proxy's Proxy. +const proxy1 = new Proxy({}, {}); +const proxy2 = new Proxy(proxy1, {}); +const proxy3 = new Proxy(proxy2, proxy1); +const proxy4 = new Proxy(proxy1, proxy2); +const proxy5 = new Proxy(proxy3, proxy4); +const proxy6 = new Proxy(proxy5, proxy5); +const expected0 = '{}'; +const expected1 = 'Proxy [ {}, {} ]'; +const expected2 = 'Proxy [ Proxy [ {}, {} ], {} ]'; +const expected3 = 'Proxy [ Proxy [ Proxy [ {}, {} ], {} ], Proxy [ {}, {} ] ]'; +const expected4 = 'Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [ {}, {} ], {} ] ]'; +const expected5 = 'Proxy [\n ' + + 'Proxy [ Proxy [ Proxy [Array], {} ], Proxy [ {}, {} ] ],\n' + + ' Proxy [ Proxy [ {}, {} ], Proxy [ Proxy [Array], {} ] ]' + + '\n]'; +const expected6 = 'Proxy [\n' + + ' Proxy [\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ],\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ]\n' + + ' ],\n' + + ' Proxy [\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ],\n' + + ' Proxy [ Proxy [Array], Proxy [Array] ]\n' + + ' ]\n' + + ']'; +assert.strictEqual( + util.inspect(proxy1, { showProxy: 1, depth: null }), + expected1); +assert.strictEqual(util.inspect(proxy2, opts), expected2); +assert.strictEqual(util.inspect(proxy3, opts), expected3); +assert.strictEqual(util.inspect(proxy4, opts), expected4); +assert.strictEqual(util.inspect(proxy5, opts), expected5); +assert.strictEqual(util.inspect(proxy6, opts), expected6); +assert.strictEqual(util.inspect(proxy1), expected0); +assert.strictEqual(util.inspect(proxy2), expected0); +assert.strictEqual(util.inspect(proxy3), expected0); +assert.strictEqual(util.inspect(proxy4), expected0); +assert.strictEqual(util.inspect(proxy5), expected0); +assert.strictEqual(util.inspect(proxy6), expected0); + +// Just for fun, let's create a Proxy using Arrays. +const proxy7 = new Proxy([], []); +const expected7 = 'Proxy [ [], [] ]'; +assert.strictEqual(util.inspect(proxy7, opts), expected7); +assert.strictEqual(util.inspect(proxy7), '[]'); + +// Now we're just getting silly, right? +const proxy8 = new Proxy(Date, []); +const proxy9 = new Proxy(Date, String); +const expected8 = 'Proxy [ [Function: Date], [] ]'; +const expected9 = 'Proxy [ [Function: Date], [Function: String] ]'; +assert.strictEqual(util.inspect(proxy8, opts), expected8); +assert.strictEqual(util.inspect(proxy9, opts), expected9); +assert.strictEqual(util.inspect(proxy8), '[Function: Date]'); +assert.strictEqual(util.inspect(proxy9), '[Function: Date]'); + +const proxy10 = new Proxy(() => {}, {}); +const proxy11 = new Proxy(() => {}, { + get() { + return proxy11; + }, + apply() { + return proxy11; + } +}); +const expected10 = '[Function (anonymous)]'; +const expected11 = '[Function (anonymous)]'; +assert.strictEqual(util.inspect(proxy10), expected10); +assert.strictEqual(util.inspect(proxy11), expected11); diff --git a/test/js/node/test/parallel/test-util-stripvtcontrolcharacters.js b/test/js/node/test/parallel/test-util-stripvtcontrolcharacters.js new file mode 100644 index 00000000000000..a201c78976c0ac --- /dev/null +++ b/test/js/node/test/parallel/test-util-stripvtcontrolcharacters.js @@ -0,0 +1,26 @@ +'use strict'; + +require('../common'); +const util = require('util'); +const assert = require('node:assert'); + +// Ref: https://github.com/chalk/ansi-regex/blob/main/test.js +const tests = [ + // [before, expected] + ['\u001B[0m\u001B[4m\u001B[42m\u001B[31mfoo\u001B[39m\u001B[49m\u001B[24mfoo\u001B[0m', 'foofoo'], // Basic ANSI + ['\u001B[0;33;49;3;9;4mbar\u001B[0m', 'bar'], // Advanced colors + ['foo\u001B[0gbar', 'foobar'], // Clear tabs + ['foo\u001B[Kbar', 'foobar'], // Clear line + ['foo\u001B[2Jbar', 'foobar'], // Clear screen +]; + +for (const ST of ['\u0007', '\u001B\u005C', '\u009C']) { + tests.push( + [`\u001B]8;;mailto:no-replay@mail.com${ST}mail\u001B]8;;${ST}`, 'mail'], + [`\u001B]8;k=v;https://example-a.com/?a_b=1&c=2#tit%20le${ST}click\u001B]8;;${ST}`, 'click'], + ); +} + +for (const [before, expected] of tests) { + assert.strictEqual(util.stripVTControlCharacters(before), expected); +} diff --git a/test/js/node/test/parallel/test-util-types.js b/test/js/node/test/parallel/test-util-types.js new file mode 100644 index 00000000000000..755209036f15ca --- /dev/null +++ b/test/js/node/test/parallel/test-util-types.js @@ -0,0 +1,296 @@ +'use strict'; +// JSStream is disabled because it is a node internal +// vm tests are skipped because node:vm Module is not yet implemented +// // Flags: --experimental-vm-modules --expose-internals +const common = require('../common'); +const assert = require('assert'); +const { types, inspect } = require('util'); +const vm = require('vm'); +// const { internalBinding } = require('internal/test/binding'); +// const { JSStream } = internalBinding('js_stream'); + +// const external = (new JSStream())._externalStream; + +for (const [ value, _method ] of [ + // [ external, 'isExternal' ], + [ new Date() ], + [ (function() { return arguments; })(), 'isArgumentsObject' ], + [ new Boolean(), 'isBooleanObject' ], + [ new Number(), 'isNumberObject' ], + [ new String(), 'isStringObject' ], + [ Object(Symbol()), 'isSymbolObject' ], + [ Object(BigInt(0)), 'isBigIntObject' ], + [ new Error(), 'isNativeError' ], + [ new RegExp() ], + [ async function() {}, 'isAsyncFunction' ], + [ function*() {}, 'isGeneratorFunction' ], + [ (function*() {})(), 'isGeneratorObject' ], + [ Promise.resolve() ], + [ new Map() ], + [ new Set() ], + [ (new Map())[Symbol.iterator](), 'isMapIterator' ], + [ (new Set())[Symbol.iterator](), 'isSetIterator' ], + [ new WeakMap() ], + [ new WeakSet() ], + [ new ArrayBuffer() ], + [ new Uint8Array() ], + [ new Uint8ClampedArray() ], + [ new Uint16Array() ], + [ new Uint32Array() ], + [ new Int8Array() ], + [ new Int16Array() ], + [ new Int32Array() ], + [ new Float32Array() ], + [ new Float64Array() ], + [ new BigInt64Array() ], + [ new BigUint64Array() ], + [ Object.defineProperty(new Uint8Array(), + Symbol.toStringTag, + { value: 'foo' }) ], + [ new DataView(new ArrayBuffer()) ], + [ new SharedArrayBuffer() ], + [ new Proxy({}, {}), 'isProxy' ], +]) { + const method = _method || `is${value.constructor.name}`; + assert(method in types, `Missing ${method} for ${inspect(value)}`); + assert(types[method](value), `Want ${inspect(value)} to match ${method}`); + + for (const key of Object.keys(types)) { + if ((types.isArrayBufferView(value) || + types.isAnyArrayBuffer(value)) && key.includes('Array') || + key === 'isBoxedPrimitive') { + continue; + } + + assert.strictEqual(types[key](value), + key === method, + `${inspect(value)}: ${key}, ` + + `${method}, ${types[key](value)}`); + } +} + +// Check boxed primitives. +[ + new Boolean(), + new Number(), + new String(), + Object(Symbol()), + Object(BigInt(0)), +].forEach((entry) => assert(types.isBoxedPrimitive(entry))); + +{ + assert(!types.isUint8Array({ [Symbol.toStringTag]: 'Uint8Array' })); + assert(types.isUint8Array(vm.runInNewContext('new Uint8Array'))); + + assert(!types.isUint8ClampedArray({ + [Symbol.toStringTag]: 'Uint8ClampedArray' + })); + assert(types.isUint8ClampedArray( + vm.runInNewContext('new Uint8ClampedArray') + )); + + assert(!types.isUint16Array({ [Symbol.toStringTag]: 'Uint16Array' })); + assert(types.isUint16Array(vm.runInNewContext('new Uint16Array'))); + + assert(!types.isUint32Array({ [Symbol.toStringTag]: 'Uint32Array' })); + assert(types.isUint32Array(vm.runInNewContext('new Uint32Array'))); + + assert(!types.isInt8Array({ [Symbol.toStringTag]: 'Int8Array' })); + assert(types.isInt8Array(vm.runInNewContext('new Int8Array'))); + + assert(!types.isInt16Array({ [Symbol.toStringTag]: 'Int16Array' })); + assert(types.isInt16Array(vm.runInNewContext('new Int16Array'))); + + assert(!types.isInt32Array({ [Symbol.toStringTag]: 'Int32Array' })); + assert(types.isInt32Array(vm.runInNewContext('new Int32Array'))); + + assert(!types.isFloat32Array({ [Symbol.toStringTag]: 'Float32Array' })); + assert(types.isFloat32Array(vm.runInNewContext('new Float32Array'))); + + assert(!types.isFloat64Array({ [Symbol.toStringTag]: 'Float64Array' })); + assert(types.isFloat64Array(vm.runInNewContext('new Float64Array'))); + + assert(!types.isBigInt64Array({ [Symbol.toStringTag]: 'BigInt64Array' })); + assert(types.isBigInt64Array(vm.runInNewContext('new BigInt64Array'))); + + assert(!types.isBigUint64Array({ [Symbol.toStringTag]: 'BigUint64Array' })); + assert(types.isBigUint64Array(vm.runInNewContext('new BigUint64Array'))); +} + +{ + const primitive = true; + const arrayBuffer = new ArrayBuffer(); + const buffer = Buffer.from(arrayBuffer); + const dataView = new DataView(arrayBuffer); + const uint8Array = new Uint8Array(arrayBuffer); + const uint8ClampedArray = new Uint8ClampedArray(arrayBuffer); + const uint16Array = new Uint16Array(arrayBuffer); + const uint32Array = new Uint32Array(arrayBuffer); + const int8Array = new Int8Array(arrayBuffer); + const int16Array = new Int16Array(arrayBuffer); + const int32Array = new Int32Array(arrayBuffer); + const float32Array = new Float32Array(arrayBuffer); + const float64Array = new Float64Array(arrayBuffer); + const bigInt64Array = new BigInt64Array(arrayBuffer); + const bigUint64Array = new BigUint64Array(arrayBuffer); + + const fakeBuffer = { __proto__: Buffer.prototype }; + const fakeDataView = { __proto__: DataView.prototype }; + const fakeUint8Array = { __proto__: Uint8Array.prototype }; + const fakeUint8ClampedArray = { __proto__: Uint8ClampedArray.prototype }; + const fakeUint16Array = { __proto__: Uint16Array.prototype }; + const fakeUint32Array = { __proto__: Uint32Array.prototype }; + const fakeInt8Array = { __proto__: Int8Array.prototype }; + const fakeInt16Array = { __proto__: Int16Array.prototype }; + const fakeInt32Array = { __proto__: Int32Array.prototype }; + const fakeFloat32Array = { __proto__: Float32Array.prototype }; + const fakeFloat64Array = { __proto__: Float64Array.prototype }; + const fakeBigInt64Array = { __proto__: BigInt64Array.prototype }; + const fakeBigUint64Array = { __proto__: BigUint64Array.prototype }; + + const stealthyDataView = + Object.setPrototypeOf(new DataView(arrayBuffer), Uint8Array.prototype); + const stealthyUint8Array = + Object.setPrototypeOf(new Uint8Array(arrayBuffer), ArrayBuffer.prototype); + const stealthyUint8ClampedArray = + Object.setPrototypeOf( + new Uint8ClampedArray(arrayBuffer), ArrayBuffer.prototype + ); + const stealthyUint16Array = + Object.setPrototypeOf(new Uint16Array(arrayBuffer), Uint16Array.prototype); + const stealthyUint32Array = + Object.setPrototypeOf(new Uint32Array(arrayBuffer), Uint32Array.prototype); + const stealthyInt8Array = + Object.setPrototypeOf(new Int8Array(arrayBuffer), Int8Array.prototype); + const stealthyInt16Array = + Object.setPrototypeOf(new Int16Array(arrayBuffer), Int16Array.prototype); + const stealthyInt32Array = + Object.setPrototypeOf(new Int32Array(arrayBuffer), Int32Array.prototype); + const stealthyFloat32Array = + Object.setPrototypeOf( + new Float32Array(arrayBuffer), Float32Array.prototype + ); + const stealthyFloat64Array = + Object.setPrototypeOf( + new Float64Array(arrayBuffer), Float64Array.prototype + ); + const stealthyBigInt64Array = + Object.setPrototypeOf( + new BigInt64Array(arrayBuffer), BigInt64Array.prototype + ); + const stealthyBigUint64Array = + Object.setPrototypeOf( + new BigUint64Array(arrayBuffer), BigUint64Array.prototype + ); + + const all = [ + primitive, arrayBuffer, buffer, fakeBuffer, + dataView, fakeDataView, stealthyDataView, + uint8Array, fakeUint8Array, stealthyUint8Array, + uint8ClampedArray, fakeUint8ClampedArray, stealthyUint8ClampedArray, + uint16Array, fakeUint16Array, stealthyUint16Array, + uint32Array, fakeUint32Array, stealthyUint32Array, + int8Array, fakeInt8Array, stealthyInt8Array, + int16Array, fakeInt16Array, stealthyInt16Array, + int32Array, fakeInt32Array, stealthyInt32Array, + float32Array, fakeFloat32Array, stealthyFloat32Array, + float64Array, fakeFloat64Array, stealthyFloat64Array, + bigInt64Array, fakeBigInt64Array, stealthyBigInt64Array, + bigUint64Array, fakeBigUint64Array, stealthyBigUint64Array, + ]; + + const expected = { + isArrayBufferView: [ + buffer, + dataView, stealthyDataView, + uint8Array, stealthyUint8Array, + uint8ClampedArray, stealthyUint8ClampedArray, + uint16Array, stealthyUint16Array, + uint32Array, stealthyUint32Array, + int8Array, stealthyInt8Array, + int16Array, stealthyInt16Array, + int32Array, stealthyInt32Array, + float32Array, stealthyFloat32Array, + float64Array, stealthyFloat64Array, + bigInt64Array, stealthyBigInt64Array, + bigUint64Array, stealthyBigUint64Array, + ], + isTypedArray: [ + buffer, + uint8Array, stealthyUint8Array, + uint8ClampedArray, stealthyUint8ClampedArray, + uint16Array, stealthyUint16Array, + uint32Array, stealthyUint32Array, + int8Array, stealthyInt8Array, + int16Array, stealthyInt16Array, + int32Array, stealthyInt32Array, + float32Array, stealthyFloat32Array, + float64Array, stealthyFloat64Array, + bigInt64Array, stealthyBigInt64Array, + bigUint64Array, stealthyBigUint64Array, + ], + isUint8Array: [ + buffer, uint8Array, stealthyUint8Array, + ], + isUint8ClampedArray: [ + uint8ClampedArray, stealthyUint8ClampedArray, + ], + isUint16Array: [ + uint16Array, stealthyUint16Array, + ], + isUint32Array: [ + uint32Array, stealthyUint32Array, + ], + isInt8Array: [ + int8Array, stealthyInt8Array, + ], + isInt16Array: [ + int16Array, stealthyInt16Array, + ], + isInt32Array: [ + int32Array, stealthyInt32Array, + ], + isFloat32Array: [ + float32Array, stealthyFloat32Array, + ], + isFloat64Array: [ + float64Array, stealthyFloat64Array, + ], + isBigInt64Array: [ + bigInt64Array, stealthyBigInt64Array, + ], + isBigUint64Array: [ + bigUint64Array, stealthyBigUint64Array, + ] + }; + + for (const testedFunc of Object.keys(expected)) { + const func = types[testedFunc]; + const yup = []; + for (const value of all) { + if (func(value)) { + yup.push(value); + } + } + console.log('Testing', testedFunc); + assert.deepStrictEqual(yup, expected[testedFunc]); + } +} + +// (skipped) +// (async () => { +// const m = new vm.SourceTextModule(''); +// await m.link(() => 0); +// await m.evaluate(); +// assert.ok(types.isModuleNamespaceObject(m.namespace)); +// })().then(common.mustCall()); + +{ + // eslint-disable-next-line node-core/crypto-check + if (common.hasCrypto) { + const crypto = require('crypto'); + assert.ok(!types.isKeyObject(crypto.createHash('sha1'))); + } + assert.ok(!types.isCryptoKey()); + assert.ok(!types.isKeyObject()); +} From 96dc7ed96ea536f6f0304c231d9005b187f458ab Mon Sep 17 00:00:00 2001 From: kjjd84 Date: Fri, 10 Jan 2025 22:52:00 -0500 Subject: [PATCH 5/6] Update unlink.md guide (#16268) --- docs/guides/write-file/unlink.md | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/docs/guides/write-file/unlink.md b/docs/guides/write-file/unlink.md index ba0cbe8b1d3611..ef2fc5fb2c92e8 100644 --- a/docs/guides/write-file/unlink.md +++ b/docs/guides/write-file/unlink.md @@ -2,22 +2,10 @@ name: Delete a file --- -To synchronously delete a file with Bun, use the `unlinkSync` function from the [`node:fs`](https://nodejs.org/api/fs.html#fs_fs_unlink_path_callback) module. (Currently, there is no `Bun` API for deleting files.) +To delete a file in Bun, use the `delete` method. ```ts -import { unlinkSync } from "node:fs"; +import { file } from "bun"; -const path = "/path/to/file.txt"; -unlinkSync(path); -``` - ---- - -To remove a file asynchronously, use the `unlink` function from the [`node:fs/promises`](https://nodejs.org/api/fs.html#fs_fspromises_unlink_path) module. - -```ts -import { unlink } from "node:fs/promises"; - -const path = "/path/to/file.txt"; -await unlink(path); +await file("./path-to-file.txt").delete(); ``` From b04ce670e3dc2b00fb493aa0d8d064b2e24740b7 Mon Sep 17 00:00:00 2001 From: pfg Date: Fri, 10 Jan 2025 20:04:16 -0800 Subject: [PATCH 6/6] Fix #16312 (#16322) Co-authored-by: Jarred Sumner --- src/bun.js/bindings/JSPropertyIterator.cpp | 8 ++++++-- test/bun.lockb | Bin 438666 -> 445722 bytes test/package.json | 2 ++ test/regression/issue/16312.test.ts | 13 +++++++++++++ 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/regression/issue/16312.test.ts diff --git a/src/bun.js/bindings/JSPropertyIterator.cpp b/src/bun.js/bindings/JSPropertyIterator.cpp index 89e64a8ac88121..c7e3ae8fed8589 100644 --- a/src/bun.js/bindings/JSPropertyIterator.cpp +++ b/src/bun.js/bindings/JSPropertyIterator.cpp @@ -45,6 +45,10 @@ extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObje auto scope = DECLARE_THROW_SCOPE(vm); JSC::PropertyNameArray array(vm, PropertyNameMode::StringsAndSymbols, PrivateSymbolMode::Exclude); + if (UNLIKELY(object->hasNonReifiedStaticProperties())) { + object->reifyAllStaticProperties(globalObject); + } + #if OS(WINDOWS) if (UNLIKELY(object->type() == JSC::ProxyObjectType)) { // Check if we're actually iterating through the JSEnvironmentVariableMap's proxy. @@ -75,7 +79,7 @@ extern "C" JSPropertyIterator* Bun__JSPropertyIterator__create(JSC::JSGlobalObje if (only_non_index_properties) { object->getOwnNonIndexPropertyNames(globalObject, array, DontEnumPropertiesMode::Exclude); } else { - object->getOwnPropertyNames(object, globalObject, array, DontEnumPropertiesMode::Exclude); + object->methodTable()->getOwnPropertyNames(object, globalObject, array, DontEnumPropertiesMode::Exclude); } } else { object->getPropertyNames(globalObject, array, DontEnumPropertiesMode::Exclude); @@ -161,7 +165,7 @@ extern "C" EncodedJSValue Bun__JSPropertyIterator__getNameAndValue(JSPropertyIte auto& vm = iter->vm; auto scope = DECLARE_THROW_SCOPE(vm); PropertySlot slot(object, PropertySlot::InternalMethodType::GetOwnProperty); - if (!object->getOwnPropertySlot(object, globalObject, prop, slot)) { + if (!object->methodTable()->getOwnPropertySlot(object, globalObject, prop, slot)) { return {}; } RETURN_IF_EXCEPTION(scope, {}); diff --git a/test/bun.lockb b/test/bun.lockb index fb2b70b1f290649c95defa16fe625f9258ead3ea..2d9775c983b0865217e2377a2bc115f818a8a3d8 100755 GIT binary patch delta 73209 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 aU6`ST&u-pREj;l{o?P=Oo!aK;U;H0Lru|R= diff --git a/test/package.json b/test/package.json index 9c9d51d496c4a6..edc248dadfa608 100644 --- a/test/package.json +++ b/test/package.json @@ -20,6 +20,8 @@ "@remix-run/serve": "2.10.3", "@resvg/resvg-js": "2.4.1", "@swc/core": "1.3.38", + "@testing-library/jest-dom": "6.6.3", + "@testing-library/react": "16.1.0", "aws-cdk-lib": "2.148.0", "axios": "1.6.8", "body-parser": "1.20.2", diff --git a/test/regression/issue/16312.test.ts b/test/regression/issue/16312.test.ts new file mode 100644 index 00000000000000..15b9019c0d17e4 --- /dev/null +++ b/test/regression/issue/16312.test.ts @@ -0,0 +1,13 @@ +import { test, afterEach, expect } from "bun:test"; +import { cleanup } from "@testing-library/react"; +import * as matchers from "@testing-library/jest-dom/matchers"; + +expect.extend(matchers); +afterEach(() => { + cleanup(); +}); + +test("expect extended", () => { + // @ts-ignore + expect(expect.toBeInTheDocument).not.toBe(undefined); +});