Code Monkey home page Code Monkey logo

concordance's Introduction

concordance

Compare, format, diff and serialize any JavaScript value. Built for Node.js 10 and above.

Behavior

Concordance recursively describes JavaScript values, whether they're booleans or complex object structures. It recurses through all enumerable properties, list items (e.g. arrays) and iterator entries.

The same algorithm is used when comparing, formatting or diffing values. This means Concordance's behavior is consistent, no matter how you use it.

Comparison details

  • Object wrappers are compared both as objects and unwrapped values. Thus Concordance always treats Object(1) as different from 1.
  • -0 is distinct from 0.
  • NaN equals NaN.
  • The Argument values can be compared to a regular array.
  • Error names and messages are always compared, even if these are not enumerable properties.
  • Function values are compared by identity only. Names are always formatted and serialized.
  • Global objects are considered equal.
  • Map keys and Set items are compared in-order.
  • Object string properties are compared according to the traversal order. Symbol properties are compared by identity.
  • Promise values are compared by identity only.
  • Symbol values are compared by identity only.
  • Recursion stops whenever a circular reference is encountered. If the same cycle is present in the actual and expected values they're considered equal, but they're unequal otherwise.

Formatting details

Concordance strives to format every aspect of a value that is used for comparisons. Formatting is optimized for human legibility.

Strings enjoy special formatting:

  • When used as keys, line break characters are escaped
  • Otherwise, multi-line strings are formatted using backticks, and line break characters are replaced by control pictures.

Similarly, line breaks in symbol descriptions are escaped.

Diffing details

Concordance tries to minimize diff lines. This is difficult with object values, which may have similar properties but a different constructor. Multi-line strings are compared line-by-line.

Serialization details

Concordance can serialize any value for later use. Deserialized values can be compared to each other or to regular JavaScript values. The deserialized value should be passed as the actual value to the comparison and diffing methods. Certain value comparisons behave differently when the actual value is deserialized:

  • Argument values can only be compared to other Argument values.
  • Function values are compared by name.
  • Promise values are compared by their constructor and additional enumerable properties, but not by identity.
  • Symbol values are compared by their string serialization. Registered and well-known symbols will never equal symbols with similar descriptions.

concordance's People

Contributors

bitjson avatar bunysae avatar exogen avatar greenkeeper[bot] avatar ninevra avatar novemberborn avatar papb avatar sindresorhus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

concordance's Issues

Support plugins

It should be possible to provide an array of plugins when describing, comparing, formatting or diffing values. Each plugin should be called when describing a complex object, before objects are mapped to the internal classes by their tag. If a plugin returns null the next plugin should be tried (if any). Otherwise the return value is used.

Plugins should be provided the Complex base class so it can extend it. Perhaps we should also provide kathryn's version so it can handle compatibility issues.

The returned value should implement all the necessary methods for comparing, formatting and diffing.

Maintenance

