@@ -28,9 +28,81 @@ interface DecycledObject {
2828 $ref ?: string ;
2929}
3030
31- export function decycle ( object : unknown , replacer ?: ReplacerFunction ) {
32- 'use strict' ;
31+ function deepCopy (
32+ value : unknown ,
33+ path : string ,
34+ objects : WeakMap < object , string > ,
35+ replacer ?: ReplacerFunction ,
36+ ) : unknown {
37+ // Recurses through the object, producing the deep copy.
38+
39+ let old_path : string | undefined ; // The path of an earlier occurance of value
40+ let nu : unknown [ ] | DecycledObject ; // The new object or array
41+
42+ // If a replacer function was provided, then call it to get a replacement value.
43+
44+ if ( replacer !== undefined ) {
45+ value = replacer ( value ) ;
46+ }
47+
48+ // typeof null === "object", so go on if this value is really an object but not
49+ // one of the weird builtin objects.
50+
51+ if (
52+ typeof value === 'object' &&
53+ value !== null &&
54+ ! ( value instanceof Boolean ) &&
55+ ! ( value instanceof Date ) &&
56+ ! ( value instanceof Number ) &&
57+ ! ( value instanceof RegExp ) &&
58+ ! ( value instanceof String )
59+ ) {
60+ // If the value is an object or array, look to see if we have already
61+ // encountered it. If so, return a {"$ref":PATH} object. This uses an
62+ // ES6 WeakMap.
63+
64+ old_path = objects . get ( value ) ;
65+ if ( old_path !== undefined ) {
66+ return { $ref : old_path } ;
67+ }
68+
69+ // Otherwise, accumulate the unique value and its path.
70+
71+ objects . set ( value , path ) ;
72+
73+ // If it is an array, replicate the array.
74+
75+ if ( Array . isArray ( value ) ) {
76+ nu = [ ] ;
77+ ( value as unknown [ ] ) . forEach ( function ( element : unknown , i : number ) {
78+ ( nu as unknown [ ] ) [ i ] = deepCopy (
79+ element ,
80+ path + '[' + String ( i ) + ']' ,
81+ objects ,
82+ replacer ,
83+ ) ;
84+ } ) ;
85+ } else {
86+ // If it is an object, replicate the object.
87+
88+ nu = { } as DecycledObject ;
89+ Object . keys ( value as Record < string , unknown > ) . forEach ( function (
90+ name : string ,
91+ ) {
92+ ( nu as DecycledObject ) [ name ] = deepCopy (
93+ ( value as Record < string , unknown > ) [ name ] ,
94+ path + '[' + JSON . stringify ( name ) + ']' ,
95+ objects ,
96+ replacer ,
97+ ) ;
98+ } ) ;
99+ }
100+ return nu ;
101+ }
102+ return value ;
103+ }
33104
105+ export function decycle ( object : unknown , replacer ?: ReplacerFunction ) {
34106 // Make a deep copy of an object or array, assuring that there is at most
35107 // one instance of each object or array in the resulting structure. The
36108 // duplicate references (which might be forming cycles) are replaced with
@@ -57,65 +129,5 @@ export function decycle(object: unknown, replacer?: ReplacerFunction) {
57129
58130 const objects = new WeakMap < object , string > ( ) ; // object to path mappings
59131
60- return ( function derez ( value : unknown , path : string ) : unknown {
61- // The derez function recurses through the object, producing the deep copy.
62-
63- let old_path : string | undefined ; // The path of an earlier occurance of value
64- let nu : unknown [ ] | DecycledObject ; // The new object or array
65-
66- // If a replacer function was provided, then call it to get a replacement value.
67-
68- if ( replacer !== undefined ) {
69- value = replacer ( value ) ;
70- }
71-
72- // typeof null === "object", so go on if this value is really an object but not
73- // one of the weird builtin objects.
74-
75- if (
76- typeof value === 'object' &&
77- value !== null &&
78- ! ( value instanceof Boolean ) &&
79- ! ( value instanceof Date ) &&
80- ! ( value instanceof Number ) &&
81- ! ( value instanceof RegExp ) &&
82- ! ( value instanceof String )
83- ) {
84- // If the value is an object or array, look to see if we have already
85- // encountered it. If so, return a {"$ref":PATH} object. This uses an
86- // ES6 WeakMap.
87-
88- old_path = objects . get ( value ) ;
89- if ( old_path !== undefined ) {
90- return { $ref : old_path } ;
91- }
92-
93- // Otherwise, accumulate the unique value and its path.
94-
95- objects . set ( value , path ) ;
96-
97- // If it is an array, replicate the array.
98-
99- if ( Array . isArray ( value ) ) {
100- nu = [ ] ;
101- ( value as unknown [ ] ) . forEach ( function ( element : unknown , i : number ) {
102- ( nu as unknown [ ] ) [ i ] = derez ( element , path + '[' + String ( i ) + ']' ) ;
103- } ) ;
104- } else {
105- // If it is an object, replicate the object.
106-
107- nu = { } as DecycledObject ;
108- Object . keys ( value as Record < string , unknown > ) . forEach ( function (
109- name : string ,
110- ) {
111- ( nu as DecycledObject ) [ name ] = derez (
112- ( value as Record < string , unknown > ) [ name ] ,
113- path + '[' + JSON . stringify ( name ) + ']' ,
114- ) ;
115- } ) ;
116- }
117- return nu ;
118- }
119- return value ;
120- } ) ( object , '$' ) ;
132+ return deepCopy ( object , '$' , objects , replacer ) ;
121133}
0 commit comments