11'use strict'
22
3+ const { hasOwnProperty } = Object . prototype
4+
35const stringify = configure ( )
46
57// @ts -expect-error
@@ -20,7 +22,7 @@ module.exports = stringify
2022// eslint-disable-next-line
2123const strEscapeSequencesRegExp = / [ \u0000 - \u001f \u0022 \u005c \ud800 - \udfff ] | [ \ud800 - \udbff ] (? ! [ \udc00 - \udfff ] ) | (?: [ ^ \ud800 - \udbff ] | ^ ) [ \udc00 - \udfff ] /
2224// eslint-disable-next-line
23- const strEscapeSequencesReplacer = / [ \u0000 - \u001f \u0022 \u005c \ud800 - \udfff ] | [ \ud800 - \udbff ] (? ! [ \udc00 - \udfff ] ) | (?: [ ^ \ud800 - \udbff ] | ^ ) [ \udc00 - \udfff ] / g
25+ const strEscapeSequencesReplacer = new RegExp ( strEscapeSequencesRegExp , 'g' )
2426
2527// Escaped special characters. Use empty strings to fill up unused entries.
2628const meta = [
@@ -69,13 +71,13 @@ function strEscape (str) {
6971 last = i + 1
7072 } else if ( point >= 0xd800 && point <= 0xdfff ) {
7173 if ( point <= 0xdbff && i + 1 < str . length ) {
72- const point = str . charCodeAt ( i + 1 )
73- if ( point >= 0xdc00 && point <= 0xdfff ) {
74+ const nextPoint = str . charCodeAt ( i + 1 )
75+ if ( nextPoint >= 0xdc00 && nextPoint <= 0xdfff ) {
7476 i ++
7577 continue
7678 }
7779 }
78- result += `${ str . slice ( last , i ) } ${ ` \\u${ point . toString ( 16 ) } ` } `
80+ result += `${ str . slice ( last , i ) } \\u${ point . toString ( 16 ) } `
7981 last = i + 1
8082 }
8183 }
@@ -105,7 +107,7 @@ const typedArrayPrototypeGetSymbolToStringTag =
105107 Object . getOwnPropertyDescriptor (
106108 Object . getPrototypeOf (
107109 Object . getPrototypeOf (
108- new Uint8Array ( )
110+ new Int8Array ( )
109111 )
110112 ) ,
111113 Symbol . toStringTag
@@ -128,8 +130,8 @@ function stringifyTypedArray (array, separator, maximumBreadth) {
128130}
129131
130132function getCircularValueOption ( options ) {
131- if ( options && Object . prototype . hasOwnProperty . call ( options , 'circularValue' ) ) {
132- var circularValue = options . circularValue
133+ if ( options && hasOwnProperty . call ( options , 'circularValue' ) ) {
134+ const circularValue = options . circularValue
133135 if ( typeof circularValue === 'string' ) {
134136 return `"${ circularValue } "`
135137 }
@@ -149,8 +151,9 @@ function getCircularValueOption (options) {
149151}
150152
151153function getBooleanOption ( options , key ) {
152- if ( options && Object . prototype . hasOwnProperty . call ( options , key ) ) {
153- var value = options [ key ]
154+ let value
155+ if ( options && hasOwnProperty . call ( options , key ) ) {
156+ value = options [ key ]
154157 if ( typeof value !== 'boolean' ) {
155158 throw new TypeError ( `The "${ key } " argument must be of type boolean` )
156159 }
@@ -159,8 +162,9 @@ function getBooleanOption (options, key) {
159162}
160163
161164function getPositiveIntegerOption ( options , key ) {
162- if ( options && Object . prototype . hasOwnProperty . call ( options , key ) ) {
163- var value = options [ key ]
165+ let value
166+ if ( options && hasOwnProperty . call ( options , key ) ) {
167+ value = options [ key ]
164168 if ( typeof value !== 'number' ) {
165169 throw new TypeError ( `The "${ key } " argument must be of type number` )
166170 }
@@ -184,16 +188,40 @@ function getItemCount (number) {
184188function getUniqueReplacerSet ( replacerArray ) {
185189 const replacerSet = new Set ( )
186190 for ( const value of replacerArray ) {
187- if ( typeof value === 'string' ) {
188- replacerSet . add ( value )
189- } else if ( typeof value === 'number' ) {
191+ if ( typeof value === 'string' || typeof value === 'number' ) {
190192 replacerSet . add ( String ( value ) )
191193 }
192194 }
193195 return replacerSet
194196}
195197
198+ function getStrictOption ( options ) {
199+ if ( options && hasOwnProperty . call ( options , 'strict' ) ) {
200+ const value = options . strict
201+ if ( typeof value !== 'boolean' ) {
202+ throw new TypeError ( 'The "strict" argument must be of type boolean' )
203+ }
204+ if ( value ) {
205+ return ( value ) => {
206+ let message = `Object can not safely be stringified. Received type ${ typeof value } `
207+ if ( typeof value !== 'function' ) message += ` (${ value . toString ( ) } )`
208+ throw new Error ( message )
209+ }
210+ }
211+ }
212+ }
213+
196214function configure ( options ) {
215+ options = { ...options }
216+ const fail = getStrictOption ( options )
217+ if ( fail ) {
218+ if ( options . bigint === undefined ) {
219+ options . bigint = false
220+ }
221+ if ( ! ( 'circularValue' in options ) ) {
222+ options . circularValue = Error
223+ }
224+ }
197225 const circularValue = getCircularValueOption ( options )
198226 const bigint = getBooleanOption ( options , 'bigint' )
199227 const deterministic = getBooleanOption ( options , 'deterministic' )
@@ -302,11 +330,18 @@ function configure (options) {
302330 return `{${ res } }`
303331 }
304332 case 'number' :
305- return isFinite ( value ) ? String ( value ) : 'null'
333+ return isFinite ( value ) ? String ( value ) : fail ? fail ( value ) : 'null'
306334 case 'boolean' :
307335 return value === true ? 'true' : 'false'
336+ case 'undefined' :
337+ return undefined
308338 case 'bigint' :
309- return bigint ? String ( value ) : undefined
339+ if ( bigint ) {
340+ return String ( value )
341+ }
342+ // fallthrough
343+ default :
344+ return fail ? fail ( value ) : undefined
310345 }
311346 }
312347
@@ -387,11 +422,18 @@ function configure (options) {
387422 return `{${ res } }`
388423 }
389424 case 'number' :
390- return isFinite ( value ) ? String ( value ) : 'null'
425+ return isFinite ( value ) ? String ( value ) : fail ? fail ( value ) : 'null'
391426 case 'boolean' :
392427 return value === true ? 'true' : 'false'
428+ case 'undefined' :
429+ return undefined
393430 case 'bigint' :
394- return bigint ? String ( value ) : undefined
431+ if ( bigint ) {
432+ return String ( value )
433+ }
434+ // fallthrough
435+ default :
436+ return fail ? fail ( value ) : undefined
395437 }
396438 }
397439
@@ -490,11 +532,18 @@ function configure (options) {
490532 return `{${ res } }`
491533 }
492534 case 'number' :
493- return isFinite ( value ) ? String ( value ) : 'null'
535+ return isFinite ( value ) ? String ( value ) : fail ? fail ( value ) : 'null'
494536 case 'boolean' :
495537 return value === true ? 'true' : 'false'
538+ case 'undefined' :
539+ return undefined
496540 case 'bigint' :
497- return bigint ? String ( value ) : undefined
541+ if ( bigint ) {
542+ return String ( value )
543+ }
544+ // fallthrough
545+ default :
546+ return fail ? fail ( value ) : undefined
498547 }
499548 }
500549
@@ -583,11 +632,18 @@ function configure (options) {
583632 return `{${ res } }`
584633 }
585634 case 'number' :
586- return isFinite ( value ) ? String ( value ) : 'null'
635+ return isFinite ( value ) ? String ( value ) : fail ? fail ( value ) : 'null'
587636 case 'boolean' :
588637 return value === true ? 'true' : 'false'
638+ case 'undefined' :
639+ return undefined
589640 case 'bigint' :
590- return bigint ? String ( value ) : undefined
641+ if ( bigint ) {
642+ return String ( value )
643+ }
644+ // fallthrough
645+ default :
646+ return fail ? fail ( value ) : undefined
591647 }
592648 }
593649
0 commit comments