API Docs for: v2.11.1
Show:

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;
  }
}