No dependencies whatsoever. This package declares no dependencies or devDependencies.
Permalink to InstallationInstallation
Permalink to Quick TakeQuick Take
Purpose
codsen-format-diagnostic-value turns any JavaScript value into bounded, human-readable text for validation errors and diagnostic logs. It represents values that JSON.stringify() cannot handle, avoids reading accessors, marks circular references, and contains failures while inspecting hostile objects.
The result is JSON-like, not JSON. Diagnostic tokens, symbol keys, and truncation can make it invalid JSON, so don’t parse the result or use it as a storage format.
API — formatDiagnosticValue()
The main function formatDiagnosticValue() is imported like this:
The function accepts these arguments:
| Argument | Type | Required | Description |
|---|---|---|---|
valueType: unknown | |||
value | unknown | yes | The value to format. |
indentationType: 0 | 4 | |||
indentation | 0 | 4 | no | Use 0, the default, for compact output. Use 4 for multiline output with four-space indentation. |
It returns a string. Ordinary inputs aren’t mutated; proxy traps can cause their own side effects, as described in Inspection limits.
Compact and indented output
By default, nested values stay on one line:
import { formatDiagnosticValue } from "codsen-format-diagnostic-value";
console.log(
formatDiagnosticValue({ one: 1, nested: { ok: true }, list: ["x", null] }),
);
// => {"one":1,"nested":{"ok":true},"list":["x",null]}
Pass 4 when the diagnostic follows a line break or needs to remain readable as it grows:
console.log(formatDiagnosticValue({ one: 1, list: [true, "x"] }, 4));
// => {
// "one": 1,
// "list": [
// true,
// "x"
// ]
// }
No other indentation width is part of the API.
Values outside JSON
The formatter preserves useful distinctions that JSON omits or rejects:
| Input | Output |
|---|---|
undefined | |
undefined | undefined |
123n | |
123n | 123n |
Symbol("marker") | |
Symbol("marker") | Symbol("marker") |
| A function | |
| A function | [Function] |
NaN | |
NaN | NaN |
| Positive or negative infinity | |
| Positive or negative infinity | Infinity or -Infinity |
| Negative zero | |
| Negative zero | -0 |
Strings use double quotes. The formatter escapes quotes, backslashes, C0 control characters (U+0000–U+001F), the U+2028 line separator, the U+2029 paragraph separator, and UTF-16 surrogate code units. These escapes keep those code units visible in diagnostic text.
Objects contain their own enumerable string and symbol properties. Inherited and non-enumerable properties are omitted. Arrays contain indexed slots only; extra named properties are omitted, and a missing or non-enumerable indexed slot becomes [Empty].
Built-ins such as Date, Map, Set, RegExp, and Error don’t receive type-specific serializers. Each is represented through its own enumerable properties, which can produce {} when it has none.
Accessors and circular references
The formatter inspects property descriptors instead of reading property values. Getters and setters aren’t invoked:
let getterCalls = 0;
const input = {};
Object.defineProperty(input, "value", {
enumerable: true,
get() {
getterCalls += 1;
throw new Error("must not run");
},
});
console.log(formatDiagnosticValue(input));
// => {"value":[Getter]}
console.log(getterCalls);
// => 0
Accessors appear as [Getter], [Setter], [Getter/Setter], or [Accessor]. The formatter also doesn’t call an object’s toJSON() method.
A reference to an active ancestor becomes [Circular]:
const input = { name: "root" };
input.self = input;
console.log(formatDiagnosticValue(input));
// => {"name":"root","self":[Circular]}
Repeated references that aren’t circular are expanded each time. For example, two sibling properties that point to the same object both include that object’s contents.
Inspection limits
The formatter caps its output and limits its own traversal after each JavaScript reflection operation returns:
| Limit | Behavior |
|---|---|
| 2,000 UTF-16 code units | |
| 2,000 UTF-16 code units | Stops output with …. An escape sequence is never split. |
| Five object levels | |
| Five object levels | Replaces a deeper object or array with [MaxDepth]. |
| 50 entries across the whole value | |
| 50 entries across the whole value | Adds [MaxEntries] when the shared object-property and array-slot budget is exhausted. |
The entry limit is global for one call, not 50 entries per nested object. Reflected non-enumerable object keys also consume that budget, even though they don’t appear in the output. This bounds descriptor checks for proxies that report many hidden keys.
Reflection failures are represented at the affected object, property, or array slot. Any failure that reaches the outer formatter, including a primitive conversion failure, makes the whole call return [Uninspectable].
Reflect.ownKeys() collects the complete key list before the 50-entry budget applies. Reflection on a proxy can also invoke its ownKeys and getOwnPropertyDescriptor traps. Those traps can run code, cause side effects, or fail to return. The formatter contains thrown failures from them, but these limits aren’t CPU-time or allocation guarantees, and the formatter isn’t a sandbox.
Re-export from codsen-utils
codsen-utils also re-exports formatDiagnosticValue() for packages that already depend on that utility collection:
import { formatDiagnosticValue } from "codsen-utils";