#

API Docs for: v2.11.1
Show: Inherited Protected Private Deprecated

# File: packages/ember-runtime/lib/compare.js

    import { typeOf } from './utils';
    import Comparable from './mixins/comparable';

    const TYPE_ORDER = {
      'undefined': 0,
      'null': 1,
      'boolean': 2,
      'number': 3,
      'string': 4,
      'array': 5,
      'object': 6,
      'instance': 7,
      'function': 8,
      'class': 9,
      'date': 10
    };

    //
    // the spaceship operator
    //
    //                      `. ___
    //                     __,' __`.                _..----....____
    //         __...--.'``;.   ,.   ;``--..__     .'    ,-._    _.-'
    //   _..-''-------'   `'   `'   `'     O ``-''._   (,;') _,'
    // ,'________________                          \`-._`-','
    //  `._              ```````````------...___   '-.._'-:
    //     ```--.._      ,.                     ````--...__\-.
    //             `.--. `-` "INFINITY IS LESS     ____    |  |`
    //               `. `.   THAN BEYOND"        ,'`````.  ;  ;`
    //                 `._`.        __________   `.      \'__/`
    //                    `-:._____/______/___/____`.     \  `
    //                                |       `._    `.    \
    //                                `._________`-.   `.   `.___
    //                                              SSt  `------'`
    function spaceship(a, b) {
      let diff = a - b;
      return (diff > 0) - (diff < 0);
    }

    /**
     Compares two javascript values and returns:

      - -1 if the first is smaller than the second,
      - 0 if both are equal,
      - 1 if the first is greater than the second.

      ```javascript
      Ember.compare('hello', 'hello');  // 0
      Ember.compare('abc', 'dfg');      // -1
      Ember.compare(2, 1);              // 1
      ```

     If the types of the two objects are different precedence occurs in the
     following order, with types earlier in the list considered `<` types
     later in the list:

      - undefined
      - null
      - boolean
      - number
      - string
      - array
      - object
      - instance
      - function
      - class
      - date

      ```javascript
      Ember.compare('hello', 50);       // 1
      Ember.compare(50, 'hello');       // -1
      ```

     @method compare
     @for Ember
     @param {Object} v First value to compare
     @param {Object} w Second value to compare
     @return {Number} -1 if v < w, 0 if v = w and 1 if v > w.
     @public
    */
    export default function compare(v, w) {
      if (v === w) {
        return 0;
      }

      let type1 = typeOf(v);
      let type2 = typeOf(w);

      if (Comparable) {
        if (type1 === 'instance' && Comparable.detect(v) && v.constructor.compare) {
          return v.constructor.compare(v, w);
        }

        if (type2 === 'instance' && Comparable.detect(w) && w.constructor.compare) {
          return w.constructor.compare(w, v) * -1;
        }
      }

      let res = spaceship(TYPE_ORDER[type1], TYPE_ORDER[type2]);

      if (res !== 0) {
        return res;
      }

      // types are equal - so we have to check values now
      switch (type1) {
        case 'boolean':
        case 'number':
          return spaceship(v, w);

        case 'string':
          return spaceship(v.localeCompare(w), 0);

        case 'array':
          let vLen = v.length;
          let wLen = w.length;
          let len = Math.min(vLen, wLen);

          for (let i = 0; i < len; i++) {
            let r = compare(v[i], w[i]);
            if (r !== 0) {
              return r;
            }
          }

          // all elements are equal now
          // shorter array should be ordered first
          return spaceship(vLen, wLen);

        case 'instance':
          if (Comparable && Comparable.detect(v)) {
            return v.compare(v, w);
          }
          return 0;

        case 'date':
          return spaceship(v.getTime(), w.getTime());

        default:
          return 0;
      }
    }