Skip to content

uneval custom serializer can cause duplicates objects (identity breaks) #158

Description

@lucacasonato

Given a serializer like this:

class Wrapper {
  constructor(inner) {
    this.inner = inner
  }
}
const y = { hello: "world" }
const serialized = uneval({ x: new Wrapper(y), y }, (value, uneval) => {
  if (value instanceof Wrapper) {
    return `new Wrapper(${uneval(value.inner)
  }
})

const deserialized = eval(s);
// deserialized.y !== deserialized.x.inner -- these should be the same, they have the same object identity on the input!

The reason this breaks, is because for custom serializers, uneval does not do a walk + stringify, but instead does a direct stringify. This means that inner values are not counted in counts, which causes them to not get deduped.

There is an API-compatibility preserving fix here, which is to call replacer twice (once to walk and once to actually stringify). In the first call to talk, the uneval function passed to it would be the reference walk. Based on whether walk was called or not, we can also skip the second call to the replacer for most scenarios.

I will work on a patch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions