11import {
2+ keys ,
23 isObservable ,
34 isObservableArray ,
4- isObservableMap ,
5- isObservableObject ,
65 isObservableValue ,
7- keys
6+ isObservableMap
87} from "../internal"
98
109export type ToJSOptions = {
1110 detectCycles ?: boolean
1211 exportMapsAsObjects ?: boolean
12+ recurseEverything ?: boolean
1313}
1414
1515const defaultOptions : ToJSOptions = {
1616 detectCycles : true ,
17- exportMapsAsObjects : true
17+ exportMapsAsObjects : true ,
18+ recurseEverything : false
1819}
1920
2021function cache < K , V > ( map : Map < any , any > , key : K , value : V , options : ToJSOptions ) : V {
@@ -23,37 +24,35 @@ function cache<K, V>(map: Map<any, any>, key: K, value: V, options: ToJSOptions)
2324}
2425
2526function toJSHelper ( source , options : ToJSOptions , __alreadySeen : Map < any , any > ) {
26- if ( ! isObservable ( source ) ) return source
27+ if ( ! options . recurseEverything && ! isObservable ( source ) ) return source
28+
29+ if ( typeof source !== "object" ) return source
30+
31+ // Directly return the Date object itself if contained in the observable
32+ if ( source instanceof Date ) return source
33+
34+ if ( isObservableValue ( source ) ) return toJSHelper ( source . get ( ) , options ! , __alreadySeen )
35+
36+ // make sure we track the keys of the object
37+ if ( isObservable ( source ) ) {
38+ keys ( source )
39+ }
2740
2841 const detectCycles = options . detectCycles === true
2942
30- if (
31- detectCycles &&
32- source !== null &&
33- typeof source === "object" &&
34- __alreadySeen . has ( source )
35- ) {
43+ if ( detectCycles && source !== null && __alreadySeen . has ( source ) ) {
3644 return __alreadySeen . get ( source )
3745 }
3846
39- if ( isObservableArray ( source ) ) {
47+ if ( isObservableArray ( source ) || Array . isArray ( source ) ) {
4048 const res = cache ( __alreadySeen , source , [ ] as any , options )
4149 const toAdd = source . map ( value => toJSHelper ( value , options ! , __alreadySeen ) )
4250 res . length = toAdd . length
4351 for ( let i = 0 , l = toAdd . length ; i < l ; i ++ ) res [ i ] = toAdd [ i ]
4452 return res
4553 }
4654
47- if ( isObservableObject ( source ) ) {
48- const res = cache ( __alreadySeen , source , { } , options )
49- keys ( source ) // make sure we track the keys of the object
50- for ( let key in source ) {
51- res [ key ] = toJSHelper ( source [ key ] , options ! , __alreadySeen )
52- }
53- return res
54- }
55-
56- if ( isObservableMap ( source ) ) {
55+ if ( isObservableMap ( source ) || Object . getPrototypeOf ( source ) === Map . prototype ) {
5756 if ( options . exportMapsAsObjects === false ) {
5857 const res = cache ( __alreadySeen , source , new Map ( ) , options )
5958 source . forEach ( ( value , key ) => {
@@ -69,9 +68,13 @@ function toJSHelper(source, options: ToJSOptions, __alreadySeen: Map<any, any>)
6968 }
7069 }
7170
72- if ( isObservableValue ( source ) ) return toJSHelper ( source . get ( ) , options ! , __alreadySeen )
71+ // Fallback to the situation that source is an ObservableObject or a plain object
72+ const res = cache ( __alreadySeen , source , { } , options )
73+ for ( let key in source ) {
74+ res [ key ] = toJSHelper ( source [ key ] , options ! , __alreadySeen )
75+ }
7376
74- return source
77+ return res
7578}
7679
7780/**
@@ -81,15 +84,16 @@ export function toJS<T>(source: T, options?: ToJSOptions): T
8184export function toJS ( source : any , options ?: ToJSOptions ) : any
8285export function toJS ( source , options : ToJSOptions ) // internal overload
8386export function toJS ( source , options ?: ToJSOptions ) {
84- if ( ! isObservable ( source ) ) return source
85-
8687 // backward compatibility
8788 if ( typeof options === "boolean" ) options = { detectCycles : options }
8889 if ( ! options ) options = defaultOptions
89- const detectCycles = options . detectCycles === true
90+ options . detectCycles =
91+ options . detectCycles === undefined
92+ ? options . recurseEverything === true
93+ : options . detectCycles === true
9094
9195 let __alreadySeen
92- if ( detectCycles ) __alreadySeen = new Map ( )
96+ if ( options . detectCycles ) __alreadySeen = new Map ( )
9397
9498 return toJSHelper ( source , options , __alreadySeen )
9599}
0 commit comments