Giter Club home page Giter Club logo

microdiff's Issues

Inconsistent diff Behavior for Object-derived Type Changes

Issue Summary:

The diff function exhibits inconsistent behavior when comparing changes between properties of different Object-derived types such as Array, Set, Map, etc. It appears to misidentify certain type changes as property additions/removals rather than recognizing a complete change in the property's type.

Example:

const changes = diff({ data: [] }, { data: { val: 'test' } });
// Returned: [ { type: 'CREATE', path: ['data', 'val'], value: 'test' } ]
// Expected: [ { type: 'CHANGE', path: ['data'], value: { val: 'test' } } ]

Description of the bug:

When the diff function encounters property values that have changed type—specifically from an Array, Set, Map, Error, Promise, or Proxy to another object type—it incorrectly reports the changes as individual property mutations (CREATE and REMOVE) rather than recognizing a CHANGE in the entire value for the key.

For types such as Function, Date, and RegExp, when these are nested property values, the change is correctly detected as a CHANGE. However, when types like Array, Set, or Map are nested, they do not receive the same treatment.

Additional Context:

There's a discrepancy based on whether the Object-derived types are passed directly as an argument to diff or nested. For example:

const diffArgument = diff(new Date(), { data: 'test' });
// Returned: [ { type: 'CREATE', path: ['data'], value: 'test' } ]

const diffObjValue = diff({ data: new Date() }, { data: { val: 'test' } });
// Returned: [ { type: 'CHANGE', path: ['data'], value: { val: 'test' }, oldValue: '2023-11-06T02:40:05.198Z' }]

It is not clear if this behavior is intentional or an oversight. Clarification in the documentation would be beneficial.

Extend the diff function with rich types not included in the base JS language.

❗ Is your feature request related to a problem? Please describe.
We use started using microdiff as a pre-step before doing db updates. When working with MongoDB, then use the ObjectId data type which is exported by the bson package to keep track of documents (records) and references between data.
It can be compared in JS using the toString() (or casting it to string).

However, currently microdiff compares it as an object and because the object has no properties (only methods), it can not identify the change.

✅ Describe the solution you'd like
In order for us to solve this issue and have microdiff detect changes to properties that are ObjectId, we needed to duplicate the function to our code base and extend the rich types object with the ObjectId: true property to have it trigger the "rich type" check and be evaluated as two strings being compared with each other.

↗️ Describe alternatives you've considered
I would recommend adding a property to the third argument of the function where cyclesFix can be passed in. This would be an object of extended rich types which then also need to be checked while calling the diff function.

➕ Additional context
Other data types in JS which have a compatible (to String) method of comparing them can be added to this and thus we can still use the microdiff library without having to duplicate the functionality.

CommonJS support

I'm trying to require('microdiff') but it throws ERR_REQUIRE_ESM. I'm using Node.js 12. Don't you think CommonJS should still be supported?

Add Code of Conduct

We recommend that every repo has a code of conduct. If you don’t feel comfortable creating your own Code of Conduct from scratch we highly recommend using one of the templates provided by GitHub. If you do use a template, please read through the template and ensure that you can and will abide by the Code of Conduct.

Please follow these instructions on how to add a Code of Conduct.

Does not handle object changes within array

import diff from "microdiff";

const obj1 = {
	array:[{test2:0}]
};
const obj2 = {
	array:[{test2:1}]
};

console.log(diff(obj1, obj2));

This ^ console logs an empty array. (repl)

Are there any plans on supporting objects within arrays? If no, do you know about another library that do support this?

Community Exchange Introduction/Tracking

👋 Hi @AsyncBanana,

I am your GitHub mentor for the GitHub Education, Community Exchange (CX) project. I'll be collaborating with you on preparing your repo for CX.

You mentioned in your submission that you wanted to submit a Collaborate repo. This means that you want to invite other students to collaborate and add features to this repo. I will generate issues, which will provide guidance on how to prepare your repo for a Collaborate CX submission on June 1, 2022.

This issue will serve as a tracking issue to track all issues related to CX. I recommend creating a new branch for every issue and opening a pull request to track changes so we can effectively collaborate with each other and merge changes when you and I feel like those changes are ready to be merged on your primary branch.

If you have any questions or concerns, please feel free to leave a comment on this issue or any of the other issues that are generated.

I look forward to working with you :octocat:

Issues

Is it possible to see the old value?

Hello, it would be very nice to be able to see the old value in a CHANGE operation. Is it already possible? If not I think it would be easy to add right?

get array removals as "DELETE"

Hey, first of all, great little tool!
But I have a question: I have two arrays, and I want to see if something gets updated, or removed or added to the array.
In both arrays are JS Objects, and if on of the JS objects is removed, I want that the libary tells met that one thing got removed, out of one array, but instead what is happening is that I get a "change" for every entry because the index of the other objects has changed. Is there a way to realise this?

support for NaN values

