source: frontend/node_modules/string-natural-compare/natural-compare.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 3.3 KB
Line 
1'use strict';
2
3const defaultAlphabetIndexMap = [];
4
5function isNumberCode(code) {
6 return code >= 48/* '0' */ && code <= 57/* '9' */;
7}
8
9function naturalCompare(a, b, opts) {
10 if (typeof a !== 'string') {
11 throw new TypeError(`The first argument must be a string. Received type '${typeof a}'`);
12 }
13 if (typeof b !== 'string') {
14 throw new TypeError(`The second argument must be a string. Received type '${typeof b}'`);
15 }
16
17 const lengthA = a.length;
18 const lengthB = b.length;
19 let indexA = 0;
20 let indexB = 0;
21 let alphabetIndexMap = defaultAlphabetIndexMap;
22 let firstDifferenceInLeadingZeros = 0;
23
24 if (opts) {
25 if (opts.caseInsensitive) {
26 a = a.toLowerCase();
27 b = b.toLowerCase();
28 }
29
30 if (opts.alphabet) {
31 alphabetIndexMap = buildAlphabetIndexMap(opts.alphabet);
32 }
33 }
34
35 while (indexA < lengthA && indexB < lengthB) {
36 let charCodeA = a.charCodeAt(indexA);
37 let charCodeB = b.charCodeAt(indexB);
38
39 if (isNumberCode(charCodeA)) {
40 if (!isNumberCode(charCodeB)) {
41 return charCodeA - charCodeB;
42 }
43
44 let numStartA = indexA;
45 let numStartB = indexB;
46
47 while (charCodeA === 48/* '0' */ && ++numStartA < lengthA) {
48 charCodeA = a.charCodeAt(numStartA);
49 }
50 while (charCodeB === 48/* '0' */ && ++numStartB < lengthB) {
51 charCodeB = b.charCodeAt(numStartB);
52 }
53
54 if (numStartA !== numStartB && firstDifferenceInLeadingZeros === 0) {
55 firstDifferenceInLeadingZeros = numStartA - numStartB;
56 }
57
58 let numEndA = numStartA;
59 let numEndB = numStartB;
60
61 while (numEndA < lengthA && isNumberCode(a.charCodeAt(numEndA))) {
62 ++numEndA;
63 }
64 while (numEndB < lengthB && isNumberCode(b.charCodeAt(numEndB))) {
65 ++numEndB;
66 }
67
68 let difference = numEndA - numStartA - numEndB + numStartB; // numA length - numB length
69 if (difference !== 0) {
70 return difference;
71 }
72
73 while (numStartA < numEndA) {
74 difference = a.charCodeAt(numStartA++) - b.charCodeAt(numStartB++);
75 if (difference !== 0) {
76 return difference;
77 }
78 }
79
80 indexA = numEndA;
81 indexB = numEndB;
82 continue;
83 }
84
85 if (charCodeA !== charCodeB) {
86 if (
87 charCodeA < alphabetIndexMap.length &&
88 charCodeB < alphabetIndexMap.length &&
89 alphabetIndexMap[charCodeA] !== -1 &&
90 alphabetIndexMap[charCodeB] !== -1
91 ) {
92 return alphabetIndexMap[charCodeA] - alphabetIndexMap[charCodeB];
93 }
94
95 return charCodeA - charCodeB;
96 }
97
98 ++indexA;
99 ++indexB;
100 }
101
102 if (indexA < lengthA) { // `b` is a substring of `a`
103 return 1;
104 }
105
106 if (indexB < lengthB) { // `a` is a substring of `b`
107 return -1;
108 }
109
110 return firstDifferenceInLeadingZeros;
111}
112
113const alphabetIndexMapCache = {};
114
115function buildAlphabetIndexMap(alphabet) {
116 const existingMap = alphabetIndexMapCache[alphabet];
117 if (existingMap !== undefined) {
118 return existingMap;
119 }
120
121 const indexMap = [];
122 const maxCharCode = alphabet.split('').reduce((maxCode, char) => {
123 return Math.max(maxCode, char.charCodeAt(0));
124 }, 0);
125
126 for (let i = 0; i <= maxCharCode; i++) {
127 indexMap.push(-1);
128 }
129
130 for (let i = 0; i < alphabet.length; i++) {
131 indexMap[alphabet.charCodeAt(i)] = i;
132 }
133
134 alphabetIndexMapCache[alphabet] = indexMap;
135
136 return indexMap;
137}
138
139module.exports = naturalCompare;
Note: See TracBrowser for help on using the repository browser.