Stringify any JavaScript value with customizable formatting, plugins, and terminal colors.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Extensible plugin architecture for handling custom data types with both modern and legacy interfaces. Plugins allow pretty-format to serialize application-specific data structures with custom formatting logic.
Two plugin interfaces are supported: the modern NewPlugin interface (recommended) and the legacy OldPlugin interface for backwards compatibility.
type Plugin = NewPlugin | OldPlugin;
interface NewPlugin {
/** Test function to determine if this plugin should handle the value */
test: (val: any) => boolean;
/** Serialize function using the improved interface (version 21+) */
serialize: (
val: any,
config: Config,
indentation: string,
depth: number,
refs: Refs,
printer: Printer
) => string;
}
interface OldPlugin {
/** Test function to determine if this plugin should handle the value */
test: (val: any) => boolean;
/** Print function using the original interface */
print: (
val: unknown,
print: (val: unknown) => string,
indent: (str: string) => string,
options: PluginOptions,
colors: Colors
) => string;
}
interface PluginOptions {
edgeSpacing: string;
min: boolean;
spacing: string;
}The test function determines whether a plugin should handle a specific value.
Guidelines for writing test functions:
// Example test functions
const reactElementTest = (val: any) =>
val && val.$$typeof === Symbol.for('react.element');
const domElementTest = (val: any) =>
val && typeof val.nodeType === 'number' && val.nodeType === 1;
// Safe property access patterns
const safeTest = (val: any) =>
val != null && typeof val.customProp === 'string';
// Efficient type checking
const arrayLikeTest = (val: any) =>
Array.isArray(val) && val.constructor.name === 'CustomArray';Usage Examples:
const customPlugin = {
test(val) {
// Safe null checking to prevent TypeErrors
return val != null &&
typeof val === 'object' &&
val.constructor.name === 'MyCustomClass';
},
serialize(val, config, indentation, depth, refs, printer) {
return `MyCustomClass { ${val.toString()} }`;
}
};The recommended interface available in version 21 and later with full access to formatting context.
interface NewPlugin {
test: (val: any) => boolean;
serialize: (
val: any,
config: Config,
indentation: string,
depth: number,
refs: Refs,
printer: Printer
) => string;
}Serialize Function Parameters:
val: The value that "passed the test"config: Unchanging config object derived from optionsindentation: Current indentation string (concatenate to config.indent)depth: Current depth number (compare to config.maxDepth)refs: Current refs array for finding circular referencesprinter: Callback function to serialize childrenUsage Examples:
const advancedPlugin = {
test(val) {
return val && val.type === 'CustomCollection';
},
serialize(val, config, indentation, depth, refs, printer) {
// Check for circular references
if (refs.includes(val)) {
return '[Circular]';
}
// Check depth limit
if (++depth > config.maxDepth) {
return '[CustomCollection]';
}
// Add to refs for circular detection
const newRefs = [...refs, val];
// Format children using printer callback
const items = val.items
.slice(0, config.maxWidth)
.map(item =>
indentation + config.indent +
printer(item, config, indentation + config.indent, depth, newRefs)
)
.join(config.spacingInner);
return `CustomCollection {${config.spacingOuter}${items}${config.spacingOuter}${indentation}}`;
}
};The original interface for backwards compatibility with limited access to formatting context.
interface OldPlugin {
test: (val: any) => boolean;
print: (
val: unknown,
print: (val: unknown) => string,
indent: (str: string) => string,
options: PluginOptions,
colors: Colors
) => string;
}Print Function Parameters:
val: The value that "passed the test"print: Current printer callback function to serialize childrenindent: Current indenter callback function to indent lines at next leveloptions: Config object with min, spacing, and edgeSpacing propertiescolors: Colors object derived from optionsUsage Examples:
const legacyPlugin = {
test(val) {
return typeof val === 'function';
},
print(val, printer, indenter, options, colors) {
const name = val.name || 'anonymous';
const paramCount = val.length;
return `[Function ${name} ${paramCount}]`;
}
};Plugins are registered through the plugins option in the format function.
interface OptionsReceived {
plugins?: Plugin[];
}Usage Examples:
import { format } from "pretty-format";
// Single plugin
const result = format(value, {
plugins: [myCustomPlugin]
});
// Multiple plugins (order matters - first matching plugin wins)
const formatted = format(value, {
plugins: [
specificPlugin, // More specific plugins first
generalPlugin, // General plugins last
fallbackPlugin
]
});
// With built-in plugins
import { plugins } from "pretty-format";
const { ReactElement, DOMElement } = plugins;
const formatted = format(reactComponent, {
plugins: [ReactElement, myCustomPlugin]
});test function is called in ordertrue is selectedserialize or print method is calledPlugins can throw errors which are wrapped in PrettyFormatPluginError.
class PrettyFormatPluginError extends Error {
constructor(message: string, stack: string);
}Error Scenarios:
Usage Examples:
const robustPlugin = {
test(val) {
try {
return val && val.customType === 'special';
} catch (error) {
// Test failures are caught and re-thrown as PrettyFormatPluginError
return false;
}
},
serialize(val, config, indentation, depth, refs, printer) {
try {
return `Special: ${val.value}`;
} catch (error) {
// Serialize failures become PrettyFormatPluginError
throw new Error(`Failed to serialize special value: ${error.message}`);
}
}
};false quickly for non-matching valuesUsage Examples:
// Efficient test function
const efficientPlugin = {
test(val) {
// Quick type check first
if (typeof val !== 'object' || val === null) {
return false;
}
// Then check specific properties
return val.constructor.name === 'MyClass';
},
serialize(val, config, indentation, depth, refs, printer) {
// Heavy computation only happens for matching values
return formatMyClass(val, config);
}
};Install with Tessl CLI
npx tessl i tessl/npm-pretty-format