UNPKG

ember-source

Version:

A JavaScript framework for creating ambitious web applications

167 lines (152 loc) 5.22 kB
import typeOf from './type-of.js'; import '../../-internals/runtime/lib/mixins/registry_proxy.js'; import '../../-internals/runtime/lib/mixins/container_proxy.js'; import Comparable from '../../-internals/runtime/lib/mixins/comparable.js'; import '../../-internals/runtime/lib/mixins/action_handler.js'; import '../../-internals/runtime/lib/mixins/-proxy.js'; import '../../enumerable/mutable.js'; import '../../-internals/runtime/lib/mixins/target_action_support.js'; import '../../-internals/runtime/lib/ext/rsvp.js'; import '../../debug/index.js'; import { isDevelopingApp } from '@embroider/macros'; import { assert } from '../../debug/lib/assert.js'; 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, regexp: 11, filelist: 12, error: 13 }; // // the spaceship operator // // `. ___ // __,' __`. _..----....____ // __...--.'``;. ,. ;``--..__ .' ,-._ _.-' // _..-''-------' `' `' `' O ``-''._ (,;') _,' // ,'________________ \`-._`-',' // `._ ```````````------...___ '-.._'-: // ```--.._ ,. ````--...__\-. // `.--. `-` "INFINITY IS LESS ____ | |` // `. `. THAN BEYOND" ,'`````. ; ;` // `._`. __________ `. \'__/` // `-:._____/______/___/____`. \ ` // | `._ `. \ // `._________`-. `. `.___ // SSt `------'` function spaceship(a, b) { // SAFETY: `Math.sign` always returns `-1` for negative, `0` for zero, and `1` // for positive numbers. (The extra precision is useful for the way we use // this in the context of `compare`.) return Math.sign(a - b); } /** @module @ember/utils */ /** 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 import { compare } from '@ember/utils'; compare('hello', 'hello'); // 0 compare('abc', 'dfg'); // -1 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 import { compare } from '@ember/utils'; compare('hello', 50); // 1 compare(50, 'hello'); // -1 ``` @method compare @for @ember/utils @static @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 */ function compare(v, w) { if (v === w) { return 0; } let type1 = typeOf(v); let type2 = typeOf(w); if (type1 === 'instance' && isComparable(v) && v.constructor.compare) { return v.constructor.compare(v, w); } if (type2 === 'instance' && isComparable(w) && w.constructor.compare) { // SAFETY: Multiplying by a negative just changes the sign 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': (isDevelopingApp() && !(typeof v === 'boolean' && typeof w === 'boolean') && assert('both are boolean', typeof v === 'boolean' && typeof w === 'boolean')); return spaceship(Number(v), Number(w)); case 'number': (isDevelopingApp() && !(typeof v === 'number' && typeof w === 'number') && assert('both are numbers', typeof v === 'number' && typeof w === 'number')); return spaceship(v, w); case 'string': (isDevelopingApp() && !(typeof v === 'string' && typeof w === 'string') && assert('both are strings', typeof v === 'string' && typeof w === 'string')); return spaceship(v.localeCompare(w), 0); case 'array': { (isDevelopingApp() && !(Array.isArray(v) && Array.isArray(w)) && assert('both are arrays', Array.isArray(v) && Array.isArray(w))); 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 (isComparable(v) && v.compare) { return v.compare(v, w); } return 0; case 'date': (isDevelopingApp() && !(v instanceof Date && w instanceof Date) && assert('both are dates', v instanceof Date && w instanceof Date)); return spaceship(v.getTime(), w.getTime()); default: return 0; } } function isComparable(value) { return Comparable.detect(value); } export { compare as default };