The following is a list of internal refactors:

  • Rewrite in TypeScript
  • Move to ESM (#83)
  • Replace the current continuation pattern with generator functions
  • Use newer JS features/syntax, e.g:
    • Object.hasOwn (available from Node.js 16.9) (#83)
    • Some more in this list
  • Remove old code (e.g. function name properties)
  • Add documentation for contributing

Original description

@novemberborn in avajs/ava#1861 (comment), you mention that Concordance is in need of some love. While the issues here are good for tracking enhancements, I think it would be good to track refactor/maintenance items in a single issue.

What are some things you think need improved? Listing them would make it easier for people to pick one and help out.

Some thoughts of my own:

  • Rewrite in ESM, use newer JS features/syntax
  • Add documentation about internals for new contributors

RangeError: 'offset' is out of bounds when comparing empty (length 0) Buffers

Test case:

const c = require('concordance');

const a = Buffer.from([]);
const b = Buffer.from([]);

console.log(c.compare(a, b));

Output:

RangeError: 'offset' is out of bounds
at RangeError (native)
at fromArrayBuffer (buffer.js:257:20)
at Function.Buffer.from (buffer.js:128:12)
at getBuffer (lib/complexValues/typedArray.js:15:25)
at describe (lib/complexValues/typedArray.js:24:13)
at describeComplex (lib/describe.js:119:22)
at c (lib/describe.js:141:12)
at describe (lib/describe.js:168:10)
at Object.compare (lib/compare.js:98:12)

Version is 3.0.0

Allow formatting depth to be controlled

When formatting or diffing, the formatting depth should be controllable. This means that when there is no difference, only a limited number of levels are printed.

Test against "any value of given type"

Hello!

My usecase is Ava's deepEqual function. In particular, I have some nested object of some sort. I'm not interested in the value of the values, but in their type. Is it possible to have something like Jest's expect.any(Boolean) for example? Or any dynamic matcher for a value?

Let say I want to check if:

{
   foo: ['a', 'b', 'c'],
   bar: {
      cat: new Cat(),
   }
}

is equal to

{
   foo: [String, String, String],
   bar: {
     cat: Cat
   }
}

That is: I'm more interested in the structure, rather than actual values (for example they are generated randomly).

Escape or replace invisible or ambiguous characters when formatting strings

Invisible characters such as zero-width joiner and non-breaking space, as well as ambiguous characters like other kinds of spaces, combining characters et cetera should be escaped when strings are formatted.

http://graphemica.com/blocks/control-pictures should be used where the behavior of the original character is preserved. This probably only applies to linebreaks.

If a simple escape sequence exist it should be used. Else characters should be escaped using the \u sequence.

When a string is formatted as a key it must not include linebreaks.

formatDescriptor() throws on certain deserialized descriptors with deeply-nested self-references

When formatDescriptor() is called on a deserialized descriptor of an object with a self-referential property at a nesting depth beyond maxDepth, it may throw a PointerLookupError.

MRE:

const value = {};
const actualDescriptor = concordance.describe({
  a: {
    b: value
  },
  c: value
});

const serializedActual = concordance.serialize(actualDescriptor);
const deserializedActual = concordance.deserialize(serializedActual);

concordance.formatDescriptor(deserializedActual, {maxDepth: 1});

This throws:

  PointerLookupError {
    index: 3,
    message: 'Could not deserialize buffer: pointer 3 could not be resolved',
  }

  › mapPointerDescriptor (node_modules/concordance/lib/serialize.js:321:67)
  › node_modules/concordance/lib/serialize.js:336:14
  › deserializeRecord (node_modules/concordance/lib/serialize.js:255:12)
  › recursor (node_modules/concordance/lib/serialize.js:264:12)
  › deserializeComplex (node_modules/concordance/lib/metaDescriptors/property.js:18:17)
  › node_modules/concordance/lib/serialize.js:336:35
  › deserializeRecord (node_modules/concordance/lib/serialize.js:267:10)
  › Object.recursor [as next] (node_modules/concordance/lib/serialize.js:264:12)
  › Object.next [as recursor] (node_modules/concordance/lib/recursorUtils.js:59:44)
  › Object.formatDescriptor (node_modules/concordance/lib/format.js:74:35)

To reproduce the issue, the following must hold:

  • The provided maxDepth is non-zero
  • The deeply-nested self-reference occurs at a depth greater than maxDepth
  • The shallow self-reference occurs at a depth at most maxDepth
  • The name of the property containing the deeply-nested self-reference is lexically less than the name of the property containing the shallow self-reference

I believe the problem to be that the descriptor is deserialized lazily, and the formatter never calls upon the deeply-nested self-referential value, so when the shallow self-reference is called upon, its pointer references a descriptor that hasn't been deserialized yet.

I first encountered this in AVA, where it can cause an error to be thrown when a snapshot assertion comparing against such a value fails.

I'm working on a PR that may fix this presently.

Error thrown in test by formatter

I get the following error during a test:

sets direct_generator option
E:\Projects\repos\elastic-builder\node_modules\concordance\lib\formatUtils.js:106

Error thrown in test:

Error {
  message: 'Formatter buffer can only take one formatted value.',
}

SingleValueFormatter.append (node_modules/concordance/lib/formatUtils.js:106:30)
format (node_modules/concordance/lib/diff.js:175:44)
Object.diffDescriptors (node_modules/concordance/lib/diff.js:338:11)
Test.setsOption (test/_macros.js:170:11)

Specifically this test - https://github.com/sudo-suhas/elastic-builder/blob/master/test/suggesters-test/phrase-suggester.test.js#L49
I am making use of macros and the test is a t.deepEqual(value, expected);. I tried to log the value and expected and they are identical:

{
  "my_suggester": {
    "phrase": {
      "direct_generator": [
        {
          "field": "title.trigram",
          "suggest_mode": "always"
        }
      ]
    }
  }
}

I can't figure out why I am getting the error.

Support snapshots

It should be possible to serialize a value into a snapshot. The snapshot needs to include a formatted representation of the value, as well as an encoded representation that can be used to compare the snapshot against a new value.

Comparison logic needs to be tweaked: Arguments objects must not match Arrays, and ambiguous symbols must now match each other.

Generator functions must be formatted as regular functions, since they're not tagged as such in Node.js 4. They should also match regular functions.

Document ArrayBuffer limitation in Node.js 4

The following throws a TypeError in Node.js 4:

const realm = vm.runInNewContext('(function () { return this })()')
Buffer.from(new realm.ArrayBuffer(8))

This means TypedArray / ArrayBuffer / DataView comparisons won't work across realms in that version. There is no efficient workaround, and it's a bit of an edge-case, so this should just be documented.

Create monorepo

Convert this to a monorepo. Official plugins like react will be easier to manage that way.

Infinite iterables cause infinite loops

concordance attempts to traverse iterables to completion, so that it can compare and/or describe their elements. This means that compare, diff, format, and serialize loop infinitely when called with infinite iterables.

This can cause AVA tests to time out, even on comparisons that can be completed in finite time, such as

const test = require('ava');

test('Comparing infinite iterables', t => {
  t.deepEqual(
    (function * () { while (true) yield; })(),
    undefined
  );
});

I'm not sure whether this is the intended behavior or not.

Support (color) themes

Consuming code should be able to provide a theme to the formatting and diffing methods. kathryn should (recursively) mix this theme into its own default theme.

Formatting code should either reference specific characters from the theme (e.g. an opening curly brace), or call a function with a formatted value (e.g. so a string can be colored).

It might be neat to use tagged template literals.

By default there should be no color output, or indeed any ANSI output, including the underlines currently used in string diffs.

Sparse arrays are treated like arrays of undefined

concordance treats empty slots in arrays like undefined, for both formatting and comparison.

format(new Array(5)) gives

[
  undefined,
  undefined,
  undefined,
  undefined,
  undefined,
]

whereas util.inspect(new Array(5)) gives [ <5 empty items> ]

compare(new Array(5), Array.from({length: 5}) returns true, although these values behave rather differently.

Add support for BigInt as a primitive

Thanks for the awesome work on this library! It's been fantastic. Do you have any plans for supporting BigInt?

The following AVA test generates an error in Concordance (Node v10.10.0):

  t.deepEqual(
    {
      a: BigInt(0)
    },
    {
      b: BigInt(0)
    }
  );

Error:

/[project]/node_modules/concordance/lib/Registry.js:20

  Error thrown in test:

  TypeError {
    message: 'Invalid value used as weak map key',
  }

  Registry.alloc (node_modules/concordance/lib/Registry.js:20:14)
  describeComplex (node_modules/concordance/lib/describe.js:102:28)
  curriedComplex (node_modules/concordance/lib/describe.js:141:12)
  Object.describeAny (node_modules/concordance/lib/describe.js:148:9)
  Object.next (node_modules/concordance/lib/complexValues/object.js:107:48)
  Object.next (node_modules/concordance/lib/recursorUtils.js:59:44)
  Object.recursor (node_modules/concordance/lib/complexValues/object.js:185:31)
  compareDescriptors (node_modules/concordance/lib/compare.js:70:32)
  Object.compare (node_modules/concordance/lib/compare.js:100:16)

Improve formatting of symbol descriptions

Symbol descriptions are currently formatted as-is. If they contain linebreaks they'll disrupt the formatting output. Invisible or ambiguous characters aren't escaped either.

At the very least characters should be escaped, like #4. Perhaps linebreaks should be preserved in the output (it ought to be technically possible), but it's probably simpler to just escape them. Note that when used as a key a symbol shouldn't span multiple lines.

deepEqual arrays if their key changed as an object

I recently write some test using AVA, something I have encountered like this below:

test('Array', t => {
  const arr1 = [1,2,3]
  const arr2 = arr1.slice()
  // normally we don't use array like this
  // but sometimes we might reach out of the array boundary unexpectedly
  for (let i = -1; i > -10; i--) {
    arr2[i] = 111
  }
  console.log(arr1, arr2)
  t.deepEqual(arr1, arr2)
})

The result is:
image

I know the arr1 and arr2 has the same items and length as arrays, but array is also object. However, the keys of object changed unexpectedly might indicate that I have write something wrong. In that case, I got passed test and know nothing about it.

How I can compare two array also as an object? I can only figure out a workaround using two assertions like this (only deal with limited situations):

t.deepEqual(arr1, arr2)
t.deepEqual(Object.keys(arr1), Object.keys(arr2))

String diffs don't invert properly

Issuehunt badges

In AVA, when diffing snapshots the gutters are inverted. This doesn't invert the string diff colors though. Compare the output for these tests:

import test from 'ava'

test('snapshot diff', t => {
  t.snapshot(`\n${Date.now()}\n`, 'the - value should be less than the + value')
})

test('direct diff', t => {
  t.is(`\n${Date.now() - 42e5}\n`, `\n${Date.now()}\n`)
})

screen shot 2017-10-23 at 15 48 57

I realized this previously but hadn't yet filed the issue. Example via avajs/ava#1558.


IssueHunt Summary

ninevra ninevra has been rewarded.

Backers (Total: $40.00)

Submitted pull Requests


Tips

Cleaner diffs for inserted array items

Isolated test case as requested in avajs/ava#1521

If you append an item to an array and diff:

var concordance = require('concordance');
const orig = [
  'foo',
  'bar',
  'fizz',
  'buzz'
];
const copy = Array.from(orig);
copy.push('hi')
concordance.diff(orig, copy);

You get neat output:

  [
    'foo',
    'bar',
    'fizz',
    'buzz',
+   'hi',
  ]

However if you insert anywhere else and diff:

var concordance = require('concordance');
const orig = [
    'foo',
    'bar',
    'fizz',
    'buzz'
];
const copy = Array.from(orig);
copy.unshift('hi')
concordance.diff(orig, copy);

The output is quite hard to follow after the inserted item:

  [
-   'foo',
+   'hi',
-   'bar',
+   'foo',
-   'fizz',
+   'bar',
-   'buzz',
+   'fizz',
+   'buzz',
  ]

Format extra level of extraneous / missing complex items when depth limit is reached

Issuehunt badges

avajs/ava#1850

Complex items are often not understandable without seeing their properties or (if they're lists or iterables) nested items. If the depth limit is reached we should still format an extra level, so rather than

  [
+   Object { … },
    Object { … },
  ]

we could print:

  [
+   {
+     id: 'first',
+   },
    {
      id: 'second',
    },
  ]

We'll have to consider whether this is a violation of the "max depth" concept. I have a feeling we already do this elsewhere though.

Printing all items at an extra level may be unnecessary.


IssueHunt Summary

bunysae bunysae has been rewarded.

Backers (Total: $60.00)

Submitted pull Requests


Tips

Crash comparing multi-line strings

Originally reported in avajs/ava#1935, comparing these two strings crashes:

`<table>
    <tr>
      <td>undefined</td>
      <td>3</td>
    </tr>
</table>
`
`<table>
    <tr>
      <td>3</td>
      <td>4</td>
    </tr>
</table>`
 Error thrown in test:

  TypeError {
    message: 'Cannot read property \'substring\' of undefined',
  }

  diff_main (node_modules/fast-diff/diff.js:63:17)
  diffLine (node_modules/concordance/lib/primitiveValues/string.js:65:19)
  StringValue.diffDeep (node_modules/concordance/lib/primitiveValues/string.js:271:24)
  Object.diffDescriptors (node_modules/concordance/lib/diff.js:307:17)
  Test.is (test/222.test.js:17:5)

Note the first string has a newline after </table>. The error occurs on this line:

const result = diffLine(theme, actualLines[actualIndex], expectedLines[expectedIndex])

Presumably expectedLines[expectedIndex] is the undefined one. This should have been picked up as "actual-is-extraneous". Why it isn't requires investigation.

Error thrown on `Proxy`s with undescribed own properties

compare(), format(), serialize(), and diff() throw an error when called on objects which have own properties with no property descriptors. (As far as I know, the only such objects are Proxys.)

concordance assumes that, if Object.getOwnPropertyNames(input) returns e.g. ['name'], then Object.getOwnPropertyDescriptor(input, 'name') will return a property descriptor. This is true for non-Proxy inputs, but can be false for Proxys, which in most cases don't have to respect any relation between the ownKeys and ownPropertyDescriptor operations.

This can lead to throwing

TypeError {
  message: 'Cannot read property \'enumerable\' of undefined',
}

at

if (accept && Object.getOwnPropertyDescriptor(obj, name).enumerable) {

I encountered this when I accidentally tried to snapshot a jsdom Window object, which apparently has some ownKeys that lack descriptors.

I'm not sure whether there's a better way to handle this. The "value" of the property can still be retrieved with e.g. Reflect.get(), so that could be used for comparison; but enumerability and other property attributes are strange.

As far as I can tell, undescribed properties do not behave identically to any valid property descriptor, nor to the absence of a property. They are not themselves listed in enumerations, but neither do they mask the presence of enumerable prototype properties, as truly unenumerable properties do. They may or may not satisfy Reflect.has(object, property).

Add option to always format error messages

Concordance ignores non-enumerable properties. AVA uses Concordance to format caught errors. If a custom error is created with a non-enumerable message then this message is not included in the results.

IIRC we already handle name properties of errors, so we could include non-enumerable message properties by default (this would be a breaking change) or by configuration.

See also avajs/ava#2755.

Adding iterator to binary tree structure breaks representation

This is related to avajs/ava#2811

Here is simple reproducation:

const concordance = require('concordance');


function Pair(car, cdr) {
  this.car = car;
  this.cdr = cdr;
}

function Nil() {}
var nil = new Nil();


var x = new Pair(
    new Pair(
        new Pair(
            10,
            new Pair(
                20,
                nil
            )
        ),
        nil
    ),
    nil
);


let data = concordance.describe(x);
console.log(concordance.format(data));



Pair.prototype[Symbol.iterator] = function() {
    var node = this;
    return {
        next: function() {
            var cur = node;
            node = cur.cdr;
            if (cur === nil) {
                return { value: undefined, done: true };
            } else {
                return { value: cur.car, done: false };
            }
        }
    };
};

data = concordance.describe(x);
console.log(concordance.format(data));

Here is the output:

@Object {
  ctor: 'Pair',
  describeAny: Function describeAny {},
  describeItem: Function describeItem {},
  describeMapEntry: Function describeMapEntry {},
  describeProperty: Function describeProperty {},
  isArray: false,
  isIterable: false,
  isList: false,
  iterableState: null,
  listState: null,
  pointer: 1,
  propertyState: null,
  stringTag: 'Object',
  value: Pair {
    car: Pair {
      car: Pair {
        car: 10,
        cdr: Pair {
          car: 20,
          cdr: Nil {},
        },
      },
      cdr: Nil {},
    },
    cdr: Nil {},
  },
}
@Object {
  ctor: 'Pair',
  describeAny: Function describeAny {},
  describeItem: Function describeItem {},
  describeMapEntry: Function describeMapEntry {},
  describeProperty: Function describeProperty {},
  isArray: false,
  isIterable: true,
  isList: false,
  iterableState: null,
  listState: null,
  pointer: 1,
  propertyState: null,
  stringTag: 'Object',
  value: Pair {
    car: Pair {
      car: Pair {
        car: 10,
        cdr: Pair {
          car: 20,
          cdr: Nil {},
          ---
          20,
        },
        ---
        10,
        20,
      },
      cdr: Nil {},
      ---
      Pair {
        car: 10,
        cdr: Pair {
          car: 20,
          cdr: Nil {},
          ---
          20,
        },
        ---
        10,
        20,
      },
    },
    cdr: Nil {},
    ---
    Pair {
      car: Pair {
        car: 10,
        cdr: Pair {
          car: 20,
          cdr: Nil {},
          ---
          20,
        },
        ---
        10,
        20,
      },
      cdr: Nil {},
      ---
      Pair {
        car: 10,
        cdr: Pair {
          car: 20,
          cdr: Nil {},
          ---
          20,
        },
        ---
        10,
        20,
      },
    },
  },
}

Improve focus of multi-line string diffs when there are loads of lines

See discussion: avajs/ava#2665

When comparing two strings that are many lines long, the diff output should focus on the lines that are actually different, not the potentially dozens or hundreds of lines that are the same.

  1. If the diff is longer than, say, 30 lines, divide it into sections of changes and non-changes.
  2. If the non-change sections are 5 lines or less, merge the surrounding change sections into one larger change section.
  3. For the sections with changes, provide 5 lines of context before and after the actual change. Take 5 lines from the preceding and succeeding non-change sections, if any. Due to step 2, these sections must be larger than 5 lines.
  4. Prefix the change sections with a hunk heading @@ -l, +l @@, where the line numbers l correspond to the - and + sides of the diff.
  5. Print the change sections, prefixed with their heading, and separated with an empty line between them.

Out of memory crash when objects have a large length field unrelated to array size

While writing tests for GraphBrainz I noticed that my latest test was consistently crashing AVA. Running the single test alone was enough to cause an OOM error, always in concordance.serialize, and the object I was snapshotting was not large by any means.

I narrowed it down to the length field on my objects. This field has nothing to do with array lengths, rather the meaning in this context is a recording length in milliseconds.

[
  {
    title: "Airbag",
    length: 284400
  },
  {
    title: "Paranoid Android",
    length: 383493
  },
  // …more…
]

Concordance seems to be assigning some special meaning to these length fields and allocating memory based on them.

Try this and you'll notice it takes quite a long time and uses a lot of memory:

> concordance = require('concordance');
> concordance.serialize(concordance.describe({ length: 12345678 }));

It's possible this could be the cause of several of the OOM bug reports opened for AVA.

Stack trace
==== JS stack trace =========================================

    0: ExitFrame [pc: 0x3241121dc01d]
Security context: 0x3f5ee919e681 <JSObject>
    1: encode [0x3f5ecb13e4a1] [/Users/brianbeck/Projects/graphbrainz/node_modules/concordance/lib/encoder.js:~177] [pc=0x3241125889c2](this=0x3f5ecfec66f9 <Object map = 0x3f5eefa91039>,serializerVersion=2,rootRecord=0x3f5ecb13e771 <Object map = 0x3f5eefa94319>,usedPlugins=0x3f5ecb145bf9 <Map map = 0x3f5e362045c1>)
    2: serialize [0x3f5ecb102e21] [/Users/b...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x100039dbf node::Abort() [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 2: 0x100039fc9 node::OnFatalError(char const*, char const*) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 3: 0x1001d1375 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 4: 0x10059c572 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 5: 0x10059f045 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 6: 0x10059aeef v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 7: 0x1005990c4 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 8: 0x1005995c5 v8::internal::Heap::CollectAllAvailableGarbage(v8::internal::GarbageCollectionReason) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
 9: 0x1005a5a21 v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationSpace, v8::internal::AllocationAlignment) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
10: 0x100574da6 v8::internal::Factory::NewFixedArrayWithFiller(v8::internal::Heap::RootListIndex, int, v8::internal::Object*, v8::internal::PretenureFlag) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
11: 0x10051c2de v8::internal::(anonymous namespace)::ElementsAccessorBase<v8::internal::(anonymous namespace)::FastPackedObjectElementsAccessor, v8::internal::(anonymous namespace)::ElementsKindTraits<(v8::internal::ElementsKind)2> >::GrowCapacity(v8::internal::Handle<v8::internal::JSObject>, unsigned int) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
12: 0x1007b6f9f v8::internal::Runtime_GrowArrayElements(int, v8::internal::Object**, v8::internal::Isolate*) [/Users/brianbeck/.nvm/versions/node/v10.10.0/bin/node]
13: 0x3241121dc01d
Abort trap: 6

Descriptors should behave the same even if recursed multiple times

Recursors should retain their state. If a new recursion is started they should provide the same values as they did in a previous recursion.

This is useful because comparisons halt recursion as soon as a difference is found. The descriptors may then be used to generate a diff. The diff should reflect the difference found when comparing, so the recursors need to retain state.

Allow number of properties / items shown to be controlled

Issuehunt badges

When formatting or diffing, if there is no difference, it should be possible to control how many properties or items are shown. This helps reduce unnecessary output.


IssueHunt Summary

Sponsors (Total: $60.00)

Become a sponsor now!

Or submit a pull request to get the deposits!

Tips

Escape backticks in multi-line strings

Issuehunt badges

Looking at https://github.com/zeit/styled-jsx/pull/272/files#diff-fc22e4f5884dfd2b8e45d855ee51f1bcR62, the backticks in new String() ought to be escaped.


IssueHunt Summary

ninevra ninevra has been rewarded.

Backers (Total: $40.00)

Submitted pull Requests


Tips

Readme: example of diff output

The docs say "Concordance strives to format every aspect of a value that is used for comparisons. Formatting is optimized for human legibility", but never give any examples of diff output - I'm a lazy person just browsing around libraries on Github, so I'm not motivated enough to install the library and poke at it in the REPL, but I am curious as to what the library does.

Examples of human-readable object/value diffing in the readme would be useful.

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.