Skip to content

Commit 4fb047c

Browse files
committed
refactor: extract builtin type stringification functions
- move TypedArray union type to types.ts for centralized definition - refactor stringify.ts builtin handling: - extract Map, Set, Date, URL, and ArrayBuffer stringification to dedicated functions - create stringifyBuiltin() dispatcher function to reduce nesting in stringifyValue() - improve code maintainability and separation of concerns
1 parent 6e855cc commit 4fb047c

3 files changed

Lines changed: 82 additions & 31 deletions

File tree

src/defaultRevivers.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { YSONReviver } from "./types.js"
1+
import { TypedArray, YSONReviver } from "./types.js"
22

33
const parseMap: YSONReviver<Map<any, any>> = x => {
44
if (typeof x != "object") throw new Error("Map must be an object or entry array")
@@ -40,8 +40,7 @@ const parseDataView: YSONReviver<DataView> = x => {
4040
return new DataView(new Uint8Array(x as []).buffer)
4141
}
4242

43-
const typedArrays = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array, Float32Array, Float64Array]
44-
type TypedArray = Int8Array| Uint8Array| Uint8ClampedArray| Int16Array| Uint16Array| Int32Array| Uint32Array| BigInt64Array| BigUint64Array| Float32Array| Float64Array
43+
const typedArrays = [Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array, Float32Array, Float64Array] as const
4544

4645
const parseTypedArray: YSONReviver<TypedArray> = (x, { name }) => {
4746
if (!Array.isArray(x)) throw new Error("TypedArray must be an array")

src/stringify.ts

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { escape } from "./escape.js";
2-
import { StringifyOptions, isYSONStringifiable, keyRegex } from "./types.js";
2+
import { StringifyOptions, TypedArray, isYSONStringifiable, keyRegex } from "./types.js";
33

44
export function stringifyValue(value: unknown, options: StringifyOptions, depth: number): string | undefined {
55
switch (typeof value) {
@@ -32,35 +32,13 @@ export function stringifyValue(value: unknown, options: StringifyOptions, depth:
3232
}
3333

3434
if (Array.isArray(value)) return stringifyArray(value, options, depth)
35-
if (value instanceof Map) {
36-
const newValue = Object.fromEntries(value.entries())
37-
const raw = stringifyObject(newValue, options, depth)
38-
return `Map${options.spaceAfterPunctuation ? " " : ""}${raw}`
39-
}
40-
if (value instanceof Set) {
41-
const newValue = Array.from(value.values())
42-
const raw = stringifyArray(newValue, options, depth)
43-
return `Set${options.spaceAfterPunctuation ? " " : ""}${raw}`
44-
}
45-
if (value instanceof Date) {
46-
const newValue = value.toISOString()
47-
const raw = escape(newValue)
48-
return `Date${options.spaceAfterPunctuation ? " " : ""}${raw}`
49-
}
50-
if (value instanceof URL) {
51-
const newValue = value.href
52-
const raw = escape(newValue)
53-
return `URL${options.spaceAfterPunctuation ? " " : ""}${raw}`
54-
}
55-
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
56-
const type = value.constructor.name
57-
if (value instanceof DataView) value = value.buffer
58-
if (value instanceof ArrayBuffer) value = new Uint8Array(value)
59-
const raw = stringifyArray(Array.from(value as []), options, depth)
60-
return `${type}${options.spaceAfterPunctuation ? " " : ""}${raw}`
35+
36+
let stringified = stringifyBuiltin(value, options, depth)
37+
if (stringified == null) {
38+
stringified = stringifyObject(value as Record<string, unknown>, options, depth)
6139
}
6240

63-
return stringifyObject(value as Record<string, unknown>, options, depth)
41+
return stringified
6442
}
6543

6644
return undefined
@@ -105,4 +83,61 @@ function joinValues(arr: unknown[], open: string, close: string, options: String
10583
if (options.insetSpace) return `${open} ${arr.join(separator)} ${close}`
10684
return `${open}${arr.join(separator)}${close}`
10785
}
86+
}
87+
88+
function stringifyBuiltin(value: object, options: StringifyOptions, depth: number): string | null {
89+
let result: { raw: string, type: string } | null = null
90+
91+
if (value instanceof Map) result = stringifyMap(value, options, depth)
92+
if (value instanceof Set) result = stringifySet(value, options, depth)
93+
if (value instanceof Date) result = stringifyDate(value)
94+
if (value instanceof URL) result = stringifyURL(value)
95+
if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
96+
result = stringifyArrayBufferLike(value, options, depth)
97+
}
98+
99+
if (result) {
100+
return `${result.type}${options.spaceAfterPunctuation ? " " : ""}${result.raw}`
101+
}
102+
103+
return null
104+
}
105+
106+
function stringifyMap(map: Map<string, unknown>, options: StringifyOptions, depth: number) {
107+
const obj = Object.fromEntries(map.entries())
108+
const raw = stringifyObject(obj, options, depth)
109+
110+
return { raw, type: "Map" }
111+
}
112+
113+
function stringifySet(set: Set<unknown>, options: StringifyOptions, depth: number) {
114+
const arr = Array.from(set.values())
115+
const raw = stringifyArray(arr, options, depth)
116+
117+
return { raw, type: "Set" }
118+
}
119+
120+
function stringifyDate(date: Date) {
121+
const raw = escape(date.toISOString())
122+
123+
return { raw, type: "Date" }
124+
}
125+
126+
function stringifyURL(url: URL) {
127+
const raw = escape(url.href)
128+
129+
return { raw, type: "URL" }
130+
}
131+
132+
function stringifyArrayBufferLike(buffer: ArrayBuffer | ArrayBufferView<ArrayBufferLike>, options: StringifyOptions, depth: number) {
133+
const type = buffer.constructor.name
134+
let arr: (number | bigint)[]
135+
136+
if (buffer instanceof DataView) arr = Array.from(new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength))
137+
else if (buffer instanceof ArrayBuffer) arr = Array.from(new Uint8Array(buffer))
138+
else arr = Array.from(buffer as unknown as Iterable<number | bigint>)
139+
140+
const raw = stringifyArray(arr, options, depth)
141+
142+
return { raw, type }
108143
}

src/types.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,23 @@ export interface YSONParsable<T> {
8484
*/
8585
export type YSONParseType = YSONParsable<any> | YSONReviver<any>
8686

87+
/**
88+
* union of all TypedArray types
89+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray
90+
*/
91+
export type TypedArray =
92+
| Int8Array
93+
| Uint8Array
94+
| Uint8ClampedArray
95+
| Int16Array
96+
| Uint16Array
97+
| Int32Array
98+
| Uint32Array
99+
| BigInt64Array
100+
| BigUint64Array
101+
| Float32Array
102+
| Float64Array
103+
87104
/**
88105
* regex for single chars of an object key
89106
*/

0 commit comments

Comments
 (0)