Currently, NaN values always result in CHANGE, even though nothing changed. Technically in JS, NaN !== NaN, so I understand that there is an argument for this behavior. However, I think that having a CHANGE entry on EVERY diff when an object contains NaN is noise, and therefore unexpected / undesirable behavior.

I propose treating NaN values as equivalent, resulting in the following:

diff({ testNaN: NaN }, { testNaN: NaN }) === [] // true

UMD bundle

Good day, and thanks for such awesome library! Are you planning to add separate builds like many other libraries do? I use your library for development under an old browser that doesn't support CommonJS format, and I constantly have to do custom UMD builds using rollup or other tools. It will be nice if you can add separate builds and possibly links to the CDN. I can try PR and implement it myself, but I'm very busy right now.

Recreation from diff

Hey!

I'm currently considering to use microdiff for my project, however I also have to be able to recreate an object from the diff and the source object (basically so that im able to send smaller-sized updates to a client state via a websocket connection), but it seems like microdiff is not offering any method for this. I will implement this in my project but I would like to know if this is in the ToDo.

How about having index path for array be a number instead of a string?

<script>
import diff from "microdiff";

const array1 = [1];
const array2 = [2];
	
	
const obj1 = {0:1};
const obj2 = {0:2};

</script>

{JSON.stringify(diff(array1,array2))}
<br/>
{JSON.stringify(diff(obj1,obj2))}

Both diffs give the same result, which could be problematic:

[{"path":["0"],"type":"CHANGE","value":2}]
[{"path":["0"],"type":"CHANGE","value":2}]

(repl)

My proposal is to differenciate between object and array by having array indexes be a number instead of a string, so that the result would be this instead:

[{"path":[0],"type":"CHANGE","value":2}]
[{"path":["0"],"type":"CHANGE","value":2}]

So the path array will have this type:

 Array<string | number>

This would make it easier to create a patching function too

Possible optimization: hashing

Leverage hashing for detecting change much much faster than a deep comparison?
And microdiff would have optionally a backing buffer/cache of previous object hashes?

Circular references

I don't think this should be supported, because of the extra overhead either in performance or in API complexity, but I think the documentation should state clearly that it's not handled. I mean, reading the code this is obvious, but it would still be a good service :)

P.s. do you align with the handmade manifesto? If you haven't heard of it, do check it out, because it seems you do! 😊🙌

Cheers

Cannot use 'in' operator to search for ... in null

const diff = require('microdiff').default
const a1 = {"a": { "b": 1 }}
const a2 = {"a": null}
console.log(diff(a1, a2))
/Users/.../node_modules/microdiff/dist/index.cjs:8
		if (!(key in newObj)) {
		          ^

TypeError: Cannot use 'in' operator to search for 'b' in null

Ineficient change detection

I need to detect as few changes as possible, however instead of one change I get a couple.

const changes = diff(['0', { a: 1 }], ['0', '1', { a: 1 }])

const expected = [ { type: 'CREATE', path: [ 1 ], value: '1' }]

const actual = [
  { path: [ 1 ], type: 'CHANGE', value: '1', oldValue: { a: 1 } },
  { type: 'CREATE', path: [ 2 ], value: { a: 1 } }
]

Is it expected behaviour? I have to use a double for loop to merge these changes back - that is not good for performance

Update README.md

Your README is in great shape! 🎉

I would recommend adding:

Depending on the complexity of your project, you might be interested in creating a CONTRIBUTING.md file, but we recommend starting simple with the bullet points above, and once you start to see an increase in users interested in contributing, you should consider a CONTRIBUTING.md file so you don’t find yourself overwhelmed with questions from other users.

➕ Feature - Export DIFFERENCE Type so it can be imported in Ts projects

❗ Is your feature request related to a problem? Please describe.
Yes. I cannot use the ReturnType in Typescript because it fails with this error:

Exported variable 'myFn' has or is using name 'DifferenceCreate' from external module "node_modules/microdiff/dist/index" but cannot be named.ts(4023)

✅ Describe the solution you'd like
I believe simply exporting all the types would be sufficient, or putting them under the "microdiff" module.

↗️ Describe alternatives you've considered
None yet

➕ Additional context
This happens with Typescript 4.9

Cheers!

Loops / infinite recursion

If you try to diff structures that have a loop in it, your diff algorithm will hang and enter infinite recursion and therefore exhaust system resources until the tab or the process hangs.

Add templates for issues

Issue templates are very helpful for a collaboration repo. When users identify a bug or want to add a new feature, you can provide templates so you can collect all the pertinent information you need to fix a bug or add a new feature.

We recommend creating a “Report Bug” and “Feature Request” issue template.

Some suggested prompts/questions you can add to a “Report Bug” template are:

  • Briefly describe the bug
  • What is the expected behavior?
  • Please provide step by step instructions on how to reproduce the bug

Some suggested prompts/questions you can add to a “Feature Request” issue template are:

  • Briefly describe your feature request
  • What problem is this feature trying to solve?
  • How do we know when the feature is complete?

Thanks

this is extractly what i need, i had a protocol impl before, but not completed like yours. i decide to use your version to build a small website

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.