@@ -63,10 +63,18 @@ export function stringify(value: any, options?: StringifyOptions): string {
6363 }
6464 const result : SerializedResult = {
6565 source : JSON . stringify ( serialized ) ,
66- patches,
67- descriptors,
66+ patches : serializeJavascriptRecursively ( patches , { parentPath : [ ] , circularRefs : new WeakMap ( ) , debug } ) as Patch [ ] ,
67+ descriptors : serializeJavascriptRecursively ( descriptors , {
68+ parentPath : [ ] ,
69+ circularRefs : new WeakMap ( ) ,
70+ } ) as DescriptorMeta [ ] ,
6871 types,
6972 } ;
73+ if ( debug ) {
74+ console . log ( 'patches: ' , patches ) ;
75+ console . log ( 'descriptors: ' , descriptors ) ;
76+ console . log ( 'types: ' , types ) ;
77+ }
7078 return JSON . stringify ( result ) ;
7179}
7280
@@ -114,6 +122,7 @@ function serializeJavascriptRecursively(
114122 } ;
115123 if ( typeof source === 'object' ) {
116124 if ( checkCircularRef ( ) ) return undefined ;
125+ // todo: 这两个字段没有被删除 "[Symbol.for('[keys]')]": undefined, "[Symbol.for('[values]')]": undefined,
117126 // todo: 修复e2e测试
118127 // todo: 优先判断对象是否有toJson()方法
119128 // todo: parse时,需要判断是否有fromJson()方法,如果有,则调用该方法进行反序列化
@@ -229,7 +238,6 @@ export function parse(input: string, options?: ParseOptions) {
229238 ...options ,
230239 closure,
231240 variablePrefix : VP ,
232- enablePatches : true ,
233241 } ) ;
234242 } catch ( error ) {
235243 console . error ( error ) ;
@@ -241,14 +249,15 @@ function executeDeserialize(result: SerializedResult, options: InternalParseOpti
241249 const { variablePrefix : VP = VariablePrefix , closure, get = getByPath , debug, prettyPrint = true } = options ?? { } ;
242250 const code = getDeserializeJavascriptCode ( result , options ) ;
243251 if ( debug ) {
244- const printSourceCode = getDeserializeJavascriptCode ( result , { ...options , isPrint : true } ) ;
252+ const printSourceCode = getDeserializeJavascriptCode ( result , { ...options , isPrinting : true } ) ;
245253 const prettyPrintCode = `\`${ printSourceCode . replace ( / ` / g, '\\`' ) . replace ( / \$ \{ / g, '\\${' ) } \`` ;
246254 const realCode = `'${ printSourceCode . replace ( / \n / g, '\\n' ) . replace ( / ' / g, "\\'" ) } '` ;
247255 const printCode = prettyPrint ? prettyPrintCode : realCode ;
248256 console . log (
249257 '-------------- deserializeCode --------------\n' ,
250- `${ getByPath . toString ( ) }
251- new Function('${ VP } context', '${ VP } options', ${ printCode } )(${ closure ? 'closure' : 'undefined' } , { get: getByPath });` ,
258+ `new Function('${ VP } context', '${ VP } options', ${ printCode } )(${ closure ? 'closure' : 'undefined' } , { get: getByPath });
259+ ${ getByPath . toString ( ) }
260+ ` ,
252261 'closure =' ,
253262 closure
254263 ) ;
@@ -270,32 +279,16 @@ function getDeserializeJavascriptCode(result: SerializedResult, options: Interna
270279 endTag : ET = DefaultEndTag ,
271280 variablePrefix : VP = VariablePrefix ,
272281 closure,
273- enablePatches = true ,
274- isPrint,
282+ isPrinting,
275283 } = options ?? { } ;
276284 const { source : sourceCode , patches, descriptors, types } = result ;
277285 // console.log('deserializeJavascript', str, sourceCode);
278- const escapeSingleQuote = ( str : string ) => str . replace ( / ' / g, isPrint ? "\\\\'" : "\\'" ) ;
286+ const escapeSingleQuote = ( str : string ) => str . replace ( / ' / g, isPrinting ? "\\\\'" : "\\'" ) ;
279287 const content = `${ closure ? `const { ${ Object . keys ( closure ?? { } ) . join ( ', ' ) } } = ${ VP } context || {};` : '' }
280288 const { get } = ${ VP } options;
281289 const deserializeResult = (\n${ decodeFormat ( sourceCode , { startTag : ST , endTag : ET } ) } \n);
282290 const types = ${ decodeFormat ( JSON . stringify ( types ) , { startTag : ST , endTag : ET } ) } ;
283- const patches = ${
284- enablePatches
285- ? decodeFormat (
286- JSON . stringify (
287- patches . map ( ( { path, ref } ) => {
288- // replace the context with ref
289- return {
290- path,
291- context : ref ,
292- } ;
293- } )
294- ) ,
295- { startTag : ST , endTag : ET }
296- )
297- : '[]'
298- } ;
291+ const patches = ${ decodeFormat ( JSON . stringify ( patches ) , { startTag : ST , endTag : ET } ) } ;
299292 const descriptors = ${ decodeFormat (
300293 JSON . stringify (
301294 descriptors . map ( ( d ) => ( {
@@ -325,7 +318,7 @@ function getDeserializeJavascriptCode(result: SerializedResult, options: Interna
325318 function restoreOriginalTypes(obj, types = []) {
326319 // Apply types to the deserialized object
327320 types.forEach(({ path, type, metadata }) => {
328- const value = path && path.length ? get(obj, path) : obj ;
321+ const value = get(obj, path);
329322 const keyName = path && path.length ? path[path.length - 1] : undefined;
330323 const parent = path && path.length ? get(obj, path.slice(0, -1)) : null;
331324 if (value && parent && parent[keyName] === value) {
@@ -367,7 +360,7 @@ function getDeserializeJavascriptCode(result: SerializedResult, options: Interna
367360 function restorePatches(obj, patches = []) {
368361 // Apply patches to the deserialized object
369362 patches.forEach(({ path, context }) => {
370- const sourceObj = path && path.length ? get(obj, path) : obj ;
363+ const sourceObj = get(obj, path);
371364 if (sourceObj) {
372365 const sourceKeys = getFullKeys(sourceObj);
373366 getFullKeys(context).forEach((key) => {
@@ -384,12 +377,12 @@ function getDeserializeJavascriptCode(result: SerializedResult, options: Interna
384377 if (typeof obj === 'object') {
385378 Object.keys(obj).forEach((key) => {
386379 if (
387- key.match(new RegExp('^${ escapeRegExp ( SymbolKeyRegExps [ 0 ] , { escapeTwice : isPrint , format : escapeSingleQuote } ) } $')) ||
388- key.match(new RegExp('^${ escapeRegExp ( SymbolKeyRegExps [ 1 ] , { escapeTwice : isPrint , format : escapeSingleQuote } ) } $'))
380+ key.match(new RegExp('^${ escapeRegExp ( SymbolKeyRegExps [ 0 ] , { escapeTwice : isPrinting , format : escapeSingleQuote } ) } $')) ||
381+ key.match(new RegExp('^${ escapeRegExp ( SymbolKeyRegExps [ 1 ] , { escapeTwice : isPrinting , format : escapeSingleQuote } ) } $'))
389382 ) {
390383 const symbolExpr = key
391- .replace(new RegExp('^${ escapeRegExp ( SymbolKeyPrefixRegExp , { escapeTwice : isPrint } ) } '), '')
392- .replace(new RegExp('${ escapeRegExp ( SymbolKeySuffixRegExp , { escapeTwice : isPrint } ) } $'), '');
384+ .replace(new RegExp('^${ escapeRegExp ( SymbolKeyPrefixRegExp , { escapeTwice : isPrinting } ) } '), '')
385+ .replace(new RegExp('${ escapeRegExp ( SymbolKeySuffixRegExp , { escapeTwice : isPrinting } ) } $'), '');
393386 const symbolKey = new Function('return ' + symbolExpr)();
394387 obj[symbolKey] = obj[key];
395388 delete obj[key];
@@ -407,7 +400,7 @@ function getDeserializeJavascriptCode(result: SerializedResult, options: Interna
407400 function restoreDescriptors(obj, descriptors = []) {
408401 // Apply descriptors to the deserialized object
409402 descriptors.forEach(({ ownerPath, key, descriptor: sourceDescriptor }) => {
410- const owner = ownerPath && ownerPath.length ? get(obj, ownerPath) : undefined ;
403+ const owner = get(obj, ownerPath);
411404 if (owner) {
412405 const value = owner[key];
413406 const copied = { ...sourceDescriptor };
@@ -522,26 +515,38 @@ function expandPrototypeChainRecursively(
522515 if ( typeof key === 'symbol' ) {
523516 key = getSymbolFieldName ( key ) ?? '' ;
524517 }
525- const copied = {
526- ...descriptor ,
527- get : descriptor . get ? stringToBase64 ( serializeFunction ( descriptor . get . toString ( ) ) ! ) : undefined ,
528- set : descriptor . set ? stringToBase64 ( serializeFunction ( descriptor . set . toString ( ) ) ! ) : undefined ,
529- } ;
530- delete copied . value ;
518+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
519+ const { value : _value , ...copied } = descriptor ;
520+ const result = copied as DescriptorMeta [ 'descriptor' ] ;
521+ if ( descriptor . get ) {
522+ result . get = stringToBase64 ( serializeFunction ( descriptor . get . toString ( ) ) ! ) ;
523+ }
524+ if ( descriptor . set ) {
525+ result . set = stringToBase64 ( serializeFunction ( descriptor . set . toString ( ) ) ! ) ;
526+ }
531527 descriptors . push ( {
532528 ownerPath : paths ,
533529 key,
534- descriptor : copied ,
530+ descriptor : result ,
535531 } ) ;
536532 }
537533 } ;
538534 const assign = ( source : Record < string | symbol , any > ) => {
539- const sourceDescriptors = Object . getOwnPropertyDescriptors ( proto ) ;
535+ const sourceDescriptors = Object . getOwnPropertyDescriptors ( source ) ;
540536 getFullKeys ( source ) . forEach ( ( key ) => {
541537 const descriptor = sourceDescriptors [ key ] ;
542538 const destDescriptor = destDescriptors [ key as string ] ;
543- // If the descriptor is not readable, skip it
539+ let index : number ;
540+ // Ignore array length and indecies
541+ if (
542+ Array . isArray ( source ) &&
543+ typeof key === 'string' &&
544+ ( key === 'length' || ( ( index = Number ( key ) ) >= 0 && index < source . length ) )
545+ ) {
546+ return ;
547+ }
544548 if ( descriptor && ! descriptor . get && ! ( 'value' in descriptor ) ) {
549+ // If the descriptor is not readable, skip it
545550 return ;
546551 }
547552 // If the destination descriptor is not writable, skip it
@@ -551,7 +556,7 @@ function expandPrototypeChainRecursively(
551556 try {
552557 result [ key ] = source [ key ] ;
553558 } catch ( error ) {
554- // not raise error
559+ // Silent failure
555560 }
556561 checkDescriptor ( key , descriptor ) ;
557562 } ) ;
@@ -740,7 +745,6 @@ type PathType = string | number | symbol;
740745interface Patch {
741746 path : PathType [ ] ;
742747 context : any ;
743- ref ?: string ;
744748}
745749interface DescriptorMeta {
746750 ownerPath : PathType [ ] ;
@@ -804,8 +808,7 @@ export type ParseOptions = Pick<StringifyOptions, 'startTag' | 'endTag' | 'varia
804808} ;
805809
806810interface InternalParseOptions extends ParseOptions {
807- enablePatches ?: boolean ;
808- isPrint ?: boolean ;
811+ isPrinting ?: boolean ;
809812}
810813
811814export type ExpandPrototypeChainOptions = {
0 commit comments