@@ -58,7 +58,8 @@ export function stringify(value: any, options?: StringifyOptions): string {
5858 const types : TypeInfo [ ] = [ ] ;
5959 const circular = new WeakMap < any , PathType [ ] > ( ) ;
6060 const refs : RefInfo [ ] = [ ] ;
61- const source = expandPrototypeChain ( value , { ...options , patches, descriptors, types, circular, refs } ) ;
61+ const apis : JsonApi [ ] = [ ] ;
62+ const source = expandPrototypeChain ( value , { ...options , patches, descriptors, types, apis, circular, refs } ) ;
6263 const serialized = serializeRecursively ( source , {
6364 ...options ,
6465 parentPath : [ ] ,
@@ -82,6 +83,7 @@ export function stringify(value: any, options?: StringifyOptions): string {
8283 } ,
8384 } ) as PatchInfo [ ] ,
8485 types,
86+ apis,
8587 refs,
8688 } ;
8789 if ( preserveDescriptors ) {
@@ -112,39 +114,35 @@ export function stringify(value: any, options?: StringifyOptions): string {
112114 * @param options - Options to control the expansion behavior.
113115 */
114116export function expandPrototypeChain ( source : any , options ?: ExpandPrototypeChainOptions ) : typeof source {
115- const { parentPath, patches = [ ] , descriptors = [ ] , types = [ ] , refs = [ ] , circular = new WeakMap ( ) } = options ?? { } ;
117+ const {
118+ parentPath,
119+ patches = [ ] ,
120+ descriptors = [ ] ,
121+ types = [ ] ,
122+ refs = [ ] ,
123+ apis = [ ] ,
124+ circular = new WeakMap ( ) ,
125+ } = options ?? { } ;
116126 return expandPrototypeChainRecursively ( source , {
117127 ...options ,
128+ paths : parentPath ?? [ ] ,
118129 patches,
119130 descriptors,
120131 types,
121132 refs,
133+ apis,
122134 circular,
123- paths : parentPath ,
124135 } ) ;
125136}
126137
127138function expandPrototypeChainRecursively (
128139 source : any ,
129140 options : {
130- paths ?: PathType [ ] ;
131- patches : PatchInfo [ ] ;
132- descriptors : DescriptorInfo [ ] ;
133- types : TypeInfo [ ] ;
134- circular : WeakMap < any , PathType [ ] > ;
135- refs : RefInfo [ ] ;
136- } & Pick < StringifyOptions , 'preserveClassConstructor' | 'preserveDescriptors' | 'debug' >
141+ paths : PathType [ ] ;
142+ } & Pick < ExpandPrototypeChainOptions , 'patches' | 'descriptors' | 'types' | 'refs' | 'apis' | 'circular' > &
143+ Pick < StringifyOptions , 'preserveClassConstructor' | 'preserveDescriptors' | 'debug' >
137144) : typeof source {
138- const {
139- debug,
140- patches,
141- preserveDescriptors = true ,
142- descriptors = [ ] ,
143- types = [ ] ,
144- paths = [ ] ,
145- refs = [ ] ,
146- circular,
147- } = options ?? { } ;
145+ const { debug, patches, preserveDescriptors = true , descriptors, types, paths, refs, apis, circular } = options ;
148146 if ( source == null || source === Array . prototype || source === Object . prototype ) {
149147 return source ;
150148 }
@@ -177,6 +175,19 @@ function expandPrototypeChainRecursively(
177175 // should return `null` instead of `undefined`, since undefined will be ignored in JSON.stringify
178176 return null ;
179177 }
178+ if ( 'isRawJSON' in JSON && typeof JSON . isRawJSON === 'function' && JSON . isRawJSON ( source ) ) {
179+ return source ;
180+ } else if ( source . toJSON && typeof source . toJSON === 'function' ) {
181+ const api : JsonApi = {
182+ toJSON : stringToBase64 ( serializeFunction ( source . toJSON . toString ( ) ) ! ) ,
183+ } ;
184+ if ( source . fromJSON && typeof source . fromJSON === 'function' ) {
185+ api . fromJSON = stringToBase64 ( serializeFunction ( source . fromJSON . toString ( ) ) ! ) ;
186+ }
187+ apis . push ( api ) ;
188+ // todo: 1. 序列化result 2. 解析apis
189+ result = source . toJSON ( ) ;
190+ }
180191 if ( Array . isArray ( source ) ) {
181192 result = [ ...source ] ;
182193 } else if ( source instanceof Map ) {
@@ -361,6 +372,8 @@ function serializeRecursively(
361372 return `${ ST } null${ ET } ` ;
362373 } else if ( source === undefined ) {
363374 return undefined ;
375+ } else if ( 'isRawJSON' in JSON && typeof JSON . isRawJSON === 'function' && JSON . isRawJSON ( source ) ) {
376+ return source ;
364377 } else if ( typeof source === 'number' ) {
365378 if ( Number . isNaN ( source ) ) {
366379 return `${ ST } NaN${ ET } ` ;
@@ -460,11 +473,17 @@ export function serializeFunction(funcStr: string) {
460473 return undefined ;
461474 }
462475 if (
476+ // function () {}
463477 ! funcStr . startsWith ( 'function' ) &&
478+ // async function () {}
464479 ! funcStr . startsWith ( 'async function' ) &&
480+ // class {}
465481 ! funcStr . startsWith ( 'class' ) &&
482+ // function* () {}
466483 ! funcStr . startsWith ( 'function*' ) &&
484+ // async function* () {}
467485 ! funcStr . startsWith ( 'async function*' ) &&
486+ // () => {}
468487 ! funcStr . replace ( / \s / g, '' ) . match ( / ^ \( ? [ ^ ) ] + \) ? = > / )
469488 ) {
470489 // If it's a computed property function, for example: { [Symbol.toPrimitive]() { return 1; } }
@@ -890,10 +909,10 @@ interface RefInfo {
890909 path : PathType [ ] ;
891910 from : PathType [ ] ;
892911}
893- // interface Jsoner<T> {
894- // fromJson: (value: T) => string;
895- // deserialize: (value: string) => T ;
896- // }
912+ interface JsonApi {
913+ fromJSON ?: string ;
914+ toJSON : string ;
915+ }
897916
898917interface SerializedResult {
899918 version ?: string ;
@@ -902,6 +921,7 @@ interface SerializedResult {
902921 endTag ?: string ;
903922 source : string | undefined ;
904923 types : TypeInfo [ ] ;
924+ apis : JsonApi [ ] ;
905925 patches : PatchInfo [ ] ;
906926 refs : RefInfo [ ] ;
907927 descriptors ?: DescriptorInfo [ ] ;
@@ -969,6 +989,7 @@ export type ExpandPrototypeChainOptions = {
969989 descriptors : DescriptorInfo [ ] ;
970990 /** The output types for the object after expanding the prototype chain. */
971991 types : TypeInfo [ ] ;
992+ apis : JsonApi [ ] ;
972993 circular : WeakMap < any , PathType [ ] > ;
973994 /** The circular refs for the object after expanding the prototype chain. */
974995 refs : RefInfo [ ] ;
0 commit comments