Bug 1700051: part 11) Change `mozInlineSpellStatus::InitForRange` to static factory...
[gecko.git] / devtools / shared / natural-sort.js
blob548c39541c1f9894f491127c02b4951fd6063c7d
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /*
6  * Natural Sort algorithm for Javascript - Version 0.8.1 - Released under MIT license
7  * Author: Jim Palmer (based on chunking idea from Dave Koelle)
8  *
9  * Includes pull request to move regexes out of main function for performance
10  * increases.
11  *
12  * Repository:
13  *   https://github.com/overset/javascript-natural-sort/
14  */
16 "use strict";
18 var re = /(^([+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|^0x[\da-fA-F]+$|\d+)/g;
19 var sre = /^\s+|\s+$/g; // trim pre-post whitespace
20 var snre = /\s+/g; // normalize all whitespace to single ' ' character
22 // eslint-disable-next-line
23 var dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/;
24 var hre = /^0x[0-9a-f]+$/i;
25 var ore = /^0/;
26 var b0re = /^\0/;
27 var e0re = /\0$/;
29 exports.naturalSortCaseSensitive = function naturalSortCaseSensitive(a, b) {
30   return naturalSort(a, b, false);
33 exports.naturalSortCaseInsensitive = function naturalSortCaseInsensitive(a, b) {
34   return naturalSort(a, b, true);
37 /**
38  * Sort numbers, strings, IP Addresses, Dates, Filenames, version numbers etc.
39  * "the way humans do."
40  *
41  * This function should only be called via naturalSortCaseSensitive and
42  * naturalSortCaseInsensitive.
43  *
44  * e.g. [3, 2, 1, 10].sort(naturalSort)
45  *
46  * @param  {Object} a
47  *         Passed in by Array.sort(a, b)
48  * @param  {Object} b
49  *         Passed in by Array.sort(a, b)
50  * @param  {Boolean} insensitive
51  *         Should the search be case insensitive?
52  */
53 // eslint-disable-next-line complexity
54 function naturalSort(a, b, insensitive) {
55   // convert all to strings strip whitespace
56   const i = function(s) {
57     return ((insensitive && ("" + s).toLowerCase()) || "" + s).replace(sre, "");
58   };
59   const x = i(a) || "";
60   const y = i(b) || "";
61   // chunk/tokenize
62   const xN = x
63     .replace(re, "\0$1\0")
64     .replace(e0re, "")
65     .replace(b0re, "")
66     .split("\0");
67   const yN = y
68     .replace(re, "\0$1\0")
69     .replace(e0re, "")
70     .replace(b0re, "")
71     .split("\0");
72   // numeric, hex or date detection
73   const xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && Date.parse(x));
74   const yD =
75     parseInt(y.match(hre), 16) || (xD && y.match(dre) && Date.parse(y)) || null;
76   const normChunk = function(s, l) {
77     // normalize spaces; find floats not starting with '0', string or 0 if
78     // not defined (Clint Priest)
79     return (
80       ((!s.match(ore) || l == 1) && parseFloat(s)) ||
81       s.replace(snre, " ").replace(sre, "") ||
82       0
83     );
84   };
85   let oFxNcL;
86   let oFyNcL;
88   // first try and sort Hex codes or Dates
89   if (yD) {
90     if (xD < yD) {
91       return -1;
92     } else if (xD > yD) {
93       return 1;
94     }
95   }
97   // natural sorting through split numeric strings and default strings
98   // eslint-disable-next-line
99   for (let cLoc = 0, xNl = xN.length, yNl = yN.length, numS = Math.max(xNl, yNl); cLoc < numS; cLoc++) {
100     oFxNcL = normChunk(xN[cLoc] || "", xNl);
101     oFyNcL = normChunk(yN[cLoc] || "", yNl);
103     // handle numeric vs string comparison - number < string - (Kyle Adams)
104     if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
105       return isNaN(oFxNcL) ? 1 : -1;
106     }
107     // if unicode use locale comparison
108     // eslint-disable-next-line
109     if (/[^\x00-\x80]/.test(oFxNcL + oFyNcL) && oFxNcL.localeCompare) {
110       const comp = oFxNcL.localeCompare(oFyNcL);
111       return comp / Math.abs(comp);
112     }
113     if (oFxNcL < oFyNcL) {
114       return -1;
115     } else if (oFxNcL > oFyNcL) {
116       return 1;
117     }
118   }
119   return null;