or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.md

index.mddocs/

0

# Safe Stable Stringify

1

2

Safe Stable Stringify is a deterministic and fast serialization alternative to JSON.stringify with zero dependencies. It gracefully handles circular structures and bigint values instead of throwing errors, offers optional custom circular values and deterministic behavior, and maintains 100% test coverage.

3

4

## Package Information

5

6

- **Package Name**: safe-stable-stringify

7

- **Package Type**: npm

8

- **Language**: JavaScript with TypeScript definitions

9

- **Installation**: `npm install safe-stable-stringify`

10

11

## Core Imports

12

13

```typescript

14

import stringify, { configure } from "safe-stable-stringify";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const stringify = require("safe-stable-stringify");

21

const { configure } = require("safe-stable-stringify");

22

```

23

24

For named imports (ESM):

25

26

```typescript

27

import { configure, stringify } from "safe-stable-stringify";

28

```

29

30

## Basic Usage

31

32

```typescript

33

import stringify from "safe-stable-stringify";

34

35

// Handle bigint values (JSON.stringify would throw)

36

const bigintObj = { a: 0, c: 2n, b: 1 };

37

console.log(stringify(bigintObj));

38

// Output: '{"a":0,"b":1,"c":2}'

39

40

// Handle circular references (JSON.stringify would throw)

41

const circular = { name: "John", age: 30 };

42

circular.self = circular;

43

console.log(stringify(circular));

44

// Output: '{"age":30,"name":"John","self":"[Circular]"}'

45

46

// Use with replacer and space parameters (same as JSON.stringify)

47

console.log(stringify(circular, ['name', 'age'], 2));

48

// Output:

49

// {

50

// "name": "John",

51

// "age": 30

52

// }

53

```

54

55

## Capabilities

56

57

### Safe Stringify

58

59

Main function that safely serializes JavaScript objects to JSON strings with deterministic behavior.

60

61

```typescript { .api }

62

/**

63

* Safely stringify JavaScript objects to JSON with circular reference and bigint handling

64

* @param value - The value to stringify

65

* @param replacer - Optional replacer function or array (same as JSON.stringify)

66

* @param space - Optional space parameter for formatting (same as JSON.stringify)

67

* @returns JSON string representation or undefined for unstringifiable values

68

*/

69

function stringify(value: undefined | symbol | ((...args: unknown[]) => unknown), replacer?: Replacer, space?: string | number): undefined;

70

function stringify(value: string | number | unknown[] | null | boolean | object, replacer?: Replacer, space?: string | number): string;

71

function stringify(value: unknown, replacer?: ((key: string, value: unknown) => unknown) | (number | string)[] | null | undefined, space?: string | number): string | undefined;

72

73

type Replacer = (number | string)[] | null | undefined | ((key: string, value: unknown) => string | number | boolean | null | object);

74

```

75

76

### Configure Function

77

78

Creates a customized stringify function with specific options for handling bigint, circular references, deterministic behavior, and other serialization settings.

79

80

```typescript { .api }

81

/**

82

* Creates a customized stringify function with specified options

83

* @param options - Configuration options object

84

* @returns Configured stringify function with applied options

85

*/

86

function configure(options: StringifyOptions): typeof stringify;

87

88

interface StringifyOptions {

89

/** Convert bigint values to numeric strings instead of ignoring them (default: true) */

90

bigint?: boolean;

91

/**

92

* Value to use for circular references

93

* - string: custom replacement text

94

* - null/undefined: omit circular properties

95

* - Error/TypeError: throw on circular references

96

* (default: '[Circular]')

97

*/

98

circularValue?: string | null | undefined | ErrorConstructor | TypeErrorConstructor;

99

/**

100

* Ensure deterministic key ordering

101

* - true: sort keys alphabetically

102

* - false: preserve insertion order

103

* - function: custom comparator for sorting

104

* (default: true)

105

*/

106

deterministic?: boolean | ((a: string, b: string) => number);

107

/** Maximum number of properties to serialize per object (default: Infinity) */

108

maximumBreadth?: number;

109

/** Maximum object nesting levels to serialize (default: Infinity) */

110

maximumDepth?: number;

111

/** Throw errors for non-JSON values instead of graceful handling (default: false) */

112

strict?: boolean;

113

}

114

```

115

116

**Usage Examples:**

117

118

```typescript

119

import { configure } from "safe-stable-stringify";

120

121

// Custom configuration

122

const customStringify = configure({

123

bigint: true, // Convert bigint to numeric JSON representation

124

circularValue: "CIRCULAR_REF", // Custom circular reference text

125

deterministic: false, // Preserve insertion order

126

maximumDepth: 3, // Limit nesting depth

127

maximumBreadth: 10 // Limit properties per object

128

});

129

130

const data = {

131

bigNum: 999_999_999_999_999_999n,

132

deep: { level1: { level2: { level3: { level4: "too deep" } } } },

133

manyProps: Object.fromEntries(Array.from({length: 15}, (_, i) => [`prop${i}`, i]))

134

};

135

data.circular = data;

136

137

console.log(customStringify(data, null, 2));

138

// Bigint converted to numeric JSON, circular ref replaced, deep object truncated

139

140

// Strict mode (throws on problematic values)

141

const strictStringify = configure({

142

strict: true,

143

bigint: false, // Must be false in strict mode unless explicitly true

144

circularValue: Error // Throw on circular references

145

});

146

147

try {

148

strictStringify({ fn: () => {} }); // Throws error for function

149

} catch (error) {

150

console.log("Strict mode prevented serialization");

151

}

152

```

153

154

## Additional Properties

155

156

The default export function has additional properties attached for convenience:

157

158

```typescript { .api }

159

/**

160

* Reference to the main stringify function (same as default export)

161

*/

162

stringify.stringify: typeof stringify;

163

164

/**

165

* Default export reference for compatibility

166

*/

167

stringify.default: typeof stringify;

168

169

/**

170

* Configuration function attached to the main function

171

*/

172

stringify.configure: typeof configure;

173

```

174

175

These properties provide multiple ways to access the functionality:

176

177

```typescript

178

import stringify from "safe-stable-stringify";

179

180

// All of these are equivalent

181

stringify({ test: true });

182

stringify.stringify({ test: true });

183

stringify.default({ test: true });

184

185

// Configure can be accessed directly from the main function

186

const customStringify = stringify.configure({ bigint: false });

187

```

188

189

## Key Differences from JSON.stringify

190

191

1. **Circular References**: Replaced with configurable value (default: `'[Circular]'`) instead of throwing

192

2. **Object Key Ordering**: Deterministic alphabetical sorting by default instead of insertion order

193

3. **BigInt Values**: Converted to numeric JSON representation instead of throwing TypeError

194

4. **Boxed Primitives**: Handled as regular objects, not unboxed (e.g., `Number(5)` stays as object)

195

5. **Error Handling**: Graceful handling of problematic values unless strict mode is enabled

196

197

## TypeScript Support

198

199

The package includes complete TypeScript definitions with:

200

201

- Function overloads for precise return type inference

202

- Generic type preservation in replacer functions

203

- Full interface definitions for all configuration options

204

- Proper handling of union types for various input scenarios

205

206

```typescript

207

// TypeScript automatically infers return types

208

const result1: string = stringify({ name: "John" }); // Always string for objects

209

const result2: undefined = stringify(Symbol("test")); // Undefined for symbols

210

const result3: string | undefined = stringify(someUnknown); // Union type for unknown inputs

211

```