-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrite-json.ts
More file actions
144 lines (137 loc) · 4.4 KB
/
write-json.ts
File metadata and controls
144 lines (137 loc) · 4.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**
* @fileoverview JSON writers that match the wire-format conventions a
* tool ecosystem expects: configurable indentation, configurable EOL,
* trailing newline by default. The `stringify` helper is exported so
* callers that already have an `fs` handle can render a buffer without
* round-tripping through this module's writers.
*/
import { getNodeFs } from '../node/fs'
import { JSONStringify, StringPrototypeReplace } from '../primordials'
import type { ObjectEncodingOptions, PathLike, WriteFileOptions } from 'node:fs'
import type { JsonReviver } from '../json/types'
import type { WriteJsonOptions } from './types'
// Module-level regex constant — avoid re-allocating on every call.
const NEWLINE_REGEX = /\n/g
/**
* Stringify JSON with custom formatting options.
* Formats JSON with configurable line endings and indentation.
*
* @param json - Value to stringify
* @param EOL - End-of-line sequence
* @param finalEOL - Whether to add final newline
* @param replacer - JSON replacer function
* @param spaces - Indentation spaces or string
* @returns Formatted JSON string
*/
/*@__NO_SIDE_EFFECTS__*/
export function stringify(
json: unknown,
EOL: string,
finalEOL: boolean,
replacer: JsonReviver | undefined,
spaces: number | string = 2,
): string {
const EOF = finalEOL ? EOL : ''
const str = JSONStringify(json, replacer, spaces)
return `${StringPrototypeReplace(str, NEWLINE_REGEX, EOL)}${EOF}`
}
/**
* Write JSON content to a file asynchronously with formatting.
* Stringifies the value with configurable indentation and line endings.
* Automatically adds a final newline by default for POSIX compliance.
*
* @param filepath - Path to write to
* @param jsonContent - Value to stringify and write
* @param options - Write options including formatting and encoding
* @returns Promise that resolves when write completes
*
* @example
* ```ts
* // Write formatted JSON with default 2-space indentation
* await writeJson('./data.json', { name: 'example', version: '1.0.0' })
*
* // Write with custom indentation
* await writeJson('./config.json', config, { spaces: 4 })
*
* // Write with tabs instead of spaces
* await writeJson('./data.json', data, { spaces: '\t' })
*
* // Write without final newline
* await writeJson('./inline.json', obj, { finalEOL: false })
*
* // Write with Windows line endings
* await writeJson('./win.json', data, { EOL: '\r\n' })
* ```
*/
export async function writeJson(
filepath: PathLike,
jsonContent: unknown,
options?: WriteJsonOptions | string,
): Promise<void> {
const opts = typeof options === 'string' ? { encoding: options } : options
const { EOL, finalEOL, replacer, spaces, ...fsOptions } = {
__proto__: null,
...opts,
} as WriteJsonOptions
const fs = getNodeFs()
const jsonString = stringify(
jsonContent,
EOL || '\n',
finalEOL !== undefined ? finalEOL : true,
replacer,
spaces,
)
await fs.promises.writeFile(filepath, jsonString, {
encoding: 'utf8',
...fsOptions,
__proto__: null,
} as ObjectEncodingOptions)
}
/**
* Write JSON content to a file synchronously with formatting.
* Stringifies the value with configurable indentation and line endings.
* Automatically adds a final newline by default for POSIX compliance.
*
* @param filepath - Path to write to
* @param jsonContent - Value to stringify and write
* @param options - Write options including formatting and encoding
*
* @example
* ```ts
* // Write formatted JSON with default 2-space indentation
* writeJsonSync('./package.json', pkg)
*
* // Write with custom indentation
* writeJsonSync('./tsconfig.json', tsconfig, { spaces: 4 })
*
* // Write with tabs for indentation
* writeJsonSync('./data.json', data, { spaces: '\t' })
*
* // Write compacted (no indentation)
* writeJsonSync('./compact.json', data, { spaces: 0 })
* ```
*/
export function writeJsonSync(
filepath: PathLike,
jsonContent: unknown,
options?: WriteJsonOptions | string | undefined,
): void {
const opts = typeof options === 'string' ? { encoding: options } : options
const { EOL, finalEOL, replacer, spaces, ...fsOptions } = {
__proto__: null,
...opts,
}
const fs = getNodeFs()
const jsonString = stringify(
jsonContent,
EOL || '\n',
finalEOL !== undefined ? finalEOL : true,
replacer,
spaces,
)
fs.writeFileSync(filepath, jsonString, {
encoding: 'utf8',
...fsOptions,
__proto__: null,
} as WriteFileOptions)
}