Complete rework of the majority of node:util, primarily util.inspect (#4493)

* 1st revision of new util.inspect impl. (not done)

* fix util.types.isArrayBuffer

* fix some utl tests and bugs

* fix node:tty missing primordials

* fix utl stackoverflow handling & some tests

* narrow down diff. context test

* util.inspect indirect circulars optimization

* temp workaround for buggy is...Function checks

* impl. Map/Set/Iterator entries inspection

* fix bigint & symbol objects inspection

* error inspection fixes

* misc util tests stuff

* inline getExternalValue stub

* leftovers

* util.inspect promise internals

* run bun fmt

* commit make js changes

* cut out unnecessary utl files

* reorganize utl folder structure

* remove browserify buffer check

* Try to revert git messing up uws somehow

This reverts commit 2c27e16e7d.

* commit src/js/out files again

* redo this edit too

* refresh js/out files

* Removed uws submodule

* tidy up

* unused primordials

* run fmt

---------

Co-authored-by: dave caruso <me@paperdave.net>
This commit is contained in:
jhmaster
2023-09-28 03:51:49 -03:00
committed by GitHub
parent 31d96a1b7f
commit e60b3607c1
23 changed files with 7863 additions and 612 deletions

View File

@@ -203,7 +203,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionIsWeakSet, (JSC::JSGlobalObject * globalObjec
JSC_DEFINE_HOST_FUNCTION(jsFunctionIsArrayBuffer, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
{
GET_FIRST_CELL
return JSValue::encode(jsBoolean(jsDynamicCast<JSArrayBuffer*>(cell) != nullptr));
auto* arrayBuffer = jsDynamicCast<JSArrayBuffer*>(cell);
if (!arrayBuffer)
return JSValue::encode(jsBoolean(false));
return JSValue::encode(jsBoolean(!arrayBuffer->isShared()));
}
JSC_DEFINE_HOST_FUNCTION(jsFunctionIsDataView, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callframe))
{

View File

@@ -29,7 +29,13 @@ const internalRegistry = new Map();
// Build Registry
for (let i = 0; i < moduleList.length; i++) {
const prefix = moduleList[i].startsWith("node/") ? "node:" : moduleList[i].startsWith("bun:") ? "bun/" : undefined;
const prefix = moduleList[i].startsWith("node/")
? "node:"
: moduleList[i].startsWith("bun:")
? "bun/"
: moduleList[i].startsWith("internal/")
? "internal/"
: undefined;
if (prefix) {
const id = prefix + moduleList[i].slice(prefix.length).replaceAll(".", "/").slice(0, -3);
internalRegistry.set(id, i);
@@ -91,7 +97,7 @@ globalThis.requireTransformer = (specifier: string, from: string) => {
return codegenRequireId(`${found}/*${path.relative(BASE, relativeMatch)}*/`);
}
throw new Error(`Builtin Bundler: Could not resolve "${specifier}" in ${from}. These cannot be relative.`);
throw new Error(`Builtin Bundler: Could not resolve "${specifier}" in ${from}.`);
};
// Preprocess builtins

View File

@@ -0,0 +1,217 @@
// TODO: Use native code and JSC intrinsics for everything in this file.
// It is primarily used for `internal/util`
const createSafeIterator = (factory, next) => {
class SafeIterator {
constructor(iterable) {
this._iterator = factory(iterable);
}
next() {
return next(this._iterator);
}
[Symbol.iterator]() {
return this;
}
}
Object.setPrototypeOf(SafeIterator.prototype, null);
Object.freeze(SafeIterator.prototype);
Object.freeze(SafeIterator);
return SafeIterator;
};
function getGetter(cls, getter) {
// TODO: __lookupGetter__ is deprecated, but Object.getOwnPropertyDescriptor doesn't work on built-ins like Typed Arrays.
return Function.prototype.call.bind(cls.prototype.__lookupGetter__(getter));
}
// function getterCaller(getter) {
// return val => {
// return val.constructor.prototype.__lookupGetter__(getter).call(val);
// };
// }
function uncurryThis(func) {
return Function.prototype.call.bind(func);
}
const copyProps = (src, dest) => {
Array.prototype.forEach.call(Reflect.ownKeys(src), key => {
if (!Reflect.getOwnPropertyDescriptor(dest, key)) {
Reflect.defineProperty(dest, key, Reflect.getOwnPropertyDescriptor(src, key));
}
});
};
const makeSafe = (unsafe, safe) => {
if (Symbol.iterator in unsafe.prototype) {
const dummy = new unsafe();
let next; // We can reuse the same `next` method.
Array.prototype.forEach.call(Reflect.ownKeys(unsafe.prototype), key => {
if (!Reflect.getOwnPropertyDescriptor(safe.prototype, key)) {
const desc = Reflect.getOwnPropertyDescriptor(unsafe.prototype, key);
if (
typeof desc.value === "function" &&
desc.value.length === 0 &&
Symbol.iterator in (Function.prototype.call.call(desc.value, dummy) || {})
) {
const createIterator = uncurryThis(desc.value);
next ??= uncurryThis(createIterator(dummy).next);
const SafeIterator = createSafeIterator(createIterator, next);
desc.value = function () {
return new SafeIterator(this);
};
}
Reflect.defineProperty(safe.prototype, key, desc);
}
});
} else copyProps(unsafe.prototype, safe.prototype);
copyProps(unsafe, safe);
Object.setPrototypeOf(safe.prototype, null);
Object.freeze(safe.prototype);
Object.freeze(safe);
return safe;
};
const StringIterator = Function.prototype.call.bind(String.prototype[Symbol.iterator]);
const StringIteratorPrototype = Reflect.getPrototypeOf(StringIterator(""));
function ErrorCaptureStackTrace(targetObject) {
const stack = new Error().stack;
// Remove the second line, which is this function
targetObject.stack = stack.replace(/.*\n.*/, "$1");
}
export default {
makeSafe, // exported for testing
Array,
ArrayFrom: Array.from,
ArrayIsArray: Array.isArray,
ArrayPrototypeFlat: Function.prototype.call.bind(Array.prototype.flat),
ArrayPrototypeFilter: Function.prototype.call.bind(Array.prototype.filter),
ArrayPrototypeForEach: Function.prototype.call.bind(Array.prototype.forEach),
ArrayPrototypeIncludes: Function.prototype.call.bind(Array.prototype.includes),
ArrayPrototypeIndexOf: Function.prototype.call.bind(Array.prototype.indexOf),
ArrayPrototypeJoin: Function.prototype.call.bind(Array.prototype.join),
ArrayPrototypeMap: Function.prototype.call.bind(Array.prototype.map),
ArrayPrototypePop: Function.prototype.call.bind(Array.prototype.pop),
ArrayPrototypePush: Function.prototype.call.bind(Array.prototype.push),
ArrayPrototypePushApply: Function.apply.bind(Array.prototype.push),
ArrayPrototypeSlice: Function.prototype.call.bind(Array.prototype.slice),
ArrayPrototypeSort: Function.prototype.call.bind(Array.prototype.sort),
ArrayPrototypeSplice: Function.prototype.call.bind(Array.prototype.splice),
ArrayPrototypeUnshift: Function.prototype.call.bind(Array.prototype.unshift),
BigIntPrototypeValueOf: Function.prototype.call.bind(BigInt.prototype.valueOf),
BooleanPrototypeValueOf: Function.prototype.call.bind(Boolean.prototype.valueOf),
DatePrototypeGetTime: Function.prototype.call.bind(Date.prototype.getTime),
DatePrototypeToISOString: Function.prototype.call.bind(Date.prototype.toISOString),
DatePrototypeToString: Function.prototype.call.bind(Date.prototype.toString),
ErrorCaptureStackTrace,
ErrorPrototypeToString: Function.prototype.call.bind(Error.prototype.toString),
FunctionPrototypeBind: Function.prototype.call.bind(Function.prototype.bind),
FunctionPrototypeCall: Function.prototype.call.bind(Function.prototype.call),
FunctionPrototypeToString: Function.prototype.call.bind(Function.prototype.toString),
JSONStringify: JSON.stringify,
MapPrototypeGetSize: getGetter(Map, "size"),
MapPrototypeEntries: Function.prototype.call.bind(Map.prototype.entries),
MapPrototypeValues: Function.prototype.call.bind(Map.prototype.values),
MapPrototypeKeys: Function.prototype.call.bind(Map.prototype.keys),
MathFloor: Math.floor,
MathMax: Math.max,
MathMin: Math.min,
MathRound: Math.round,
MathSqrt: Math.sqrt,
MathTrunc: Math.trunc,
Number,
NumberIsFinite: Number.isFinite,
NumberIsNaN: Number.isNaN,
NumberParseFloat: Number.parseFloat,
NumberParseInt: Number.parseInt,
NumberPrototypeToString: Function.prototype.call.bind(Number.prototype.toString),
NumberPrototypeValueOf: Function.prototype.call.bind(Number.prototype.valueOf),
Object,
ObjectAssign: Object.assign,
ObjectCreate: Object.create,
ObjectDefineProperty: Object.defineProperty,
ObjectEntries: Object.entries,
ObjectGetOwnPropertyDescriptor: Object.getOwnPropertyDescriptor,
ObjectGetOwnPropertyDescriptors: Object.getOwnPropertyDescriptors,
ObjectGetOwnPropertyNames: Object.getOwnPropertyNames,
ObjectGetOwnPropertySymbols: Object.getOwnPropertySymbols,
ObjectGetPrototypeOf: Object.getPrototypeOf,
ObjectIs: Object.is,
ObjectKeys: Object.keys,
ObjectPrototypeHasOwnProperty: Function.prototype.call.bind(Object.prototype.hasOwnProperty),
ObjectPrototypePropertyIsEnumerable: Function.prototype.call.bind(Object.prototype.propertyIsEnumerable),
ObjectPrototypeToString: Function.prototype.call.bind(Object.prototype.toString),
ObjectSeal: Object.seal,
ObjectSetPrototypeOf: Object.setPrototypeOf,
ReflectApply: Reflect.apply,
ReflectOwnKeys: Reflect.ownKeys,
RegExp,
RegExpPrototypeExec: Function.prototype.call.bind(RegExp.prototype.exec),
RegExpPrototypeSymbolReplace: Function.prototype.call.bind(RegExp.prototype[Symbol.replace]),
RegExpPrototypeSymbolSplit: Function.prototype.call.bind(RegExp.prototype[Symbol.split]),
RegExpPrototypeTest: Function.prototype.call.bind(RegExp.prototype.test),
RegExpPrototypeToString: Function.prototype.call.bind(RegExp.prototype.toString),
SafeStringIterator: createSafeIterator(StringIterator, Function.prototype.call.bind(StringIteratorPrototype.next)),
SafeMap: makeSafe(
Map,
class SafeMap extends Map {
constructor(i) {
super(i);
}
},
),
SafeSet: makeSafe(
Set,
class SafeSet extends Set {
constructor(i) {
super(i);
}
},
),
SetPrototypeGetSize: getGetter(Set, "size"),
SetPrototypeEntries: Function.prototype.call.bind(Set.prototype.entries),
SetPrototypeValues: Function.prototype.call.bind(Set.prototype.values),
String,
StringPrototypeCharCodeAt: Function.prototype.call.bind(String.prototype.charCodeAt),
StringPrototypeCodePointAt: Function.prototype.call.bind(String.prototype.codePointAt),
StringPrototypeEndsWith: Function.prototype.call.bind(String.prototype.endsWith),
StringPrototypeIncludes: Function.prototype.call.bind(String.prototype.includes),
StringPrototypeIndexOf: Function.prototype.call.bind(String.prototype.indexOf),
StringPrototypeLastIndexOf: Function.prototype.call.bind(String.prototype.lastIndexOf),
StringPrototypeMatch: Function.prototype.call.bind(String.prototype.match),
StringPrototypeNormalize: Function.prototype.call.bind(String.prototype.normalize),
StringPrototypePadEnd: Function.prototype.call.bind(String.prototype.padEnd),
StringPrototypePadStart: Function.prototype.call.bind(String.prototype.padStart),
StringPrototypeRepeat: Function.prototype.call.bind(String.prototype.repeat),
StringPrototypeReplace: Function.prototype.call.bind(String.prototype.replace),
StringPrototypeReplaceAll: Function.prototype.call.bind(String.prototype.replaceAll),
StringPrototypeSlice: Function.prototype.call.bind(String.prototype.slice),
StringPrototypeSplit: Function.prototype.call.bind(String.prototype.split),
StringPrototypeStartsWith: Function.prototype.call.bind(String.prototype.startsWith),
StringPrototypeToLowerCase: Function.prototype.call.bind(String.prototype.toLowerCase),
StringPrototypeTrim: Function.prototype.call.bind(String.prototype.trim),
StringPrototypeValueOf: Function.prototype.call.bind(String.prototype.valueOf),
SymbolPrototypeToString: Function.prototype.call.bind(Symbol.prototype.toString),
SymbolPrototypeValueOf: Function.prototype.call.bind(Symbol.prototype.valueOf),
SymbolIterator: Symbol.iterator,
SymbolFor: Symbol.for,
SymbolToStringTag: Symbol.toStringTag,
TypedArrayPrototypeGetLength: getGetter(Uint8Array, "length"),
TypedArrayPrototypeGetSymbolToStringTag: getGetter(Uint8Array, Symbol.toStringTag),
Uint8ClampedArray,
Uint8Array,
Uint16Array,
Uint32Array,
Int8Array,
Int16Array,
Int32Array,
Float32Array,
Float64Array,
BigUint64Array,
BigInt64Array,
uncurryThis,
};

View File

@@ -0,0 +1,77 @@
# node-inspect-extracted
Vendored copy of [node-inspect-extracted](https://github.com/hildjj/node-inspect-extracted) with adaptations for Bun.
Some features not relevant to Bun have been removed. Others might be added or modified.
This library provides an as-faithful-as-possible implementation of Node.js's
[`util.inspect`](https://nodejs.org/api/util.html#util_util_inspect_object_options) function.
This is currently done for compatibility reasons. In the future, this should be replaced with a 100% native implementation.
## API
The following [`util`](https://nodejs.org/api/util.html) functions:
- [`inspect(object[,showHidden|options[,depth [, colors]]])`](https://nodejs.org/api/util.html#util_util_inspect_object_showhidden_depth_colors)
- [`format(format[, ...args])`](https://nodejs.org/api/util.html#util_util_format_format_args)
- [`formatWithOptions(inspectOptions, format[, ...args])`](https://nodejs.org/api/util.html#util_util_formatwithoptions_inspectoptions_format_args)
<!--And these extras:
- `stylizeWithColor(str, styleType)`: colorize `str` with ANSI escapes according to the styleType
- `stylizeWithHTML(str, styleType)`: colorize `str` with HTML span tags
## Colors
If you specify `{colors: true}` in the inspect options, you will get ANSI
escape codes, just as you would in Node. That's unlikely to be helpful to you
on the Web, so you might want `stylizeWithHTML`, which is also exported from the package:
```js
inspect(
{ a: 1 },
{
compact: false,
stylize: stylizeWithHTML,
},
);
```
which yields this ugly HTML:
```html
{ a: <span style="color:yellow;">1</span> }
```
If you want better HTML, the [lightly-documented](https://nodejs.org/api/util.html#util_custom_inspection_functions_on_objects) `stylize` option requires
a function that takes two parameters, a string, and a class name. The mappings
from class names to colors is in `inspect.styles`, so start with this:
```js
function stylizeWithHTML(str, styleType) {
const style = inspect.styles[styleType];
if (style !== undefined) {
return `<span style="color:${style};">${str}</span>`;
}
return str;
}
```-->
## Known Limitations
- Objects that have been mangled with `Object.setPrototypeOf`
do not retain their original type information.
[[bug](https://github.com/hildjj/node-inspect-extracted/issues/3)]
- `WeakMap` and `WeakSet` will not show their contents, because those contents
cannot be iterated over in unprivileged code.
- Colorful stack traces are not completely accurate with respect to what
modules are Node-internal. This doesn't matter on the Web.
## LICENSE
This code is an adaptation of the Node.js internal implementation, mostly from
the file lib/internal/util/inspect.js, which does not have the Joyent
copyright header. The maintainers of this package will not assert copyright
over this code, but will assign ownership to the Node.js contributors, with
the same license as specified in the Node.js codebase; the portion adapted
here should all be plain MIT license.

347
src/js/internal/util/inspect.d.ts vendored Normal file
View File

@@ -0,0 +1,347 @@
/**
* Extracted from https://github.com/DefinitelyTyped/DefinitelyTyped
*
* This project is licensed under the MIT license.
* Copyrights are respective of each contributor listed at the beginning of each definition file.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* The `util` module supports the needs of Node.js internal APIs. Many of the
* utilities are useful for application and module developers as well. To access
* it:
*
* ```js
* const util = require('node-inspect-extracted');
* // or
* import * as util from 'node-inspect-extracted';
* ```
* @see [source](https://github.com/nodejs/node/blob/v17.6.0/lib/util.js)
*/
declare module "node-inspect-extracted" {
export interface InspectOptions {
/**
* If set to `true`, getters are going to be
* inspected as well. If set to `'get'` only getters without setter are going
* to be inspected. If set to `'set'` only getters having a corresponding
* setter are going to be inspected. This might cause side effects depending on
* the getter function.
* @default `false`
*/
getters?: "get" | "set" | boolean | undefined;
showHidden?: boolean | undefined;
/**
* @default 2
*/
depth?: number | null | undefined;
colors?: boolean | undefined;
customInspect?: boolean | undefined;
showProxy?: boolean | undefined;
maxArrayLength?: number | null | undefined;
/**
* Specifies the maximum number of characters to
* include when formatting. Set to `null` or `Infinity` to show all elements.
* Set to `0` or negative to show no characters.
* @default 10000
*/
maxStringLength?: number | null | undefined;
breakLength?: number | undefined;
/**
* Setting this to `false` causes each object key
* to be displayed on a new line. It will also add new lines to text that is
* longer than `breakLength`. If set to a number, the most `n` inner elements
* are united on a single line as long as all properties fit into
* `breakLength`. Short array elements are also grouped together. Note that no
* text will be reduced below 16 characters, no matter the `breakLength` size.
* For more information, see the example below.
* @default `true`
*/
compact?: boolean | number | undefined;
sorted?: boolean | ((a: string, b: string) => number) | undefined;
numericSeparator?: boolean | undefined;
}
// Not exposed from node's `util` package.
// export const inspectDefaultOptions: Required<InspectOptions>;
export type Style =
| "special"
| "number"
| "bigint"
| "boolean"
| "undefined"
| "null"
| "string"
| "symbol"
| "date"
| "regexp"
| "module";
export type CustomInspectFunction = (depth: number, options: InspectOptionsStylized) => string;
export interface InspectOptionsStylized extends InspectOptions {
/**
* Write your own function for adding color to the output, or use one of the built-in stylize* functions.
*/
stylize(text: string, styleType: Style): string;
}
/**
* The `util.format()` method returns a formatted string using the first argument
* as a `printf`\-like format string which can contain zero or more format
* specifiers. Each specifier is replaced with the converted value from the
* corresponding argument. Supported specifiers are:
*
* If a specifier does not have a corresponding argument, it is not replaced:
*
* ```js
* util.format('%s:%s', 'foo');
* // Returns: 'foo:%s'
* ```
*
* Values that are not part of the format string are formatted using`util.inspect()` if their type is not `string`.
*
* If there are more arguments passed to the `util.format()` method than the
* number of specifiers, the extra arguments are concatenated to the returned
* string, separated by spaces:
*
* ```js
* util.format('%s:%s', 'foo', 'bar', 'baz');
* // Returns: 'foo:bar baz'
* ```
*
* If the first argument does not contain a valid format specifier, `util.format()`returns a string that is the concatenation of all arguments separated by spaces:
*
* ```js
* util.format(1, 2, 3);
* // Returns: '1 2 3'
* ```
*
* If only one argument is passed to `util.format()`, it is returned as it is
* without any formatting:
*
* ```js
* util.format('%% %s');
* // Returns: '%% %s'
* ```
*
* `util.format()` is a synchronous method that is intended as a debugging tool.
* Some input values can have a significant performance overhead that can block the
* event loop. Use this function with care and never in a hot code path.
* @since v0.5.3
* @param format A `printf`-like format string.
*/
export function format(format?: any, ...param: any[]): string;
/**
* This function is identical to {@link format}, except in that it takes
* an `inspectOptions` argument which specifies options that are passed along to {@link inspect}.
*
* ```js
* util.formatWithOptions({ colors: true }, 'See object %O', { foo: 42 });
* // Returns 'See object { foo: 42 }', where `42` is colored as a number
* // when printed to a terminal.
* ```
* @since v10.0.0
*/
export function formatWithOptions(inspectOptions: InspectOptions, format?: any, ...param: any[]): string;
/**
* The `util.inspect()` method returns a string representation of `object` that is
* intended for debugging. The output of `util.inspect` may change at any time
* and should not be depended upon programmatically. Additional `options` may be
* passed that alter the result.`util.inspect()` will use the constructor's name and/or `@@toStringTag` to make
* an identifiable tag for an inspected value.
*
* ```js
* class Foo {
* get [Symbol.toStringTag]() {
* return 'bar';
* }
* }
*
* class Bar {}
*
* const baz = Object.create(null, { [Symbol.toStringTag]: { value: 'foo' } });
*
* util.inspect(new Foo()); // 'Foo [bar] {}'
* util.inspect(new Bar()); // 'Bar {}'
* util.inspect(baz); // '[foo] {}'
* ```
*
* Circular references point to their anchor by using a reference index:
*
* ```js
* const { inspect } = require('util');
*
* const obj = {};
* obj.a = [obj];
* obj.b = {};
* obj.b.inner = obj.b;
* obj.b.obj = obj;
*
* console.log(inspect(obj));
* // <ref *1> {
* // a: [ [Circular *1] ],
* // b: <ref *2> { inner: [Circular *2], obj: [Circular *1] }
* // }
* ```
*
* The following example inspects all properties of the `util` object:
*
* ```js
* const util = require('util');
*
* console.log(util.inspect(util, { showHidden: true, depth: null }));
* ```
*
* The following example highlights the effect of the `compact` option:
*
* ```js
* const util = require('util');
*
* const o = {
* a: [1, 2, [[
* 'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit, sed do ' +
* 'eiusmod \ntempor incididunt ut labore et dolore magna aliqua.',
* 'test',
* 'foo']], 4],
* b: new Map([['za', 1], ['zb', 'test']])
* };
* console.log(util.inspect(o, { compact: true, depth: 5, breakLength: 80 }));
*
* // { a:
* // [ 1,
* // 2,
* // [ [ 'Lorem ipsum dolor sit amet,\nconsectetur [...]', // A long line
* // 'test',
* // 'foo' ] ],
* // 4 ],
* // b: Map(2) { 'za' => 1, 'zb' => 'test' } }
*
* // Setting `compact` to false or an integer creates more reader friendly output.
* console.log(util.inspect(o, { compact: false, depth: 5, breakLength: 80 }));
*
* // {
* // a: [
* // 1,
* // 2,
* // [
* // [
* // 'Lorem ipsum dolor sit amet,\n' +
* // 'consectetur adipiscing elit, sed do eiusmod \n' +
* // 'tempor incididunt ut labore et dolore magna aliqua.',
* // 'test',
* // 'foo'
* // ]
* // ],
* // 4
* // ],
* // b: Map(2) {
* // 'za' => 1,
* // 'zb' => 'test'
* // }
* // }
*
* // Setting `breakLength` to e.g. 150 will print the "Lorem ipsum" text in a
* // single line.
* ```
*
* The `showHidden` option allows [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) and
* [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) entries to be
* inspected. If there are more entries than `maxArrayLength`, there is no
* guarantee which entries are displayed. That means retrieving the same [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) entries twice may
* result in different output. Furthermore, entries
* with no remaining strong references may be garbage collected at any time.
*
* ```js
* const { inspect } = require('util');
*
* const obj = { a: 1 };
* const obj2 = { b: 2 };
* const weakSet = new WeakSet([obj, obj2]);
*
* console.log(inspect(weakSet, { showHidden: true }));
* // WeakSet { { a: 1 }, { b: 2 } }
* ```
*
* The `sorted` option ensures that an object's property insertion order does not
* impact the result of `util.inspect()`.
*
* ```js
* const { inspect } = require('util');
* const assert = require('assert');
*
* const o1 = {
* b: [2, 3, 1],
* a: '`a` comes before `b`',
* c: new Set([2, 3, 1])
* };
* console.log(inspect(o1, { sorted: true }));
* // { a: '`a` comes before `b`', b: [ 2, 3, 1 ], c: Set(3) { 1, 2, 3 } }
* console.log(inspect(o1, { sorted: (a, b) => b.localeCompare(a) }));
* // { c: Set(3) { 3, 2, 1 }, b: [ 2, 3, 1 ], a: '`a` comes before `b`' }
*
* const o2 = {
* c: new Set([2, 1, 3]),
* a: '`a` comes before `b`',
* b: [2, 3, 1]
* };
* assert.strict.equal(
* inspect(o1, { sorted: true }),
* inspect(o2, { sorted: true })
* );
* ```
*
* `util.inspect()` is a synchronous method intended for debugging. Its maximum
* output length is approximately 128 MB. Inputs that result in longer output will
* be truncated.
* @since v0.3.0
* @param object Any JavaScript primitive or `Object`.
* @return The representation of `object`.
*/
export function inspect(object: any, showHidden?: boolean, depth?: number | null, color?: boolean): string;
export function inspect(object: any, options?: InspectOptions): string;
export namespace inspect {
let colors: { [key: number]: number };
let styles: {
[K in Style]: string;
};
let defaultOptions: InspectOptions;
/**
* Allows changing inspect settings from the repl.
*/
let replDefaults: InspectOptions;
/**
* That can be used to declare custom inspect functions.
*/
const custom: unique symbol;
}
/**
* Returns `str` with any ANSI escape codes removed.
*
* ```js
* console.log(util.stripVTControlCharacters('\u001B[4mvalue\u001B[0m'));
* // Prints "value"
* ```
* @since v16.11.0
*/
export function stripVTControlCharacters(str: string): string;
/**
* Colorize `text` with ANSI escapes according to the styleType. Mostly used in inspect() options.
*
* ```typescript
* inspect({ a: 'b' }, { stylize: stylizeWithColor });
* ```
*/
export function stylizeWithColor(text: string, styleType: Style): string;
/**
* Colorize `text` using HTML span tags and style. Mostly used in inspect() options.
*
* ```typescript
* inspect({ a: 'b' }, { stylize: stylizeWithHTML });
* ```
*/
export function stylizeWithHTML(text: string, styleType: Style): string;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,9 @@
const { ttySetMode, isatty, getWindowSize: _getWindowSize } = $lazy("tty");
// primordials
const StringPrototypeSplit = Function.prototype.call.bind(String.prototype.split);
const NumberIsInteger = Number.isInteger;
function ReadStream(fd) {
if (!(this instanceof ReadStream)) return new ReadStream(fd);
if (fd >> 0 !== fd || fd < 0) throw new RangeError("fd must be a positive integer");
@@ -284,7 +288,7 @@ Object.defineProperty(WriteStream, "prototype", {
var validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {
if (typeof value !== "number") throw new ERR_INVALID_ARG_TYPE(name, "number", value);
if (!Number.isInteger(value)) throw new ERR_OUT_OF_RANGE(name, "an integer", value);
if (!NumberIsInteger(value)) throw new ERR_OUT_OF_RANGE(name, "an integer", value);
if (value < min || value > max) throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);
};

View File

@@ -1,20 +1,13 @@
// Hardcoded module "node:util"
const types = require("node:util/types");
/** @type {import('node-inspect-extracted')} */
const utl = require("internal/util/inspect");
var cjs_exports = {};
function isBufferInterface({ copy, fill, readUint8 }) {
return typeof copy === "function" && typeof fill === "function" && typeof readUint8 === "function";
}
function isBuffer(value) {
return (
Buffer.isBuffer(value) ||
// incase it ends up as a browserify buffer
(typeof value === "object" && isBufferInterface(value || {}))
);
return Buffer.isBuffer(value);
}
function isFunction(value) {
return typeof value === "function";
}
@@ -22,55 +15,11 @@ function isFunction(value) {
const deepEquals = Bun.deepEquals;
const isDeepStrictEqual = (a, b) => deepEquals(a, b, true);
var getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors;
var formatRegExp = /%[sdjfoc%]/g;
// This function is nowhere near what Node.js does but it is close enough of a shim.
function formatWithOptions(inspectOptions, f) {
if (!isString(f)) {
var objects = [];
for (var i = 1; i < arguments.length; i++) {
objects.push(inspect(arguments[i], inspectOptions));
}
return objects.join(" ");
}
var i = 2;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function (x2) {
if (x2 === "%%") return "%";
if (i >= len) return x2;
switch (x2) {
case "%s":
return String(args[i++]);
case "%f":
return Number(args[i++]);
case "%d":
return Math.round(Number(args[i++]));
case "%j":
try {
return JSON.stringify(args[i++]);
} catch (_) {
return "[Circular]";
}
case "%o":
return inspect(args[i++], { showHidden: true, showProxy: true, ...inspectOptions });
case "%O":
return inspect(args[i++], { showHidden: true, showProxy: true, ...inspectOptions });
default:
return x2;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += " " + x;
} else {
str += " " + inspect(x, inspectOptions);
}
}
return str;
}
function format(...args) {
return formatWithOptions({}, ...args);
}
const inspect = utl.inspect;
const formatWithOptions = utl.formatWithOptions;
const format = utl.format;
const stripVTControlCharacters = utl.stripVTControlCharacters;
function deprecate(fn, msg, code) {
if (process.noDeprecation === true) {
@@ -123,277 +72,6 @@ function debuglog(set) {
}
return debugs[set];
}
var kInspectCustom = Symbol.for("nodejs.util.inspect.custom");
function inspect(obj, opts) {
var ctx = {
seen: [],
stylize: stylizeNoColor,
};
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
ctx.showHidden = opts;
} else if (opts) {
_extend(ctx, opts);
}
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
inspect.colors = {
bold: [1, 22],
italic: [3, 23],
underline: [4, 24],
inverse: [7, 27],
white: [37, 39],
grey: [90, 39],
black: [30, 39],
blue: [34, 39],
cyan: [36, 39],
green: [32, 39],
magenta: [35, 39],
red: [31, 39],
yellow: [33, 39],
};
inspect.styles = {
special: "cyan",
number: "yellow",
boolean: "yellow",
undefined: "grey",
null: "bold",
string: "green",
date: "magenta",
regexp: "red",
};
inspect.custom = kInspectCustom;
// JS polyfill doesnt support all these options
inspect.defaultOptions = {
showHidden: false,
depth: 2,
colors: false,
customInspect: true,
showProxy: false,
maxArrayLength: 100,
maxStringLength: 10000,
breakLength: 80,
compact: 3,
sorted: false,
getters: false,
numericSeparator: false,
};
function stylizeWithColor(str, styleType) {
const style = inspect.styles[styleType];
if (style !== undefined) {
const color = inspect.colors[style];
if (color !== undefined) return `\u001b[${color[0]}m${str}\u001b[${color[1]}m`;
}
return str;
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function (val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
if (ctx.customInspect && value) {
const customInspect = value[kInspectCustom];
if (isFunction(customInspect)) {
var ret = customInspect.call(value, recurseTimes, ctx, inspect);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
}
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
var keys = Object.keys(value).concat(Object.getOwnPropertySymbols(value));
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
if (isError(value) && (keys.indexOf("message") >= 0 || keys.indexOf("description") >= 0)) {
return formatError(value);
}
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ": " + value.name : "";
return ctx.stylize("[Function" + name + "]", "special");
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), "date");
}
if (isError(value)) {
return formatError(value);
}
}
var base = "",
array = false,
braces = ["{", "}"];
if ($isArray(value)) {
array = true;
braces = ["[", "]"];
}
if (isFunction(value)) {
var n = value.name ? ": " + value.name : "";
base = " [Function" + n + "]";
}
if (isRegExp(value)) {
base = " " + RegExp.prototype.toString.call(value);
}
if (isDate(value)) {
base = " " + Date.prototype.toUTCString.call(value);
}
if (isError(value)) {
base = " " + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), "regexp");
} else {
return ctx.stylize("[Object]", "special");
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function (key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value)) return ctx.stylize("undefined", "undefined");
if (isString(value)) {
var simple = "'" + JSON.stringify(value).replace(/^"|"$/g, "").replace(/'/g, "\\'").replace(/\\"/g, '"') + "'";
return ctx.stylize(simple, "string");
}
if (isNumber(value)) return ctx.stylize("" + value, "number");
if (isBoolean(value)) return ctx.stylize("" + value, "boolean");
if (isNull(value)) return ctx.stylize("null", "null");
}
function formatError(value) {
return "[" + Error.prototype.toString.call(value) + "]";
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, String(i), true));
} else {
output.push("");
}
}
keys.forEach(function (key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || {
value: value[key],
};
if (desc.get) {
if (desc.set) {
str = ctx.stylize("[Getter/Setter]", "special");
} else {
str = ctx.stylize("[Getter]", "special");
}
} else {
if (desc.set) {
str = ctx.stylize("[Setter]", "special");
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = "[" + (typeof key === "symbol" ? key.description : key) + "]";
}
if (typeof key === "symbol") {
name = "[" + ctx.stylize(`Symbol(${key.description})`, "string") + "]";
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf("\n") > -1) {
if (array) {
str = str
.split("\n")
.map(function (line) {
return " " + line;
})
.join("\n")
.substr(2);
} else {
str =
"\n" +
str
.split("\n")
.map(function (line) {
return " " + line;
})
.join("\n");
}
}
} else {
str = ctx.stylize("[Circular]", "special");
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify("" + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, "name");
} else {
name = name
.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, "string");
}
}
return name + ": " + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function (prev, cur) {
numLinesEst++;
if (cur.indexOf("\n") >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, "").length + 1;
}, 0);
if (length > 60) {
return braces[0] + (base === "" ? "" : base + "\n ") + " " + output.join(",\n ") + " " + braces[1];
}
return braces[0] + base + " " + output.join(", ") + " " + braces[1];
}
function isBoolean(arg) {
return typeof arg === "boolean";
@@ -469,9 +147,7 @@ var _extend = function (origin, add) {
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
var kCustomPromisifiedSymbol = Symbol.for("util.promisify.custom");
var promisify = function promisify(original) {
if (typeof original !== "function") throw new TypeError('The "original" argument must be of type Function');
@@ -566,6 +242,7 @@ var toUSVString = input => {
export default Object.assign(cjs_exports, {
format,
formatWithOptions,
stripVTControlCharacters,
deprecate,
debuglog,
_extend,

View File

@@ -18,9 +18,15 @@ JSValue InternalModuleRegistry::createInternalModuleById(JSGlobalObject* globalO
case Field::InternalFSCp: {
INTERNAL_MODULE_REGISTRY_GENERATE(globalObject, vm, "internal:fs/cp"_s, "internal/fs/cp.js"_s, InternalModuleRegistryConstants::InternalFSCpCode, "builtin://internal/fs/cp"_s);
}
case Field::InternalPrimordials: {
INTERNAL_MODULE_REGISTRY_GENERATE(globalObject, vm, "internal:primordials"_s, "internal/primordials.js"_s, InternalModuleRegistryConstants::InternalPrimordialsCode, "builtin://internal/primordials"_s);
}
case Field::InternalShared: {
INTERNAL_MODULE_REGISTRY_GENERATE(globalObject, vm, "internal:shared"_s, "internal/shared.js"_s, InternalModuleRegistryConstants::InternalSharedCode, "builtin://internal/shared"_s);
}
case Field::InternalUtilInspect: {
INTERNAL_MODULE_REGISTRY_GENERATE(globalObject, vm, "internal:util/inspect"_s, "internal/util/inspect.js"_s, InternalModuleRegistryConstants::InternalUtilInspectCode, "builtin://internal/util/inspect"_s);
}
case Field::NodeAssert: {
INTERNAL_MODULE_REGISTRY_GENERATE(globalObject, vm, "node:assert"_s, "node/assert.js"_s, InternalModuleRegistryConstants::NodeAssertCode, "builtin://node/assert"_s);
}

View File

@@ -3,59 +3,61 @@ BunSqlite = 1,
InternalDebugger = 2,
InternalFSCpSync = 3,
InternalFSCp = 4,
InternalShared = 5,
NodeAssert = 6,
NodeAssertStrict = 7,
NodeAsyncHooks = 8,
NodeChildProcess = 9,
NodeCluster = 10,
NodeConsole = 11,
NodeCrypto = 12,
NodeDgram = 13,
NodeDiagnosticsChannel = 14,
NodeDNS = 15,
NodeDNSPromises = 16,
NodeDomain = 17,
NodeEvents = 18,
NodeFS = 19,
NodeFSPromises = 20,
NodeHttp = 21,
NodeHttp2 = 22,
NodeHttps = 23,
NodeInspector = 24,
NodeNet = 25,
NodeOS = 26,
NodePathPosix = 27,
NodePath = 28,
NodePathWin32 = 29,
NodePerfHooks = 30,
NodePunycode = 31,
NodeQuerystring = 32,
NodeReadline = 33,
NodeReadlinePromises = 34,
NodeRepl = 35,
NodeStreamConsumers = 36,
NodeStream = 37,
NodeStreamPromises = 38,
NodeStreamWeb = 39,
NodeTimers = 40,
NodeTimersPromises = 41,
NodeTLS = 42,
NodeTraceEvents = 43,
NodeTty = 44,
NodeUrl = 45,
NodeUtil = 46,
NodeV8 = 47,
NodeVM = 48,
NodeWasi = 49,
NodeWorkerThreads = 50,
NodeZlib = 51,
ThirdpartyDepd = 52,
ThirdpartyDetectLibc = 53,
ThirdpartyDetectLibcLinux = 54,
ThirdpartyIsomorphicFetch = 55,
ThirdpartyNodeFetch = 56,
ThirdpartyUndici = 57,
ThirdpartyVercelFetch = 58,
ThirdpartyWS = 59,
InternalPrimordials = 5,
InternalShared = 6,
InternalUtilInspect = 7,
NodeAssert = 8,
NodeAssertStrict = 9,
NodeAsyncHooks = 10,
NodeChildProcess = 11,
NodeCluster = 12,
NodeConsole = 13,
NodeCrypto = 14,
NodeDgram = 15,
NodeDiagnosticsChannel = 16,
NodeDNS = 17,
NodeDNSPromises = 18,
NodeDomain = 19,
NodeEvents = 20,
NodeFS = 21,
NodeFSPromises = 22,
NodeHttp = 23,
NodeHttp2 = 24,
NodeHttps = 25,
NodeInspector = 26,
NodeNet = 27,
NodeOS = 28,
NodePathPosix = 29,
NodePath = 30,
NodePathWin32 = 31,
NodePerfHooks = 32,
NodePunycode = 33,
NodeQuerystring = 34,
NodeReadline = 35,
NodeReadlinePromises = 36,
NodeRepl = 37,
NodeStreamConsumers = 38,
NodeStream = 39,
NodeStreamPromises = 40,
NodeStreamWeb = 41,
NodeTimers = 42,
NodeTimersPromises = 43,
NodeTLS = 44,
NodeTraceEvents = 45,
NodeTty = 46,
NodeUrl = 47,
NodeUtil = 48,
NodeV8 = 49,
NodeVM = 50,
NodeWasi = 51,
NodeWorkerThreads = 52,
NodeZlib = 53,
ThirdpartyDepd = 54,
ThirdpartyDetectLibc = 55,
ThirdpartyDetectLibcLinux = 56,
ThirdpartyIsomorphicFetch = 57,
ThirdpartyNodeFetch = 58,
ThirdpartyUndici = 59,
ThirdpartyVercelFetch = 60,
ThirdpartyWS = 61,

View File

@@ -1 +1 @@
#define BUN_INTERNAL_MODULE_COUNT 60
#define BUN_INTERNAL_MODULE_COUNT 62

File diff suppressed because one or more lines are too long

View File

@@ -15,61 +15,63 @@ pub const ResolvedSourceTag = enum(u32) {
@"internal:debugger" = 514,
@"internal:fs/cp-sync" = 515,
@"internal:fs/cp" = 516,
@"internal:shared" = 517,
@"node:assert" = 518,
@"node:assert/strict" = 519,
@"node:async_hooks" = 520,
@"node:child_process" = 521,
@"node:cluster" = 522,
@"node:console" = 523,
@"node:crypto" = 524,
@"node:dgram" = 525,
@"node:diagnostics_channel" = 526,
@"node:dns" = 527,
@"node:dns/promises" = 528,
@"node:domain" = 529,
@"node:events" = 530,
@"node:fs" = 531,
@"node:fs/promises" = 532,
@"node:http" = 533,
@"node:http2" = 534,
@"node:https" = 535,
@"node:inspector" = 536,
@"node:net" = 537,
@"node:os" = 538,
@"node:path/posix" = 539,
@"node:path" = 540,
@"node:path/win32" = 541,
@"node:perf_hooks" = 542,
@"node:punycode" = 543,
@"node:querystring" = 544,
@"node:readline" = 545,
@"node:readline/promises" = 546,
@"node:repl" = 547,
@"node:stream/consumers" = 548,
@"node:stream" = 549,
@"node:stream/promises" = 550,
@"node:stream/web" = 551,
@"node:timers" = 552,
@"node:timers/promises" = 553,
@"node:tls" = 554,
@"node:trace_events" = 555,
@"node:tty" = 556,
@"node:url" = 557,
@"node:util" = 558,
@"node:v8" = 559,
@"node:vm" = 560,
@"node:wasi" = 561,
@"node:worker_threads" = 562,
@"node:zlib" = 563,
@"depd" = 564,
@"detect-libc" = 565,
@"detect-libc/linux" = 566,
@"isomorphic-fetch" = 567,
@"node-fetch" = 568,
@"undici" = 569,
@"vercel_fetch" = 570,
@"ws" = 571,
@"internal:primordials" = 517,
@"internal:shared" = 518,
@"internal:util/inspect" = 519,
@"node:assert" = 520,
@"node:assert/strict" = 521,
@"node:async_hooks" = 522,
@"node:child_process" = 523,
@"node:cluster" = 524,
@"node:console" = 525,
@"node:crypto" = 526,
@"node:dgram" = 527,
@"node:diagnostics_channel" = 528,
@"node:dns" = 529,
@"node:dns/promises" = 530,
@"node:domain" = 531,
@"node:events" = 532,
@"node:fs" = 533,
@"node:fs/promises" = 534,
@"node:http" = 535,
@"node:http2" = 536,
@"node:https" = 537,
@"node:inspector" = 538,
@"node:net" = 539,
@"node:os" = 540,
@"node:path/posix" = 541,
@"node:path" = 542,
@"node:path/win32" = 543,
@"node:perf_hooks" = 544,
@"node:punycode" = 545,
@"node:querystring" = 546,
@"node:readline" = 547,
@"node:readline/promises" = 548,
@"node:repl" = 549,
@"node:stream/consumers" = 550,
@"node:stream" = 551,
@"node:stream/promises" = 552,
@"node:stream/web" = 553,
@"node:timers" = 554,
@"node:timers/promises" = 555,
@"node:tls" = 556,
@"node:trace_events" = 557,
@"node:tty" = 558,
@"node:url" = 559,
@"node:util" = 560,
@"node:v8" = 561,
@"node:vm" = 562,
@"node:wasi" = 563,
@"node:worker_threads" = 564,
@"node:zlib" = 565,
@"depd" = 566,
@"detect-libc" = 567,
@"detect-libc/linux" = 568,
@"isomorphic-fetch" = 569,
@"node-fetch" = 570,
@"undici" = 571,
@"vercel_fetch" = 572,
@"ws" = 573,
// Native modules run through a different system using ESM registry.
@"bun" = 1024,
@"bun:jsc" = 1025,

View File

@@ -15,61 +15,63 @@ enum SyntheticModuleType : uint32_t {
InternalDebugger = 514,
InternalFSCpSync = 515,
InternalFSCp = 516,
InternalShared = 517,
NodeAssert = 518,
NodeAssertStrict = 519,
NodeAsyncHooks = 520,
NodeChildProcess = 521,
NodeCluster = 522,
NodeConsole = 523,
NodeCrypto = 524,
NodeDgram = 525,
NodeDiagnosticsChannel = 526,
NodeDNS = 527,
NodeDNSPromises = 528,
NodeDomain = 529,
NodeEvents = 530,
NodeFS = 531,
NodeFSPromises = 532,
NodeHttp = 533,
NodeHttp2 = 534,
NodeHttps = 535,
NodeInspector = 536,
NodeNet = 537,
NodeOS = 538,
NodePathPosix = 539,
NodePath = 540,
NodePathWin32 = 541,
NodePerfHooks = 542,
NodePunycode = 543,
NodeQuerystring = 544,
NodeReadline = 545,
NodeReadlinePromises = 546,
NodeRepl = 547,
NodeStreamConsumers = 548,
NodeStream = 549,
NodeStreamPromises = 550,
NodeStreamWeb = 551,
NodeTimers = 552,
NodeTimersPromises = 553,
NodeTLS = 554,
NodeTraceEvents = 555,
NodeTty = 556,
NodeUrl = 557,
NodeUtil = 558,
NodeV8 = 559,
NodeVM = 560,
NodeWasi = 561,
NodeWorkerThreads = 562,
NodeZlib = 563,
ThirdpartyDepd = 564,
ThirdpartyDetectLibc = 565,
ThirdpartyDetectLibcLinux = 566,
ThirdpartyIsomorphicFetch = 567,
ThirdpartyNodeFetch = 568,
ThirdpartyUndici = 569,
ThirdpartyVercelFetch = 570,
ThirdpartyWS = 571,
InternalPrimordials = 517,
InternalShared = 518,
InternalUtilInspect = 519,
NodeAssert = 520,
NodeAssertStrict = 521,
NodeAsyncHooks = 522,
NodeChildProcess = 523,
NodeCluster = 524,
NodeConsole = 525,
NodeCrypto = 526,
NodeDgram = 527,
NodeDiagnosticsChannel = 528,
NodeDNS = 529,
NodeDNSPromises = 530,
NodeDomain = 531,
NodeEvents = 532,
NodeFS = 533,
NodeFSPromises = 534,
NodeHttp = 535,
NodeHttp2 = 536,
NodeHttps = 537,
NodeInspector = 538,
NodeNet = 539,
NodeOS = 540,
NodePathPosix = 541,
NodePath = 542,
NodePathWin32 = 543,
NodePerfHooks = 544,
NodePunycode = 545,
NodeQuerystring = 546,
NodeReadline = 547,
NodeReadlinePromises = 548,
NodeRepl = 549,
NodeStreamConsumers = 550,
NodeStream = 551,
NodeStreamPromises = 552,
NodeStreamWeb = 553,
NodeTimers = 554,
NodeTimersPromises = 555,
NodeTLS = 556,
NodeTraceEvents = 557,
NodeTty = 558,
NodeUrl = 559,
NodeUtil = 560,
NodeV8 = 561,
NodeVM = 562,
NodeWasi = 563,
NodeWorkerThreads = 564,
NodeZlib = 565,
ThirdpartyDepd = 566,
ThirdpartyDetectLibc = 567,
ThirdpartyDetectLibcLinux = 568,
ThirdpartyIsomorphicFetch = 569,
ThirdpartyNodeFetch = 570,
ThirdpartyUndici = 571,
ThirdpartyVercelFetch = 572,
ThirdpartyWS = 573,
// Native modules run through the same system, but with different underlying initializers.
// They also have bit 10 set to differentiate them from JS builtins.

File diff suppressed because one or more lines are too long

View File

@@ -2,7 +2,7 @@ import { test, expect } from "bun:test";
import { spawnSync } from "bun";
import { bunEnv, bunExe } from "harness";
test("reportError", () => {
test.skipIf(Bun.version.endsWith("debug"))("reportError", () => {
const cwd = import.meta.dir;
const { stderr } = spawnSync({
cmd: [bunExe(), new URL("./reportError.ts", import.meta.url).pathname],

View File

@@ -0,0 +1,9 @@
import assert from "assert";
import util, { inspect } from "util";
test("no assertion failures", () => {
assert.strictEqual(typeof util.inspect, "function");
assert.strictEqual(util.inspect, inspect);
assert.strictEqual(util.inspect(null), "null");
assert.strictEqual(util.inspect({ a: 1 }, { compact: false }), "{\n a: 1\n}");
});

View File

@@ -0,0 +1,57 @@
import assert from "assert";
import util from "util";
test("no assertion failures", () => {
// Errors in accessors are not triggered
const obj = new Proxy(
{ x: 5 },
{
get() {
throw new Error("Error message");
},
},
);
assert.strictEqual(util.format(obj), "{ x: 5 }");
assert.strictEqual(util.formatWithOptions({ numericSeparator: true }, "%d", 4000), "4_000");
const a = {};
a.b = a;
assert.strictEqual(util.inspect(a, { compact: false }), "<ref *1> {\n b: [Circular *1]\n}");
assert.strictEqual(util.inspect(a, { compact: true }), "<ref *1> { b: [Circular *1] }");
const cause = new Error("cause");
const e2 = new Error("wrapper", { cause });
assert.match(util.inspect(e2), /\[cause\]: Error: cause\n/);
});
//! non-standard property, should this be kept?
test.skip("util.stylizeWithHTML", () => {
assert.strictEqual(
util.inspect(
{
a: 1,
b: "<p>\xA0\u{1F4A9}</p>",
"&lt;": NaN,
[Symbol("<br>")]: false,
buf: new Uint8Array([1, 2, 3, 4]),
},
{
compact: false,
stylize: util.stylizeWithHTML,
},
),
"{\n" +
' a: <span style="color:yellow;">1</span>,\n' +
' b: <span style="color:green;">&apos;&lt;p&gt;&nbsp;\u{1F4A9}&lt;&#47;p&gt;&apos;</span>,\n' +
' <span style="color:green;">&apos;&amp;lt&#59;&apos;</span>: <span style="color:yellow;">NaN</span>,\n' +
" buf: Uint8Array(4) [\n" +
' <span style="color:yellow;">1</span>,\n' +
' <span style="color:yellow;">2</span>,\n' +
' <span style="color:yellow;">3</span>,\n' +
' <span style="color:yellow;">4</span>\n' +
" ],\n" +
' [<span style="color:green;">Symbol&#40;&lt;br&gt;&#41;</span>]: <span style="color:yellow;">false</span>\n' +
"}",
);
});

View File

@@ -0,0 +1,489 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import assert from "assert";
import util from "util";
const symbol = Symbol("foo");
test("no assertion failures", () => {
assert.strictEqual(util.format(), "");
assert.strictEqual(util.format(""), "");
assert.strictEqual(util.format([]), "[]");
assert.strictEqual(util.format([0]), "[ 0 ]");
assert.strictEqual(util.format({}), "{}");
assert.strictEqual(util.format({ foo: 42 }), "{ foo: 42 }");
assert.strictEqual(util.format(null), "null");
assert.strictEqual(util.format(true), "true");
assert.strictEqual(util.format(false), "false");
assert.strictEqual(util.format("test"), "test");
// CHECKME this is for console.log() compatibility - but is it *right*?
assert.strictEqual(util.format("foo", "bar", "baz"), "foo bar baz");
// ES6 Symbol handling
assert.strictEqual(util.format(symbol), "Symbol(foo)");
assert.strictEqual(util.format("foo", symbol), "foo Symbol(foo)");
assert.strictEqual(util.format("%s", symbol), "Symbol(foo)");
assert.strictEqual(util.format("%j", symbol), "undefined");
// Number format specifier
assert.strictEqual(util.format("%d"), "%d");
assert.strictEqual(util.format("%d", 42.0), "42");
assert.strictEqual(util.format("%d", 42), "42");
assert.strictEqual(util.format("%d", "42"), "42");
assert.strictEqual(util.format("%d", "42.0"), "42");
assert.strictEqual(util.format("%d", 1.5), "1.5");
assert.strictEqual(util.format("%d", -0.5), "-0.5");
assert.strictEqual(util.format("%d", -0.0), "-0");
assert.strictEqual(util.format("%d", ""), "0");
assert.strictEqual(util.format("%d", " -0.000"), "-0");
assert.strictEqual(util.format("%d", Symbol()), "NaN");
assert.strictEqual(util.format("%d", Infinity), "Infinity");
assert.strictEqual(util.format("%d", -Infinity), "-Infinity");
assert.strictEqual(util.format("%d %d", 42, 43), "42 43");
assert.strictEqual(util.format("%d %d", 42), "42 %d");
assert.strictEqual(util.format("%d", 1180591620717411303424), "1.1805916207174113e+21");
assert.strictEqual(util.format("%d", 1180591620717411303424n), "1180591620717411303424n");
assert.strictEqual(
util.format("%d %d", 1180591620717411303424n, 12345678901234567890123n),
"1180591620717411303424n 12345678901234567890123n",
);
{
const { numericSeparator } = util.inspect.defaultOptions;
util.inspect.defaultOptions.numericSeparator = true;
assert.strictEqual(util.format("%d", 1180591620717411303424), "1.1805916207174113e+21");
assert.strictEqual(
util.format("%d %s %i", 118059162071741130342, 118059162071741130342, 123_123_123),
"118_059_162_071_741_140_000 118_059_162_071_741_140_000 123_123_123",
);
assert.strictEqual(
util.format("%d %s", 1_180_591_620_717_411_303_424n, 12_345_678_901_234_567_890_123n),
"1_180_591_620_717_411_303_424n 12_345_678_901_234_567_890_123n",
);
assert.strictEqual(util.format("%i", 1_180_591_620_717_411_303_424n), "1_180_591_620_717_411_303_424n");
util.inspect.defaultOptions.numericSeparator = numericSeparator;
}
// Integer format specifier
assert.strictEqual(util.format("%i"), "%i");
assert.strictEqual(util.format("%i", 42.0), "42");
assert.strictEqual(util.format("%i", 42), "42");
assert.strictEqual(util.format("%i", "42"), "42");
assert.strictEqual(util.format("%i", "42.0"), "42");
assert.strictEqual(util.format("%i", 1.5), "1");
assert.strictEqual(util.format("%i", -0.5), "-0");
assert.strictEqual(util.format("%i", ""), "NaN");
assert.strictEqual(util.format("%i", Infinity), "NaN");
assert.strictEqual(util.format("%i", -Infinity), "NaN");
assert.strictEqual(util.format("%i", Symbol()), "NaN");
assert.strictEqual(util.format("%i %i", 42, 43), "42 43");
assert.strictEqual(util.format("%i %i", 42), "42 %i");
assert.strictEqual(util.format("%i", 1180591620717411303424), "1");
assert.strictEqual(util.format("%i", 1180591620717411303424n), "1180591620717411303424n");
assert.strictEqual(
util.format("%i %i", 1180591620717411303424n, 12345678901234567890123n),
"1180591620717411303424n 12345678901234567890123n",
);
assert.strictEqual(
util.format("%d %i", 1180591620717411303424n, 12345678901234567890123n),
"1180591620717411303424n 12345678901234567890123n",
);
assert.strictEqual(
util.format("%i %d", 1180591620717411303424n, 12345678901234567890123n),
"1180591620717411303424n 12345678901234567890123n",
);
assert.strictEqual(
util.formatWithOptions({ numericSeparator: true }, "%i %d", 1180591620717411303424n, 12345678901234567890123n),
"1_180_591_620_717_411_303_424n 12_345_678_901_234_567_890_123n",
);
// Float format specifier
assert.strictEqual(util.format("%f"), "%f");
assert.strictEqual(util.format("%f", 42.0), "42");
assert.strictEqual(util.format("%f", 42), "42");
assert.strictEqual(util.format("%f", "42"), "42");
assert.strictEqual(util.format("%f", "-0.0"), "-0");
assert.strictEqual(util.format("%f", "42.0"), "42");
assert.strictEqual(util.format("%f", 1.5), "1.5");
assert.strictEqual(util.format("%f", -0.5), "-0.5");
assert.strictEqual(util.format("%f", Math.PI), "3.141592653589793");
assert.strictEqual(util.format("%f", ""), "NaN");
assert.strictEqual(util.format("%f", Symbol("foo")), "NaN");
assert.strictEqual(util.format("%f", 5n), "5");
assert.strictEqual(util.format("%f", Infinity), "Infinity");
assert.strictEqual(util.format("%f", -Infinity), "-Infinity");
assert.strictEqual(util.format("%f %f", 42, 43), "42 43");
assert.strictEqual(util.format("%f %f", 42), "42 %f");
// String format specifier
assert.strictEqual(util.format("%s"), "%s");
assert.strictEqual(util.format("%s", undefined), "undefined");
assert.strictEqual(util.format("%s", null), "null");
assert.strictEqual(util.format("%s", "foo"), "foo");
assert.strictEqual(util.format("%s", 42), "42");
assert.strictEqual(util.format("%s", "42"), "42");
assert.strictEqual(util.format("%s", -0), "-0");
assert.strictEqual(util.format("%s", "-0.0"), "-0.0");
assert.strictEqual(util.format("%s %s", 42, 43), "42 43");
assert.strictEqual(util.format("%s %s", 42), "42 %s");
assert.strictEqual(util.format("%s", 42n), "42n");
assert.strictEqual(util.format("%s", Symbol("foo")), "Symbol(foo)");
assert.strictEqual(util.format("%s", true), "true");
assert.strictEqual(util.format("%s", { a: [1, 2, 3] }), "{ a: [Array] }");
assert.strictEqual(
util.format("%s", {
toString() {
return "Foo";
},
}),
"Foo",
);
assert.strictEqual(util.format("%s", { toString: 5 }), "{ toString: 5 }");
assert.strictEqual(
util.format("%s", () => 5),
"() => 5",
);
assert.strictEqual(util.format("%s", Infinity), "Infinity");
assert.strictEqual(util.format("%s", -Infinity), "-Infinity");
// String format specifier including `toString` properties on the prototype.
{
class Foo {
toString() {
return "Bar";
}
}
assert.strictEqual(util.format("%s", new Foo()), "Bar");
// TODO: null prototypes
// assert.strictEqual(
// util.format('%s', Object.setPrototypeOf(new Foo(), null)),
// '[Foo: null prototype] {}'
// );
global.Foo = Foo;
assert.strictEqual(util.format("%s", new Foo()), "Bar");
delete global.Foo;
class Bar {
abc = true;
}
assert.strictEqual(util.format("%s", new Bar()), "Bar { abc: true }");
class Foobar extends Array {
aaa = true;
}
assert.strictEqual(util.format("%s", new Foobar(5)), "Foobar(5) [ <5 empty items>, aaa: true ]");
// Subclassing:
class B extends Foo {}
function C() {}
C.prototype.toString = function () {
return "Custom";
};
function D() {
C.call(this);
}
D.prototype = { __proto__: C.prototype };
assert.strictEqual(util.format("%s", new B()), "Bar");
assert.strictEqual(util.format("%s", new C()), "Custom");
assert.strictEqual(util.format("%s", new D()), "Custom");
D.prototype.constructor = D;
assert.strictEqual(util.format("%s", new D()), "Custom");
D.prototype.constructor = null;
assert.strictEqual(util.format("%s", new D()), "Custom");
D.prototype.constructor = { name: "Foobar" };
assert.strictEqual(util.format("%s", new D()), "Custom");
Object.defineProperty(D.prototype, "constructor", {
get() {
throw new Error();
},
configurable: true,
});
assert.strictEqual(util.format("%s", new D()), "Custom");
assert.strictEqual(util.format("%s", { __proto__: null }), "[Object: null prototype] {}");
}
// JSON format specifier
assert.strictEqual(util.format("%j"), "%j");
assert.strictEqual(util.format("%j", 42), "42");
assert.strictEqual(util.format("%j", "42"), '"42"');
assert.strictEqual(util.format("%j %j", 42, 43), "42 43");
assert.strictEqual(util.format("%j %j", 42), "42 %j");
// Object format specifier
const obj = {
foo: "bar",
foobar: 1,
func: function () {},
};
const nestedObj = {
foo: "bar",
foobar: {
foo: "bar",
func: function () {},
},
};
const nestedObj2 = {
foo: "bar",
foobar: 1,
func: [{ a: function () {} }],
};
assert.strictEqual(util.format("%o"), "%o");
assert.strictEqual(util.format("%o", 42), "42");
assert.strictEqual(util.format("%o", "foo"), "'foo'");
assert.strictEqual(
util.format("%o", obj),
"{\n" +
" foo: 'bar',\n" +
" foobar: 1,\n" +
" func: <ref *1> [Function: func] {\n" +
" [length]: 0,\n" +
" [name]: 'func',\n" +
" [prototype]: { [constructor]: [Circular *1] }\n" +
" }\n" +
"}",
);
assert.strictEqual(
util.format("%o", nestedObj2),
"{\n" +
" foo: 'bar',\n" +
" foobar: 1,\n" +
" func: [\n" +
" {\n" +
" a: <ref *1> [Function: a] {\n" +
" [length]: 0,\n" +
" [name]: 'a',\n" +
" [prototype]: { [constructor]: [Circular *1] }\n" +
" }\n" +
" },\n" +
" [length]: 1\n" +
" ]\n" +
"}",
);
assert.strictEqual(
util.format("%o", nestedObj),
"{\n" +
" foo: 'bar',\n" +
" foobar: {\n" +
" foo: 'bar',\n" +
" func: <ref *1> [Function: func] {\n" +
" [length]: 0,\n" +
" [name]: 'func',\n" +
" [prototype]: { [constructor]: [Circular *1] }\n" +
" }\n" +
" }\n" +
"}",
);
assert.strictEqual(
util.format("%o %o", obj, obj),
"{\n" +
" foo: 'bar',\n" +
" foobar: 1,\n" +
" func: <ref *1> [Function: func] {\n" +
" [prototype]: { [constructor]: [Circular *1] },\n" +
" [name]: 'func',\n" +
" [length]: 0\n" +
" }\n" +
"} {\n" +
" foo: 'bar',\n" +
" foobar: 1,\n" +
" func: <ref *1> [Function: func] {\n" +
" [prototype]: { [constructor]: [Circular *1] },\n" +
" [name]: 'func',\n" +
" [length]: 0\n" +
" }\n" +
"}",
);
assert.strictEqual(
util.format("%o %o", obj),
"{\n" +
" foo: 'bar',\n" +
" foobar: 1,\n" +
" func: <ref *1> [Function: func] {\n" +
" [prototype]: { [constructor]: [Circular *1] },\n" +
" [name]: 'func',\n" +
" [length]: 0\n" +
" }\n" +
"} %o",
);
assert.strictEqual(util.format("%O"), "%O");
assert.strictEqual(util.format("%O", 42), "42");
assert.strictEqual(util.format("%O", "foo"), "'foo'");
assert.strictEqual(util.format("%O", obj), "{ foo: 'bar', foobar: 1, func: [Function: func] }");
assert.strictEqual(util.format("%O", nestedObj), "{ foo: 'bar', foobar: { foo: 'bar', func: [Function: func] } }");
assert.strictEqual(
util.format("%O %O", obj, obj),
"{ foo: 'bar', foobar: 1, func: [Function: func] } " + "{ foo: 'bar', foobar: 1, func: [Function: func] }",
);
assert.strictEqual(util.format("%O %O", obj), "{ foo: 'bar', foobar: 1, func: [Function: func] } %O");
// Various format specifiers
assert.strictEqual(util.format("%%s%s", "foo"), "%sfoo");
assert.strictEqual(util.format("%s:%s"), "%s:%s");
assert.strictEqual(util.format("%s:%s", undefined), "undefined:%s");
assert.strictEqual(util.format("%s:%s", "foo"), "foo:%s");
assert.strictEqual(util.format("%s:%i", "foo"), "foo:%i");
assert.strictEqual(util.format("%s:%f", "foo"), "foo:%f");
assert.strictEqual(util.format("%s:%s", "foo", "bar"), "foo:bar");
assert.strictEqual(util.format("%s:%s", "foo", "bar", "baz"), "foo:bar baz");
assert.strictEqual(util.format("%%%s%%", "hi"), "%hi%");
assert.strictEqual(util.format("%%%s%%%%", "hi"), "%hi%%");
assert.strictEqual(util.format("%sbc%%def", "a"), "abc%def");
assert.strictEqual(util.format("%d:%d", 12, 30), "12:30");
assert.strictEqual(util.format("%d:%d", 12), "12:%d");
assert.strictEqual(util.format("%d:%d"), "%d:%d");
assert.strictEqual(util.format("%i:%i", 12, 30), "12:30");
assert.strictEqual(util.format("%i:%i", 12), "12:%i");
assert.strictEqual(util.format("%i:%i"), "%i:%i");
assert.strictEqual(util.format("%f:%f", 12, 30), "12:30");
assert.strictEqual(util.format("%f:%f", 12), "12:%f");
assert.strictEqual(util.format("%f:%f"), "%f:%f");
assert.strictEqual(util.format("o: %j, a: %j", {}, []), "o: {}, a: []");
assert.strictEqual(util.format("o: %j, a: %j", {}), "o: {}, a: %j");
assert.strictEqual(util.format("o: %j, a: %j"), "o: %j, a: %j");
assert.strictEqual(util.format("o: %o, a: %O", {}, []), "o: {}, a: []");
assert.strictEqual(util.format("o: %o, a: %o", {}), "o: {}, a: %o");
assert.strictEqual(util.format("o: %O, a: %O"), "o: %O, a: %O");
// Invalid format specifiers
assert.strictEqual(util.format("a% b", "x"), "a% b x");
assert.strictEqual(util.format("percent: %d%, fraction: %d", 10, 0.1), "percent: 10%, fraction: 0.1");
assert.strictEqual(util.format("abc%", 1), "abc% 1");
// Additional arguments after format specifiers
assert.strictEqual(util.format("%i", 1, "number"), "1 number");
assert.strictEqual(
util.format("%i", 1, () => {}),
"1 [Function (anonymous)]",
);
// %c from https://console.spec.whatwg.org/
assert.strictEqual(util.format("%c"), "%c");
assert.strictEqual(util.format("%cab"), "%cab");
assert.strictEqual(util.format("%cab", "color: blue"), "ab");
assert.strictEqual(util.format("%cab", "color: blue", "c"), "ab c");
{
const o = {};
o.o = o;
assert.strictEqual(util.format("%j", o), "[Circular]");
}
{
const o = {
toJSON() {
throw new Error("Not a circular object but still not serializable");
},
};
assert.throws(() => util.format("%j", o), /^Error: Not a circular object but still not serializable$/);
}
// Errors
const err = new Error("foo");
assert(util.format(err).startsWith(err.stack), `Expected "${util.format(err)}" to start with "${err.stack}"`);
class CustomError extends Error {
constructor(msg) {
super();
Object.defineProperty(this, "message", { value: msg, enumerable: false });
Object.defineProperty(this, "name", { value: "CustomError", enumerable: false });
Error.captureStackTrace(this, CustomError);
}
}
const customError = new CustomError("bar");
assert.strictEqual(util.format(customError), customError.stack.replace(/^Error/, "Custom$&")); //! temp bug workaround
// Doesn't capture stack trace
function BadCustomError(msg) {
Error.call(this);
Object.defineProperty(this, "message", { value: msg, enumerable: false });
Object.defineProperty(this, "name", { value: "BadCustomError", enumerable: false });
}
Object.setPrototypeOf(BadCustomError.prototype, Error.prototype);
Object.setPrototypeOf(BadCustomError, Error);
assert.strictEqual(util.format(new BadCustomError("foo")), "[BadCustomError: foo]");
// The format of arguments should not depend on type of the first argument
assert.strictEqual(util.format("1", "1"), "1 1");
assert.strictEqual(util.format(1, "1"), "1 1");
assert.strictEqual(util.format("1", 1), "1 1");
assert.strictEqual(util.format(1, -0), "1 -0");
assert.strictEqual(
util.format("1", () => {}),
"1 [Function (anonymous)]",
);
assert.strictEqual(
util.format(1, () => {}),
"1 [Function (anonymous)]",
);
assert.strictEqual(util.format("1", "'"), "1 '");
assert.strictEqual(util.format(1, "'"), "1 '");
assert.strictEqual(util.format("1", "number"), "1 number");
assert.strictEqual(util.format(1, "number"), "1 number");
assert.strictEqual(util.format(5n), "5n");
assert.strictEqual(util.format(5n, 5n), "5n 5n");
// Check `formatWithOptions`.
assert.strictEqual(
util.formatWithOptions({ colors: true }, true, undefined, Symbol(), 1, 5n, null, "foobar"),
"\u001b[33mtrue\u001b[39m " +
"\u001b[90mundefined\u001b[39m " +
"\u001b[32mSymbol()\u001b[39m " +
"\u001b[33m1\u001b[39m " +
"\u001b[33m5n\u001b[39m " +
"\u001b[1mnull\u001b[22m " +
"foobar",
);
assert.strictEqual(
util.format(new SharedArrayBuffer(4)),
"SharedArrayBuffer { [Uint8Contents]: <00 00 00 00>, byteLength: 4 }",
);
assert.strictEqual(util.formatWithOptions({ colors: true, compact: 3 }, "%s", [1, { a: true }]), "[ 1, [Object] ]");
[undefined, null, false, 5n, 5, "test", Symbol()].forEach(invalidOptions => {
assert.throws(
() => {
util.formatWithOptions(invalidOptions, { a: true });
},
{
code: "ERR_INVALID_ARG_TYPE",
message: /"inspectOptions".+object/,
},
);
});
});

View File

@@ -0,0 +1,60 @@
// This test ensures that util.inspect logs getters which access this.
import assert from "assert";
import { inspect } from "util";
test("no assertion failures", () => {
{
class X {
constructor() {
this._y = 123;
}
get y() {
return this._y;
}
}
const result = inspect(new X(), {
getters: true,
showHidden: true,
});
assert.strictEqual(result, "X { _y: 123, [y]: [Getter: 123] }");
}
// Regression test for https://github.com/nodejs/node/issues/37054
{
class A {
constructor(B) {
this.B = B;
}
get b() {
return this.B;
}
}
class B {
constructor() {
this.A = new A(this);
}
get a() {
return this.A;
}
}
const result = inspect(new B(), {
depth: 1,
getters: true,
showHidden: true,
});
assert.strictEqual(
result,
"<ref *1> B {\n" +
" A: A { B: [Circular *1], [b]: [Getter] [Circular *1] },\n" +
" [a]: [Getter] A { B: [Circular *1], [b]: [Getter] [Circular *1] }\n" +
"}",
);
}
});

View File

@@ -0,0 +1,27 @@
import util from "util";
// Test that huge objects don't crash due to exceeding the maximum heap size.
// Create a difficult to stringify object. Without the artificial limitation
// this would crash or throw an maximum string size error.
//! This test currently relies on a non-standard extension to util.inspect
// It optimizes the output of circular objects. If that extension ends up
// being removed, this test will likely hang for a pretty long time.
// We are missing some kind of optimization Node does to pass this test near instantly even without the extension.
test("should not take longer than 2 seconds", () => {
let last = {};
const obj = last;
for (let i = 0; i < 500; i++) {
// original value: 1000 (reduced to 500 to let tests run faster)
last.next = { circular: obj, last, obj: { a: i, b: 2, c: true } };
last = last.next;
obj[i] = last;
}
const str = util.inspect(obj, { depth: Infinity, colors: false });
void str;
//console.log(str);
//console.log(str.length);
});

View File

@@ -0,0 +1,177 @@
import assert from "assert";
import util from "util";
const opts = { showProxy: true };
test("no assertion failures", () => {
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(_, key) {
throw new Error("get: " + String(key));
},
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);
const r = Proxy.revocable({}, {});
r.revoke();
assert.strictEqual(util.inspect(r.proxy), "<Revoked Proxy>");
assert.strictEqual(
util.inspect(r, { showProxy: true }),
"{ proxy: <Revoked Proxy>, revoke: [Function (anonymous)] }",
);
assert.strictEqual(util.format("%s", r.proxy), "<Revoked 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" +
"]",
);
// 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);
});

File diff suppressed because it is too large Load Diff