csv-sort 5.0.16 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +4 -0
- package/dist/csv-sort.esm.js +1 -1
- package/dist/csv-sort.umd.js +18 -18
- package/package.json +47 -40
- package/dist/csv-sort.cjs.js +0 -297
- package/dist/csv-sort.dev.umd.js +0 -2204
package/dist/csv-sort.dev.umd.js
DELETED
|
@@ -1,2204 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @name csv-sort
|
|
3
|
-
* @fileoverview Sorts double-entry bookkeeping CSV coming from internet banking
|
|
4
|
-
* @version 5.0.16
|
|
5
|
-
* @author Roy Revelt, Codsen Ltd
|
|
6
|
-
* @license MIT
|
|
7
|
-
* {@link https://codsen.com/os/csv-sort/}
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
(function (global, factory) {
|
|
11
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
12
|
-
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
13
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.csvSort = {}));
|
|
14
|
-
}(this, (function (exports) { 'use strict';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* lodash (Custom Build) <https://lodash.com/>
|
|
18
|
-
* Build: `lodash modularize exports="npm" -o ./`
|
|
19
|
-
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
|
20
|
-
* Released under MIT license <https://lodash.com/license>
|
|
21
|
-
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
|
22
|
-
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
|
23
|
-
*/
|
|
24
|
-
/**
|
|
25
|
-
* A faster alternative to `Function#apply`, this function invokes `func`
|
|
26
|
-
* with the `this` binding of `thisArg` and the arguments of `args`.
|
|
27
|
-
*
|
|
28
|
-
* @private
|
|
29
|
-
* @param {Function} func The function to invoke.
|
|
30
|
-
* @param {*} thisArg The `this` binding of `func`.
|
|
31
|
-
* @param {Array} args The arguments to invoke `func` with.
|
|
32
|
-
* @returns {*} Returns the result of `func`.
|
|
33
|
-
*/
|
|
34
|
-
function apply(func, thisArg, args) {
|
|
35
|
-
switch (args.length) {
|
|
36
|
-
case 0: return func.call(thisArg);
|
|
37
|
-
case 1: return func.call(thisArg, args[0]);
|
|
38
|
-
case 2: return func.call(thisArg, args[0], args[1]);
|
|
39
|
-
case 3: return func.call(thisArg, args[0], args[1], args[2]);
|
|
40
|
-
}
|
|
41
|
-
return func.apply(thisArg, args);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* A specialized version of `_.map` for arrays without support for iteratee
|
|
46
|
-
* shorthands.
|
|
47
|
-
*
|
|
48
|
-
* @private
|
|
49
|
-
* @param {Array} [array] The array to iterate over.
|
|
50
|
-
* @param {Function} iteratee The function invoked per iteration.
|
|
51
|
-
* @returns {Array} Returns the new mapped array.
|
|
52
|
-
*/
|
|
53
|
-
function arrayMap(array, iteratee) {
|
|
54
|
-
var index = -1,
|
|
55
|
-
length = array ? array.length : 0,
|
|
56
|
-
result = Array(length);
|
|
57
|
-
|
|
58
|
-
while (++index < length) {
|
|
59
|
-
result[index] = iteratee(array[index], index, array);
|
|
60
|
-
}
|
|
61
|
-
return result;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* The base implementation of `_.findIndex` and `_.findLastIndex` without
|
|
66
|
-
* support for iteratee shorthands.
|
|
67
|
-
*
|
|
68
|
-
* @private
|
|
69
|
-
* @param {Array} array The array to search.
|
|
70
|
-
* @param {Function} predicate The function invoked per iteration.
|
|
71
|
-
* @param {number} fromIndex The index to search from.
|
|
72
|
-
* @param {boolean} [fromRight] Specify iterating from right to left.
|
|
73
|
-
* @returns {number} Returns the index of the matched value, else `-1`.
|
|
74
|
-
*/
|
|
75
|
-
function baseFindIndex$1(array, predicate, fromIndex, fromRight) {
|
|
76
|
-
var length = array.length,
|
|
77
|
-
index = fromIndex + (fromRight ? 1 : -1);
|
|
78
|
-
|
|
79
|
-
while ((fromRight ? index-- : ++index < length)) {
|
|
80
|
-
if (predicate(array[index], index, array)) {
|
|
81
|
-
return index;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return -1;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
|
|
89
|
-
*
|
|
90
|
-
* @private
|
|
91
|
-
* @param {Array} array The array to search.
|
|
92
|
-
* @param {*} value The value to search for.
|
|
93
|
-
* @param {number} fromIndex The index to search from.
|
|
94
|
-
* @returns {number} Returns the index of the matched value, else `-1`.
|
|
95
|
-
*/
|
|
96
|
-
function baseIndexOf$1(array, value, fromIndex) {
|
|
97
|
-
if (value !== value) {
|
|
98
|
-
return baseFindIndex$1(array, baseIsNaN$1, fromIndex);
|
|
99
|
-
}
|
|
100
|
-
var index = fromIndex - 1,
|
|
101
|
-
length = array.length;
|
|
102
|
-
|
|
103
|
-
while (++index < length) {
|
|
104
|
-
if (array[index] === value) {
|
|
105
|
-
return index;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return -1;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* This function is like `baseIndexOf` except that it accepts a comparator.
|
|
113
|
-
*
|
|
114
|
-
* @private
|
|
115
|
-
* @param {Array} array The array to search.
|
|
116
|
-
* @param {*} value The value to search for.
|
|
117
|
-
* @param {number} fromIndex The index to search from.
|
|
118
|
-
* @param {Function} comparator The comparator invoked per element.
|
|
119
|
-
* @returns {number} Returns the index of the matched value, else `-1`.
|
|
120
|
-
*/
|
|
121
|
-
function baseIndexOfWith(array, value, fromIndex, comparator) {
|
|
122
|
-
var index = fromIndex - 1,
|
|
123
|
-
length = array.length;
|
|
124
|
-
|
|
125
|
-
while (++index < length) {
|
|
126
|
-
if (comparator(array[index], value)) {
|
|
127
|
-
return index;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return -1;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* The base implementation of `_.isNaN` without support for number objects.
|
|
135
|
-
*
|
|
136
|
-
* @private
|
|
137
|
-
* @param {*} value The value to check.
|
|
138
|
-
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
|
|
139
|
-
*/
|
|
140
|
-
function baseIsNaN$1(value) {
|
|
141
|
-
return value !== value;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* The base implementation of `_.unary` without support for storing metadata.
|
|
146
|
-
*
|
|
147
|
-
* @private
|
|
148
|
-
* @param {Function} func The function to cap arguments for.
|
|
149
|
-
* @returns {Function} Returns the new capped function.
|
|
150
|
-
*/
|
|
151
|
-
function baseUnary(func) {
|
|
152
|
-
return function(value) {
|
|
153
|
-
return func(value);
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** Used for built-in method references. */
|
|
158
|
-
var arrayProto = Array.prototype;
|
|
159
|
-
|
|
160
|
-
/** Built-in value references. */
|
|
161
|
-
var splice = arrayProto.splice;
|
|
162
|
-
|
|
163
|
-
/* Built-in method references for those with the same name as other `lodash` methods. */
|
|
164
|
-
var nativeMax = Math.max;
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* The base implementation of `_.pullAllBy` without support for iteratee
|
|
168
|
-
* shorthands.
|
|
169
|
-
*
|
|
170
|
-
* @private
|
|
171
|
-
* @param {Array} array The array to modify.
|
|
172
|
-
* @param {Array} values The values to remove.
|
|
173
|
-
* @param {Function} [iteratee] The iteratee invoked per element.
|
|
174
|
-
* @param {Function} [comparator] The comparator invoked per element.
|
|
175
|
-
* @returns {Array} Returns `array`.
|
|
176
|
-
*/
|
|
177
|
-
function basePullAll(array, values, iteratee, comparator) {
|
|
178
|
-
var indexOf = comparator ? baseIndexOfWith : baseIndexOf$1,
|
|
179
|
-
index = -1,
|
|
180
|
-
length = values.length,
|
|
181
|
-
seen = array;
|
|
182
|
-
|
|
183
|
-
if (array === values) {
|
|
184
|
-
values = copyArray(values);
|
|
185
|
-
}
|
|
186
|
-
if (iteratee) {
|
|
187
|
-
seen = arrayMap(array, baseUnary(iteratee));
|
|
188
|
-
}
|
|
189
|
-
while (++index < length) {
|
|
190
|
-
var fromIndex = 0,
|
|
191
|
-
value = values[index],
|
|
192
|
-
computed = iteratee ? iteratee(value) : value;
|
|
193
|
-
|
|
194
|
-
while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
|
|
195
|
-
if (seen !== array) {
|
|
196
|
-
splice.call(seen, fromIndex, 1);
|
|
197
|
-
}
|
|
198
|
-
splice.call(array, fromIndex, 1);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return array;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* The base implementation of `_.rest` which doesn't validate or coerce arguments.
|
|
206
|
-
*
|
|
207
|
-
* @private
|
|
208
|
-
* @param {Function} func The function to apply a rest parameter to.
|
|
209
|
-
* @param {number} [start=func.length-1] The start position of the rest parameter.
|
|
210
|
-
* @returns {Function} Returns the new function.
|
|
211
|
-
*/
|
|
212
|
-
function baseRest(func, start) {
|
|
213
|
-
start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
|
|
214
|
-
return function() {
|
|
215
|
-
var args = arguments,
|
|
216
|
-
index = -1,
|
|
217
|
-
length = nativeMax(args.length - start, 0),
|
|
218
|
-
array = Array(length);
|
|
219
|
-
|
|
220
|
-
while (++index < length) {
|
|
221
|
-
array[index] = args[start + index];
|
|
222
|
-
}
|
|
223
|
-
index = -1;
|
|
224
|
-
var otherArgs = Array(start + 1);
|
|
225
|
-
while (++index < start) {
|
|
226
|
-
otherArgs[index] = args[index];
|
|
227
|
-
}
|
|
228
|
-
otherArgs[start] = array;
|
|
229
|
-
return apply(func, this, otherArgs);
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Copies the values of `source` to `array`.
|
|
235
|
-
*
|
|
236
|
-
* @private
|
|
237
|
-
* @param {Array} source The array to copy values from.
|
|
238
|
-
* @param {Array} [array=[]] The array to copy values to.
|
|
239
|
-
* @returns {Array} Returns `array`.
|
|
240
|
-
*/
|
|
241
|
-
function copyArray(source, array) {
|
|
242
|
-
var index = -1,
|
|
243
|
-
length = source.length;
|
|
244
|
-
|
|
245
|
-
array || (array = Array(length));
|
|
246
|
-
while (++index < length) {
|
|
247
|
-
array[index] = source[index];
|
|
248
|
-
}
|
|
249
|
-
return array;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Removes all given values from `array` using
|
|
254
|
-
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
|
255
|
-
* for equality comparisons.
|
|
256
|
-
*
|
|
257
|
-
* **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
|
|
258
|
-
* to remove elements from an array by predicate.
|
|
259
|
-
*
|
|
260
|
-
* @static
|
|
261
|
-
* @memberOf _
|
|
262
|
-
* @since 2.0.0
|
|
263
|
-
* @category Array
|
|
264
|
-
* @param {Array} array The array to modify.
|
|
265
|
-
* @param {...*} [values] The values to remove.
|
|
266
|
-
* @returns {Array} Returns `array`.
|
|
267
|
-
* @example
|
|
268
|
-
*
|
|
269
|
-
* var array = ['a', 'b', 'c', 'a', 'b', 'c'];
|
|
270
|
-
*
|
|
271
|
-
* _.pull(array, 'a', 'c');
|
|
272
|
-
* console.log(array);
|
|
273
|
-
* // => ['b', 'b']
|
|
274
|
-
*/
|
|
275
|
-
var pull = baseRest(pullAll);
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* This method is like `_.pull` except that it accepts an array of values to remove.
|
|
279
|
-
*
|
|
280
|
-
* **Note:** Unlike `_.difference`, this method mutates `array`.
|
|
281
|
-
*
|
|
282
|
-
* @static
|
|
283
|
-
* @memberOf _
|
|
284
|
-
* @since 4.0.0
|
|
285
|
-
* @category Array
|
|
286
|
-
* @param {Array} array The array to modify.
|
|
287
|
-
* @param {Array} values The values to remove.
|
|
288
|
-
* @returns {Array} Returns `array`.
|
|
289
|
-
* @example
|
|
290
|
-
*
|
|
291
|
-
* var array = ['a', 'b', 'c', 'a', 'b', 'c'];
|
|
292
|
-
*
|
|
293
|
-
* _.pullAll(array, ['a', 'c']);
|
|
294
|
-
* console.log(array);
|
|
295
|
-
* // => ['b', 'b']
|
|
296
|
-
*/
|
|
297
|
-
function pullAll(array, values) {
|
|
298
|
-
return (array && array.length && values && values.length)
|
|
299
|
-
? basePullAll(array, values)
|
|
300
|
-
: array;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
var lodash_pull = pull;
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* @name ranges-sort
|
|
307
|
-
* @fileoverview Sort string index ranges
|
|
308
|
-
* @version 4.0.16
|
|
309
|
-
* @author Roy Revelt, Codsen Ltd
|
|
310
|
-
* @license MIT
|
|
311
|
-
* {@link https://codsen.com/os/ranges-sort/}
|
|
312
|
-
*/
|
|
313
|
-
const defaults$4 = {
|
|
314
|
-
strictlyTwoElementsInRangeArrays: false,
|
|
315
|
-
progressFn: null
|
|
316
|
-
};
|
|
317
|
-
function rSort(arrOfRanges, originalOptions) {
|
|
318
|
-
if (!Array.isArray(arrOfRanges) || !arrOfRanges.length) {
|
|
319
|
-
return arrOfRanges;
|
|
320
|
-
}
|
|
321
|
-
const opts = { ...defaults$4,
|
|
322
|
-
...originalOptions
|
|
323
|
-
};
|
|
324
|
-
let culpritsIndex;
|
|
325
|
-
let culpritsLen;
|
|
326
|
-
if (opts.strictlyTwoElementsInRangeArrays && !arrOfRanges.filter(range => range).every((rangeArr, indx) => {
|
|
327
|
-
if (rangeArr.length !== 2) {
|
|
328
|
-
culpritsIndex = indx;
|
|
329
|
-
culpritsLen = rangeArr.length;
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
return true;
|
|
333
|
-
})) {
|
|
334
|
-
throw new TypeError(`ranges-sort: [THROW_ID_03] The first argument should be an array and must consist of arrays which are natural number indexes representing TWO string index ranges. However, ${culpritsIndex}th range (${JSON.stringify(arrOfRanges[culpritsIndex], null, 4)}) has not two but ${culpritsLen} elements!`);
|
|
335
|
-
}
|
|
336
|
-
if (!arrOfRanges.filter(range => range).every((rangeArr, indx) => {
|
|
337
|
-
if (!Number.isInteger(rangeArr[0]) || rangeArr[0] < 0 || !Number.isInteger(rangeArr[1]) || rangeArr[1] < 0) {
|
|
338
|
-
culpritsIndex = indx;
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
|
-
return true;
|
|
342
|
-
})) {
|
|
343
|
-
throw new TypeError(`ranges-sort: [THROW_ID_04] The first argument should be an array and must consist of arrays which are natural number indexes representing string index ranges. However, ${culpritsIndex}th range (${JSON.stringify(arrOfRanges[culpritsIndex], null, 4)}) does not consist of only natural numbers!`);
|
|
344
|
-
}
|
|
345
|
-
const maxPossibleIterations = arrOfRanges.filter(range => range).length ** 2;
|
|
346
|
-
let counter = 0;
|
|
347
|
-
return Array.from(arrOfRanges).filter(range => range).sort((range1, range2) => {
|
|
348
|
-
if (opts.progressFn) {
|
|
349
|
-
counter += 1;
|
|
350
|
-
opts.progressFn(Math.floor(counter * 100 / maxPossibleIterations));
|
|
351
|
-
}
|
|
352
|
-
if (range1[0] === range2[0]) {
|
|
353
|
-
if (range1[1] < range2[1]) {
|
|
354
|
-
return -1;
|
|
355
|
-
}
|
|
356
|
-
if (range1[1] > range2[1]) {
|
|
357
|
-
return 1;
|
|
358
|
-
}
|
|
359
|
-
return 0;
|
|
360
|
-
}
|
|
361
|
-
if (range1[0] < range2[0]) {
|
|
362
|
-
return -1;
|
|
363
|
-
}
|
|
364
|
-
return 1;
|
|
365
|
-
});
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* @name ranges-merge
|
|
370
|
-
* @fileoverview Merge and sort string index ranges
|
|
371
|
-
* @version 7.0.16
|
|
372
|
-
* @author Roy Revelt, Codsen Ltd
|
|
373
|
-
* @license MIT
|
|
374
|
-
* {@link https://codsen.com/os/ranges-merge/}
|
|
375
|
-
*/
|
|
376
|
-
const defaults$3 = {
|
|
377
|
-
mergeType: 1,
|
|
378
|
-
progressFn: null,
|
|
379
|
-
joinRangesThatTouchEdges: true
|
|
380
|
-
};
|
|
381
|
-
function rMerge(arrOfRanges, originalOpts) {
|
|
382
|
-
function isObj(something) {
|
|
383
|
-
return something && typeof something === "object" && !Array.isArray(something);
|
|
384
|
-
}
|
|
385
|
-
if (!Array.isArray(arrOfRanges) || !arrOfRanges.length) {
|
|
386
|
-
return null;
|
|
387
|
-
}
|
|
388
|
-
let opts;
|
|
389
|
-
if (originalOpts) {
|
|
390
|
-
if (isObj(originalOpts)) {
|
|
391
|
-
opts = { ...defaults$3,
|
|
392
|
-
...originalOpts
|
|
393
|
-
};
|
|
394
|
-
if (opts.progressFn && isObj(opts.progressFn) && !Object.keys(opts.progressFn).length) {
|
|
395
|
-
opts.progressFn = null;
|
|
396
|
-
} else if (opts.progressFn && typeof opts.progressFn !== "function") {
|
|
397
|
-
throw new Error(`ranges-merge: [THROW_ID_01] opts.progressFn must be a function! It was given of a type: "${typeof opts.progressFn}", equal to ${JSON.stringify(opts.progressFn, null, 4)}`);
|
|
398
|
-
}
|
|
399
|
-
if (opts.mergeType && +opts.mergeType !== 1 && +opts.mergeType !== 2) {
|
|
400
|
-
throw new Error(`ranges-merge: [THROW_ID_02] opts.mergeType was customised to a wrong thing! It was given of a type: "${typeof opts.mergeType}", equal to ${JSON.stringify(opts.mergeType, null, 4)}`);
|
|
401
|
-
}
|
|
402
|
-
if (typeof opts.joinRangesThatTouchEdges !== "boolean") {
|
|
403
|
-
throw new Error(`ranges-merge: [THROW_ID_04] opts.joinRangesThatTouchEdges was customised to a wrong thing! It was given of a type: "${typeof opts.joinRangesThatTouchEdges}", equal to ${JSON.stringify(opts.joinRangesThatTouchEdges, null, 4)}`);
|
|
404
|
-
}
|
|
405
|
-
} else {
|
|
406
|
-
throw new Error(`emlint: [THROW_ID_03] the second input argument must be a plain object. It was given as:\n${JSON.stringify(originalOpts, null, 4)} (type ${typeof originalOpts})`);
|
|
407
|
-
}
|
|
408
|
-
} else {
|
|
409
|
-
opts = { ...defaults$3
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
const filtered = arrOfRanges
|
|
413
|
-
.filter(range => range).map(subarr => [...subarr]).filter(
|
|
414
|
-
rangeArr => rangeArr[2] !== undefined || rangeArr[0] !== rangeArr[1]);
|
|
415
|
-
let sortedRanges;
|
|
416
|
-
let lastPercentageDone;
|
|
417
|
-
let percentageDone;
|
|
418
|
-
if (opts.progressFn) {
|
|
419
|
-
sortedRanges = rSort(filtered, {
|
|
420
|
-
progressFn: percentage => {
|
|
421
|
-
percentageDone = Math.floor(percentage / 5);
|
|
422
|
-
if (percentageDone !== lastPercentageDone) {
|
|
423
|
-
lastPercentageDone = percentageDone;
|
|
424
|
-
opts.progressFn(percentageDone);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
} else {
|
|
429
|
-
sortedRanges = rSort(filtered);
|
|
430
|
-
}
|
|
431
|
-
if (!sortedRanges) {
|
|
432
|
-
return null;
|
|
433
|
-
}
|
|
434
|
-
const len = sortedRanges.length - 1;
|
|
435
|
-
for (let i = len; i > 0; i--) {
|
|
436
|
-
if (opts.progressFn) {
|
|
437
|
-
percentageDone = Math.floor((1 - i / len) * 78) + 21;
|
|
438
|
-
if (percentageDone !== lastPercentageDone && percentageDone > lastPercentageDone) {
|
|
439
|
-
lastPercentageDone = percentageDone;
|
|
440
|
-
opts.progressFn(percentageDone);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
if (sortedRanges[i][0] <= sortedRanges[i - 1][0] || !opts.joinRangesThatTouchEdges && sortedRanges[i][0] < sortedRanges[i - 1][1] || opts.joinRangesThatTouchEdges && sortedRanges[i][0] <= sortedRanges[i - 1][1]) {
|
|
444
|
-
sortedRanges[i - 1][0] = Math.min(sortedRanges[i][0], sortedRanges[i - 1][0]);
|
|
445
|
-
sortedRanges[i - 1][1] = Math.max(sortedRanges[i][1], sortedRanges[i - 1][1]);
|
|
446
|
-
if (sortedRanges[i][2] !== undefined && (sortedRanges[i - 1][0] >= sortedRanges[i][0] || sortedRanges[i - 1][1] <= sortedRanges[i][1])) {
|
|
447
|
-
if (sortedRanges[i - 1][2] !== null) {
|
|
448
|
-
if (sortedRanges[i][2] === null && sortedRanges[i - 1][2] !== null) {
|
|
449
|
-
sortedRanges[i - 1][2] = null;
|
|
450
|
-
} else if (sortedRanges[i - 1][2] != null) {
|
|
451
|
-
if (+opts.mergeType === 2 && sortedRanges[i - 1][0] === sortedRanges[i][0]) {
|
|
452
|
-
sortedRanges[i - 1][2] = sortedRanges[i][2];
|
|
453
|
-
} else {
|
|
454
|
-
sortedRanges[i - 1][2] += sortedRanges[i][2];
|
|
455
|
-
}
|
|
456
|
-
} else {
|
|
457
|
-
sortedRanges[i - 1][2] = sortedRanges[i][2];
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
sortedRanges.splice(i, 1);
|
|
462
|
-
i = sortedRanges.length;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return sortedRanges.length ? sortedRanges : null;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* @name ranges-apply
|
|
470
|
-
* @fileoverview Take an array of string index ranges, delete/replace the string according to them
|
|
471
|
-
* @version 5.0.16
|
|
472
|
-
* @author Roy Revelt, Codsen Ltd
|
|
473
|
-
* @license MIT
|
|
474
|
-
* {@link https://codsen.com/os/ranges-apply/}
|
|
475
|
-
*/
|
|
476
|
-
function rApply(str, originalRangesArr, progressFn) {
|
|
477
|
-
let percentageDone = 0;
|
|
478
|
-
let lastPercentageDone = 0;
|
|
479
|
-
if (arguments.length === 0) {
|
|
480
|
-
throw new Error("ranges-apply: [THROW_ID_01] inputs missing!");
|
|
481
|
-
}
|
|
482
|
-
if (typeof str !== "string") {
|
|
483
|
-
throw new TypeError(`ranges-apply: [THROW_ID_02] first input argument must be a string! Currently it's: ${typeof str}, equal to: ${JSON.stringify(str, null, 4)}`);
|
|
484
|
-
}
|
|
485
|
-
if (originalRangesArr && !Array.isArray(originalRangesArr)) {
|
|
486
|
-
throw new TypeError(`ranges-apply: [THROW_ID_03] second input argument must be an array (or null)! Currently it's: ${typeof originalRangesArr}, equal to: ${JSON.stringify(originalRangesArr, null, 4)}`);
|
|
487
|
-
}
|
|
488
|
-
if (progressFn && typeof progressFn !== "function") {
|
|
489
|
-
throw new TypeError(`ranges-apply: [THROW_ID_04] the third input argument must be a function (or falsey)! Currently it's: ${typeof progressFn}, equal to: ${JSON.stringify(progressFn, null, 4)}`);
|
|
490
|
-
}
|
|
491
|
-
if (!originalRangesArr || !originalRangesArr.filter(range => range).length) {
|
|
492
|
-
return str;
|
|
493
|
-
}
|
|
494
|
-
let rangesArr;
|
|
495
|
-
if (Array.isArray(originalRangesArr) && Number.isInteger(originalRangesArr[0]) && Number.isInteger(originalRangesArr[1])) {
|
|
496
|
-
rangesArr = [Array.from(originalRangesArr)];
|
|
497
|
-
} else {
|
|
498
|
-
rangesArr = Array.from(originalRangesArr);
|
|
499
|
-
}
|
|
500
|
-
const len = rangesArr.length;
|
|
501
|
-
let counter = 0;
|
|
502
|
-
rangesArr.filter(range => range).forEach((el, i) => {
|
|
503
|
-
if (progressFn) {
|
|
504
|
-
percentageDone = Math.floor(counter / len * 10);
|
|
505
|
-
/* istanbul ignore else */
|
|
506
|
-
if (percentageDone !== lastPercentageDone) {
|
|
507
|
-
lastPercentageDone = percentageDone;
|
|
508
|
-
progressFn(percentageDone);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
if (!Array.isArray(el)) {
|
|
512
|
-
throw new TypeError(`ranges-apply: [THROW_ID_05] ranges array, second input arg., has ${i}th element not an array: ${JSON.stringify(el, null, 4)}, which is ${typeof el}`);
|
|
513
|
-
}
|
|
514
|
-
if (!Number.isInteger(el[0])) {
|
|
515
|
-
if (!Number.isInteger(+el[0]) || +el[0] < 0) {
|
|
516
|
-
throw new TypeError(`ranges-apply: [THROW_ID_06] ranges array, second input arg. has ${i}th element, array ${JSON.stringify(el, null, 0)}. Its first element is not an integer, string index, but ${typeof el[0]}, equal to: ${JSON.stringify(el[0], null, 4)}.`);
|
|
517
|
-
} else {
|
|
518
|
-
rangesArr[i][0] = +rangesArr[i][0];
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
if (!Number.isInteger(el[1])) {
|
|
522
|
-
if (!Number.isInteger(+el[1]) || +el[1] < 0) {
|
|
523
|
-
throw new TypeError(`ranges-apply: [THROW_ID_07] ranges array, second input arg. has ${i}th element, array ${JSON.stringify(el, null, 0)}. Its second element is not an integer, string index, but ${typeof el[1]}, equal to: ${JSON.stringify(el[1], null, 4)}.`);
|
|
524
|
-
} else {
|
|
525
|
-
rangesArr[i][1] = +rangesArr[i][1];
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
counter += 1;
|
|
529
|
-
});
|
|
530
|
-
const workingRanges = rMerge(rangesArr, {
|
|
531
|
-
progressFn: perc => {
|
|
532
|
-
if (progressFn) {
|
|
533
|
-
percentageDone = 10 + Math.floor(perc / 10);
|
|
534
|
-
/* istanbul ignore else */
|
|
535
|
-
if (percentageDone !== lastPercentageDone) {
|
|
536
|
-
lastPercentageDone = percentageDone;
|
|
537
|
-
progressFn(percentageDone);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
const len2 = Array.isArray(workingRanges) ? workingRanges.length : 0;
|
|
543
|
-
/* istanbul ignore else */
|
|
544
|
-
if (len2 > 0) {
|
|
545
|
-
const tails = str.slice(workingRanges[len2 - 1][1]);
|
|
546
|
-
str = workingRanges.reduce((acc, _val, i, arr) => {
|
|
547
|
-
if (progressFn) {
|
|
548
|
-
percentageDone = 20 + Math.floor(i / len2 * 80);
|
|
549
|
-
/* istanbul ignore else */
|
|
550
|
-
if (percentageDone !== lastPercentageDone) {
|
|
551
|
-
lastPercentageDone = percentageDone;
|
|
552
|
-
progressFn(percentageDone);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
const beginning = i === 0 ? 0 : arr[i - 1][1];
|
|
556
|
-
const ending = arr[i][0];
|
|
557
|
-
return acc + str.slice(beginning, ending) + (arr[i][2] || "");
|
|
558
|
-
}, "");
|
|
559
|
-
str += tails;
|
|
560
|
-
}
|
|
561
|
-
return str;
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* @name string-collapse-leading-whitespace
|
|
566
|
-
* @fileoverview Collapse the leading and trailing whitespace of a string
|
|
567
|
-
* @version 5.0.16
|
|
568
|
-
* @author Roy Revelt, Codsen Ltd
|
|
569
|
-
* @license MIT
|
|
570
|
-
* {@link https://codsen.com/os/string-collapse-leading-whitespace/}
|
|
571
|
-
*/
|
|
572
|
-
function collWhitespace(str, originallineBreakLimit = 1) {
|
|
573
|
-
const rawNbsp = "\u00A0";
|
|
574
|
-
function reverse(s) {
|
|
575
|
-
return Array.from(s).reverse().join("");
|
|
576
|
-
}
|
|
577
|
-
function prep(whitespaceChunk, limit, trailing) {
|
|
578
|
-
const firstBreakChar = trailing ? "\n" : "\r";
|
|
579
|
-
const secondBreakChar = trailing ? "\r" : "\n";
|
|
580
|
-
if (!whitespaceChunk) {
|
|
581
|
-
return whitespaceChunk;
|
|
582
|
-
}
|
|
583
|
-
let crlfCount = 0;
|
|
584
|
-
let res = "";
|
|
585
|
-
for (let i = 0, len = whitespaceChunk.length; i < len; i++) {
|
|
586
|
-
if (whitespaceChunk[i] === firstBreakChar || whitespaceChunk[i] === secondBreakChar && whitespaceChunk[i - 1] !== firstBreakChar) {
|
|
587
|
-
crlfCount++;
|
|
588
|
-
}
|
|
589
|
-
if (`\r\n`.includes(whitespaceChunk[i]) || whitespaceChunk[i] === rawNbsp) {
|
|
590
|
-
if (whitespaceChunk[i] === rawNbsp) {
|
|
591
|
-
res += whitespaceChunk[i];
|
|
592
|
-
} else if (whitespaceChunk[i] === firstBreakChar) {
|
|
593
|
-
if (crlfCount <= limit) {
|
|
594
|
-
res += whitespaceChunk[i];
|
|
595
|
-
if (whitespaceChunk[i + 1] === secondBreakChar) {
|
|
596
|
-
res += whitespaceChunk[i + 1];
|
|
597
|
-
i++;
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
} else if (whitespaceChunk[i] === secondBreakChar && (!whitespaceChunk[i - 1] || whitespaceChunk[i - 1] !== firstBreakChar) && crlfCount <= limit) {
|
|
601
|
-
res += whitespaceChunk[i];
|
|
602
|
-
}
|
|
603
|
-
} else {
|
|
604
|
-
if (!whitespaceChunk[i + 1] && !crlfCount) {
|
|
605
|
-
res += " ";
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
return res;
|
|
610
|
-
}
|
|
611
|
-
if (typeof str === "string" && str.length) {
|
|
612
|
-
let lineBreakLimit = 1;
|
|
613
|
-
if (typeof +originallineBreakLimit === "number" && Number.isInteger(+originallineBreakLimit) && +originallineBreakLimit >= 0) {
|
|
614
|
-
lineBreakLimit = +originallineBreakLimit;
|
|
615
|
-
}
|
|
616
|
-
let frontPart = "";
|
|
617
|
-
let endPart = "";
|
|
618
|
-
if (!str.trim()) {
|
|
619
|
-
frontPart = str;
|
|
620
|
-
} else if (!str[0].trim()) {
|
|
621
|
-
for (let i = 0, len = str.length; i < len; i++) {
|
|
622
|
-
if (str[i].trim()) {
|
|
623
|
-
frontPart = str.slice(0, i);
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
if (str.trim() && (str.slice(-1).trim() === "" || str.slice(-1) === rawNbsp)) {
|
|
629
|
-
for (let i = str.length; i--;) {
|
|
630
|
-
if (str[i].trim()) {
|
|
631
|
-
endPart = str.slice(i + 1);
|
|
632
|
-
break;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
return `${prep(frontPart, lineBreakLimit, false)}${str.trim()}${reverse(prep(reverse(endPart), lineBreakLimit, true))}`;
|
|
637
|
-
}
|
|
638
|
-
return str;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* @name ranges-push
|
|
643
|
-
* @fileoverview Gather string index ranges
|
|
644
|
-
* @version 5.0.16
|
|
645
|
-
* @author Roy Revelt, Codsen Ltd
|
|
646
|
-
* @license MIT
|
|
647
|
-
* {@link https://codsen.com/os/ranges-push/}
|
|
648
|
-
*/
|
|
649
|
-
function existy(x) {
|
|
650
|
-
return x != null;
|
|
651
|
-
}
|
|
652
|
-
function isNum(something) {
|
|
653
|
-
return Number.isInteger(something) && something >= 0;
|
|
654
|
-
}
|
|
655
|
-
function isStr(something) {
|
|
656
|
-
return typeof something === "string";
|
|
657
|
-
}
|
|
658
|
-
const defaults$2 = {
|
|
659
|
-
limitToBeAddedWhitespace: false,
|
|
660
|
-
limitLinebreaksCount: 1,
|
|
661
|
-
mergeType: 1
|
|
662
|
-
};
|
|
663
|
-
class Ranges {
|
|
664
|
-
constructor(originalOpts) {
|
|
665
|
-
const opts = { ...defaults$2,
|
|
666
|
-
...originalOpts
|
|
667
|
-
};
|
|
668
|
-
if (opts.mergeType && opts.mergeType !== 1 && opts.mergeType !== 2) {
|
|
669
|
-
if (isStr(opts.mergeType) && opts.mergeType.trim() === "1") {
|
|
670
|
-
opts.mergeType = 1;
|
|
671
|
-
} else if (isStr(opts.mergeType) && opts.mergeType.trim() === "2") {
|
|
672
|
-
opts.mergeType = 2;
|
|
673
|
-
} else {
|
|
674
|
-
throw new Error(`ranges-push: [THROW_ID_02] opts.mergeType was customised to a wrong thing! It was given of a type: "${typeof opts.mergeType}", equal to ${JSON.stringify(opts.mergeType, null, 4)}`);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
this.opts = opts;
|
|
678
|
-
this.ranges = [];
|
|
679
|
-
}
|
|
680
|
-
add(originalFrom, originalTo, addVal) {
|
|
681
|
-
if (originalFrom == null && originalTo == null) {
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
if (existy(originalFrom) && !existy(originalTo)) {
|
|
685
|
-
if (Array.isArray(originalFrom)) {
|
|
686
|
-
if (originalFrom.length) {
|
|
687
|
-
if (originalFrom.some(el => Array.isArray(el))) {
|
|
688
|
-
originalFrom.forEach(thing => {
|
|
689
|
-
if (Array.isArray(thing)) {
|
|
690
|
-
this.add(...thing);
|
|
691
|
-
}
|
|
692
|
-
});
|
|
693
|
-
return;
|
|
694
|
-
}
|
|
695
|
-
if (originalFrom.length && isNum(+originalFrom[0]) && isNum(+originalFrom[1])) {
|
|
696
|
-
this.add(...originalFrom);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
throw new TypeError(`ranges-push/Ranges/add(): [THROW_ID_12] the first input argument, "from" is set (${JSON.stringify(originalFrom, null, 0)}) but second-one, "to" is not (${JSON.stringify(originalTo, null, 0)})`);
|
|
702
|
-
} else if (!existy(originalFrom) && existy(originalTo)) {
|
|
703
|
-
throw new TypeError(`ranges-push/Ranges/add(): [THROW_ID_13] the second input argument, "to" is set (${JSON.stringify(originalTo, null, 0)}) but first-one, "from" is not (${JSON.stringify(originalFrom, null, 0)})`);
|
|
704
|
-
}
|
|
705
|
-
const from = +originalFrom;
|
|
706
|
-
const to = +originalTo;
|
|
707
|
-
if (isNum(addVal)) {
|
|
708
|
-
addVal = String(addVal);
|
|
709
|
-
}
|
|
710
|
-
if (isNum(from) && isNum(to)) {
|
|
711
|
-
if (existy(addVal) && !isStr(addVal) && !isNum(addVal)) {
|
|
712
|
-
throw new TypeError(`ranges-push/Ranges/add(): [THROW_ID_08] The third argument, the value to add, was given not as string but ${typeof addVal}, equal to:\n${JSON.stringify(addVal, null, 4)}`);
|
|
713
|
-
}
|
|
714
|
-
if (existy(this.ranges) && Array.isArray(this.last()) && from === this.last()[1]) {
|
|
715
|
-
this.last()[1] = to;
|
|
716
|
-
if (this.last()[2] === null || addVal === null) ;
|
|
717
|
-
if (this.last()[2] !== null && existy(addVal)) {
|
|
718
|
-
let calculatedVal = this.last()[2] && this.last()[2].length > 0 && (!this.opts || !this.opts.mergeType || this.opts.mergeType === 1) ? this.last()[2] + addVal : addVal;
|
|
719
|
-
if (this.opts.limitToBeAddedWhitespace) {
|
|
720
|
-
calculatedVal = collWhitespace(calculatedVal, this.opts.limitLinebreaksCount);
|
|
721
|
-
}
|
|
722
|
-
if (!(isStr(calculatedVal) && !calculatedVal.length)) {
|
|
723
|
-
this.last()[2] = calculatedVal;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
} else {
|
|
727
|
-
if (!this.ranges) {
|
|
728
|
-
this.ranges = [];
|
|
729
|
-
}
|
|
730
|
-
const whatToPush = addVal !== undefined && !(isStr(addVal) && !addVal.length) ? [from, to, addVal && this.opts.limitToBeAddedWhitespace ? collWhitespace(addVal, this.opts.limitLinebreaksCount) : addVal] : [from, to];
|
|
731
|
-
this.ranges.push(whatToPush);
|
|
732
|
-
}
|
|
733
|
-
} else {
|
|
734
|
-
if (!(isNum(from) && from >= 0)) {
|
|
735
|
-
throw new TypeError(`ranges-push/Ranges/add(): [THROW_ID_09] "from" value, the first input argument, must be a natural number or zero! Currently it's of a type "${typeof from}" equal to: ${JSON.stringify(from, null, 4)}`);
|
|
736
|
-
} else {
|
|
737
|
-
throw new TypeError(`ranges-push/Ranges/add(): [THROW_ID_10] "to" value, the second input argument, must be a natural number or zero! Currently it's of a type "${typeof to}" equal to: ${JSON.stringify(to, null, 4)}`);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
push(originalFrom, originalTo, addVal) {
|
|
742
|
-
this.add(originalFrom, originalTo, addVal);
|
|
743
|
-
}
|
|
744
|
-
current() {
|
|
745
|
-
if (Array.isArray(this.ranges) && this.ranges.length) {
|
|
746
|
-
this.ranges = rMerge(this.ranges, {
|
|
747
|
-
mergeType: this.opts.mergeType
|
|
748
|
-
});
|
|
749
|
-
if (this.ranges && this.opts.limitToBeAddedWhitespace) {
|
|
750
|
-
return this.ranges.map(val => {
|
|
751
|
-
if (existy(val[2])) {
|
|
752
|
-
return [val[0], val[1], collWhitespace(val[2], this.opts.limitLinebreaksCount)];
|
|
753
|
-
}
|
|
754
|
-
return val;
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
return this.ranges;
|
|
758
|
-
}
|
|
759
|
-
return null;
|
|
760
|
-
}
|
|
761
|
-
wipe() {
|
|
762
|
-
this.ranges = [];
|
|
763
|
-
}
|
|
764
|
-
replace(givenRanges) {
|
|
765
|
-
if (Array.isArray(givenRanges) && givenRanges.length) {
|
|
766
|
-
if (!(Array.isArray(givenRanges[0]) && isNum(givenRanges[0][0]))) {
|
|
767
|
-
throw new Error(`ranges-push/Ranges/replace(): [THROW_ID_11] Single range was given but we expected array of arrays! The first element, ${JSON.stringify(givenRanges[0], null, 4)} should be an array and its first element should be an integer, a string index.`);
|
|
768
|
-
} else {
|
|
769
|
-
this.ranges = Array.from(givenRanges);
|
|
770
|
-
}
|
|
771
|
-
} else {
|
|
772
|
-
this.ranges = [];
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
last() {
|
|
776
|
-
if (Array.isArray(this.ranges) && this.ranges.length) {
|
|
777
|
-
return this.ranges[this.ranges.length - 1];
|
|
778
|
-
}
|
|
779
|
-
return null;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* lodash (Custom Build) <https://lodash.com/>
|
|
787
|
-
* Build: `lodash modularize exports="npm" -o ./`
|
|
788
|
-
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
|
789
|
-
* Released under MIT license <https://lodash.com/license>
|
|
790
|
-
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
|
791
|
-
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
|
792
|
-
*/
|
|
793
|
-
|
|
794
|
-
/** Used as references for various `Number` constants. */
|
|
795
|
-
var INFINITY = 1 / 0;
|
|
796
|
-
|
|
797
|
-
/** `Object#toString` result references. */
|
|
798
|
-
var symbolTag = '[object Symbol]';
|
|
799
|
-
|
|
800
|
-
/** Used to match leading and trailing whitespace. */
|
|
801
|
-
var reTrim = /^\s+|\s+$/g;
|
|
802
|
-
|
|
803
|
-
/** Used to compose unicode character classes. */
|
|
804
|
-
var rsAstralRange = '\\ud800-\\udfff',
|
|
805
|
-
rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23',
|
|
806
|
-
rsComboSymbolsRange = '\\u20d0-\\u20f0',
|
|
807
|
-
rsVarRange = '\\ufe0e\\ufe0f';
|
|
808
|
-
|
|
809
|
-
/** Used to compose unicode capture groups. */
|
|
810
|
-
var rsAstral = '[' + rsAstralRange + ']',
|
|
811
|
-
rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',
|
|
812
|
-
rsFitz = '\\ud83c[\\udffb-\\udfff]',
|
|
813
|
-
rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
|
|
814
|
-
rsNonAstral = '[^' + rsAstralRange + ']',
|
|
815
|
-
rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
|
|
816
|
-
rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
|
|
817
|
-
rsZWJ = '\\u200d';
|
|
818
|
-
|
|
819
|
-
/** Used to compose unicode regexes. */
|
|
820
|
-
var reOptMod = rsModifier + '?',
|
|
821
|
-
rsOptVar = '[' + rsVarRange + ']?',
|
|
822
|
-
rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
|
|
823
|
-
rsSeq = rsOptVar + reOptMod + rsOptJoin,
|
|
824
|
-
rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
|
|
825
|
-
|
|
826
|
-
/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
|
|
827
|
-
var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
|
|
828
|
-
|
|
829
|
-
/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
|
|
830
|
-
var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']');
|
|
831
|
-
|
|
832
|
-
/** Detect free variable `global` from Node.js. */
|
|
833
|
-
var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
|
|
834
|
-
|
|
835
|
-
/** Detect free variable `self`. */
|
|
836
|
-
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
|
|
837
|
-
|
|
838
|
-
/** Used as a reference to the global object. */
|
|
839
|
-
var root = freeGlobal || freeSelf || Function('return this')();
|
|
840
|
-
|
|
841
|
-
/**
|
|
842
|
-
* Converts an ASCII `string` to an array.
|
|
843
|
-
*
|
|
844
|
-
* @private
|
|
845
|
-
* @param {string} string The string to convert.
|
|
846
|
-
* @returns {Array} Returns the converted array.
|
|
847
|
-
*/
|
|
848
|
-
function asciiToArray(string) {
|
|
849
|
-
return string.split('');
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
/**
|
|
853
|
-
* The base implementation of `_.findIndex` and `_.findLastIndex` without
|
|
854
|
-
* support for iteratee shorthands.
|
|
855
|
-
*
|
|
856
|
-
* @private
|
|
857
|
-
* @param {Array} array The array to inspect.
|
|
858
|
-
* @param {Function} predicate The function invoked per iteration.
|
|
859
|
-
* @param {number} fromIndex The index to search from.
|
|
860
|
-
* @param {boolean} [fromRight] Specify iterating from right to left.
|
|
861
|
-
* @returns {number} Returns the index of the matched value, else `-1`.
|
|
862
|
-
*/
|
|
863
|
-
function baseFindIndex(array, predicate, fromIndex, fromRight) {
|
|
864
|
-
var length = array.length,
|
|
865
|
-
index = fromIndex + (fromRight ? 1 : -1);
|
|
866
|
-
|
|
867
|
-
while ((fromRight ? index-- : ++index < length)) {
|
|
868
|
-
if (predicate(array[index], index, array)) {
|
|
869
|
-
return index;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
return -1;
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
/**
|
|
876
|
-
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
|
|
877
|
-
*
|
|
878
|
-
* @private
|
|
879
|
-
* @param {Array} array The array to inspect.
|
|
880
|
-
* @param {*} value The value to search for.
|
|
881
|
-
* @param {number} fromIndex The index to search from.
|
|
882
|
-
* @returns {number} Returns the index of the matched value, else `-1`.
|
|
883
|
-
*/
|
|
884
|
-
function baseIndexOf(array, value, fromIndex) {
|
|
885
|
-
if (value !== value) {
|
|
886
|
-
return baseFindIndex(array, baseIsNaN, fromIndex);
|
|
887
|
-
}
|
|
888
|
-
var index = fromIndex - 1,
|
|
889
|
-
length = array.length;
|
|
890
|
-
|
|
891
|
-
while (++index < length) {
|
|
892
|
-
if (array[index] === value) {
|
|
893
|
-
return index;
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
return -1;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
/**
|
|
900
|
-
* The base implementation of `_.isNaN` without support for number objects.
|
|
901
|
-
*
|
|
902
|
-
* @private
|
|
903
|
-
* @param {*} value The value to check.
|
|
904
|
-
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
|
|
905
|
-
*/
|
|
906
|
-
function baseIsNaN(value) {
|
|
907
|
-
return value !== value;
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
/**
|
|
911
|
-
* Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
|
|
912
|
-
* that is not found in the character symbols.
|
|
913
|
-
*
|
|
914
|
-
* @private
|
|
915
|
-
* @param {Array} strSymbols The string symbols to inspect.
|
|
916
|
-
* @param {Array} chrSymbols The character symbols to find.
|
|
917
|
-
* @returns {number} Returns the index of the first unmatched string symbol.
|
|
918
|
-
*/
|
|
919
|
-
function charsStartIndex(strSymbols, chrSymbols) {
|
|
920
|
-
var index = -1,
|
|
921
|
-
length = strSymbols.length;
|
|
922
|
-
|
|
923
|
-
while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
|
924
|
-
return index;
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
/**
|
|
928
|
-
* Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
|
|
929
|
-
* that is not found in the character symbols.
|
|
930
|
-
*
|
|
931
|
-
* @private
|
|
932
|
-
* @param {Array} strSymbols The string symbols to inspect.
|
|
933
|
-
* @param {Array} chrSymbols The character symbols to find.
|
|
934
|
-
* @returns {number} Returns the index of the last unmatched string symbol.
|
|
935
|
-
*/
|
|
936
|
-
function charsEndIndex(strSymbols, chrSymbols) {
|
|
937
|
-
var index = strSymbols.length;
|
|
938
|
-
|
|
939
|
-
while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
|
940
|
-
return index;
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
/**
|
|
944
|
-
* Checks if `string` contains Unicode symbols.
|
|
945
|
-
*
|
|
946
|
-
* @private
|
|
947
|
-
* @param {string} string The string to inspect.
|
|
948
|
-
* @returns {boolean} Returns `true` if a symbol is found, else `false`.
|
|
949
|
-
*/
|
|
950
|
-
function hasUnicode(string) {
|
|
951
|
-
return reHasUnicode.test(string);
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
/**
|
|
955
|
-
* Converts `string` to an array.
|
|
956
|
-
*
|
|
957
|
-
* @private
|
|
958
|
-
* @param {string} string The string to convert.
|
|
959
|
-
* @returns {Array} Returns the converted array.
|
|
960
|
-
*/
|
|
961
|
-
function stringToArray(string) {
|
|
962
|
-
return hasUnicode(string)
|
|
963
|
-
? unicodeToArray(string)
|
|
964
|
-
: asciiToArray(string);
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
/**
|
|
968
|
-
* Converts a Unicode `string` to an array.
|
|
969
|
-
*
|
|
970
|
-
* @private
|
|
971
|
-
* @param {string} string The string to convert.
|
|
972
|
-
* @returns {Array} Returns the converted array.
|
|
973
|
-
*/
|
|
974
|
-
function unicodeToArray(string) {
|
|
975
|
-
return string.match(reUnicode) || [];
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
/** Used for built-in method references. */
|
|
979
|
-
var objectProto = Object.prototype;
|
|
980
|
-
|
|
981
|
-
/**
|
|
982
|
-
* Used to resolve the
|
|
983
|
-
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
|
|
984
|
-
* of values.
|
|
985
|
-
*/
|
|
986
|
-
var objectToString = objectProto.toString;
|
|
987
|
-
|
|
988
|
-
/** Built-in value references. */
|
|
989
|
-
var Symbol = root.Symbol;
|
|
990
|
-
|
|
991
|
-
/** Used to convert symbols to primitives and strings. */
|
|
992
|
-
var symbolProto = Symbol ? Symbol.prototype : undefined,
|
|
993
|
-
symbolToString = symbolProto ? symbolProto.toString : undefined;
|
|
994
|
-
|
|
995
|
-
/**
|
|
996
|
-
* The base implementation of `_.slice` without an iteratee call guard.
|
|
997
|
-
*
|
|
998
|
-
* @private
|
|
999
|
-
* @param {Array} array The array to slice.
|
|
1000
|
-
* @param {number} [start=0] The start position.
|
|
1001
|
-
* @param {number} [end=array.length] The end position.
|
|
1002
|
-
* @returns {Array} Returns the slice of `array`.
|
|
1003
|
-
*/
|
|
1004
|
-
function baseSlice(array, start, end) {
|
|
1005
|
-
var index = -1,
|
|
1006
|
-
length = array.length;
|
|
1007
|
-
|
|
1008
|
-
if (start < 0) {
|
|
1009
|
-
start = -start > length ? 0 : (length + start);
|
|
1010
|
-
}
|
|
1011
|
-
end = end > length ? length : end;
|
|
1012
|
-
if (end < 0) {
|
|
1013
|
-
end += length;
|
|
1014
|
-
}
|
|
1015
|
-
length = start > end ? 0 : ((end - start) >>> 0);
|
|
1016
|
-
start >>>= 0;
|
|
1017
|
-
|
|
1018
|
-
var result = Array(length);
|
|
1019
|
-
while (++index < length) {
|
|
1020
|
-
result[index] = array[index + start];
|
|
1021
|
-
}
|
|
1022
|
-
return result;
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
/**
|
|
1026
|
-
* The base implementation of `_.toString` which doesn't convert nullish
|
|
1027
|
-
* values to empty strings.
|
|
1028
|
-
*
|
|
1029
|
-
* @private
|
|
1030
|
-
* @param {*} value The value to process.
|
|
1031
|
-
* @returns {string} Returns the string.
|
|
1032
|
-
*/
|
|
1033
|
-
function baseToString(value) {
|
|
1034
|
-
// Exit early for strings to avoid a performance hit in some environments.
|
|
1035
|
-
if (typeof value == 'string') {
|
|
1036
|
-
return value;
|
|
1037
|
-
}
|
|
1038
|
-
if (isSymbol(value)) {
|
|
1039
|
-
return symbolToString ? symbolToString.call(value) : '';
|
|
1040
|
-
}
|
|
1041
|
-
var result = (value + '');
|
|
1042
|
-
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
/**
|
|
1046
|
-
* Casts `array` to a slice if it's needed.
|
|
1047
|
-
*
|
|
1048
|
-
* @private
|
|
1049
|
-
* @param {Array} array The array to inspect.
|
|
1050
|
-
* @param {number} start The start position.
|
|
1051
|
-
* @param {number} [end=array.length] The end position.
|
|
1052
|
-
* @returns {Array} Returns the cast slice.
|
|
1053
|
-
*/
|
|
1054
|
-
function castSlice(array, start, end) {
|
|
1055
|
-
var length = array.length;
|
|
1056
|
-
end = end === undefined ? length : end;
|
|
1057
|
-
return (!start && end >= length) ? array : baseSlice(array, start, end);
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
/**
|
|
1061
|
-
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
|
1062
|
-
* and has a `typeof` result of "object".
|
|
1063
|
-
*
|
|
1064
|
-
* @static
|
|
1065
|
-
* @memberOf _
|
|
1066
|
-
* @since 4.0.0
|
|
1067
|
-
* @category Lang
|
|
1068
|
-
* @param {*} value The value to check.
|
|
1069
|
-
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
|
1070
|
-
* @example
|
|
1071
|
-
*
|
|
1072
|
-
* _.isObjectLike({});
|
|
1073
|
-
* // => true
|
|
1074
|
-
*
|
|
1075
|
-
* _.isObjectLike([1, 2, 3]);
|
|
1076
|
-
* // => true
|
|
1077
|
-
*
|
|
1078
|
-
* _.isObjectLike(_.noop);
|
|
1079
|
-
* // => false
|
|
1080
|
-
*
|
|
1081
|
-
* _.isObjectLike(null);
|
|
1082
|
-
* // => false
|
|
1083
|
-
*/
|
|
1084
|
-
function isObjectLike(value) {
|
|
1085
|
-
return !!value && typeof value == 'object';
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
/**
|
|
1089
|
-
* Checks if `value` is classified as a `Symbol` primitive or object.
|
|
1090
|
-
*
|
|
1091
|
-
* @static
|
|
1092
|
-
* @memberOf _
|
|
1093
|
-
* @since 4.0.0
|
|
1094
|
-
* @category Lang
|
|
1095
|
-
* @param {*} value The value to check.
|
|
1096
|
-
* @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
|
|
1097
|
-
* @example
|
|
1098
|
-
*
|
|
1099
|
-
* _.isSymbol(Symbol.iterator);
|
|
1100
|
-
* // => true
|
|
1101
|
-
*
|
|
1102
|
-
* _.isSymbol('abc');
|
|
1103
|
-
* // => false
|
|
1104
|
-
*/
|
|
1105
|
-
function isSymbol(value) {
|
|
1106
|
-
return typeof value == 'symbol' ||
|
|
1107
|
-
(isObjectLike(value) && objectToString.call(value) == symbolTag);
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
/**
|
|
1111
|
-
* Converts `value` to a string. An empty string is returned for `null`
|
|
1112
|
-
* and `undefined` values. The sign of `-0` is preserved.
|
|
1113
|
-
*
|
|
1114
|
-
* @static
|
|
1115
|
-
* @memberOf _
|
|
1116
|
-
* @since 4.0.0
|
|
1117
|
-
* @category Lang
|
|
1118
|
-
* @param {*} value The value to process.
|
|
1119
|
-
* @returns {string} Returns the string.
|
|
1120
|
-
* @example
|
|
1121
|
-
*
|
|
1122
|
-
* _.toString(null);
|
|
1123
|
-
* // => ''
|
|
1124
|
-
*
|
|
1125
|
-
* _.toString(-0);
|
|
1126
|
-
* // => '-0'
|
|
1127
|
-
*
|
|
1128
|
-
* _.toString([1, 2, 3]);
|
|
1129
|
-
* // => '1,2,3'
|
|
1130
|
-
*/
|
|
1131
|
-
function toString(value) {
|
|
1132
|
-
return value == null ? '' : baseToString(value);
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
/**
|
|
1136
|
-
* Removes leading and trailing whitespace or specified characters from `string`.
|
|
1137
|
-
*
|
|
1138
|
-
* @static
|
|
1139
|
-
* @memberOf _
|
|
1140
|
-
* @since 3.0.0
|
|
1141
|
-
* @category String
|
|
1142
|
-
* @param {string} [string=''] The string to trim.
|
|
1143
|
-
* @param {string} [chars=whitespace] The characters to trim.
|
|
1144
|
-
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
|
1145
|
-
* @returns {string} Returns the trimmed string.
|
|
1146
|
-
* @example
|
|
1147
|
-
*
|
|
1148
|
-
* _.trim(' abc ');
|
|
1149
|
-
* // => 'abc'
|
|
1150
|
-
*
|
|
1151
|
-
* _.trim('-_-abc-_-', '_-');
|
|
1152
|
-
* // => 'abc'
|
|
1153
|
-
*
|
|
1154
|
-
* _.map([' foo ', ' bar '], _.trim);
|
|
1155
|
-
* // => ['foo', 'bar']
|
|
1156
|
-
*/
|
|
1157
|
-
function trim(string, chars, guard) {
|
|
1158
|
-
string = toString(string);
|
|
1159
|
-
if (string && (guard || chars === undefined)) {
|
|
1160
|
-
return string.replace(reTrim, '');
|
|
1161
|
-
}
|
|
1162
|
-
if (!string || !(chars = baseToString(chars))) {
|
|
1163
|
-
return string;
|
|
1164
|
-
}
|
|
1165
|
-
var strSymbols = stringToArray(string),
|
|
1166
|
-
chrSymbols = stringToArray(chars),
|
|
1167
|
-
start = charsStartIndex(strSymbols, chrSymbols),
|
|
1168
|
-
end = charsEndIndex(strSymbols, chrSymbols) + 1;
|
|
1169
|
-
|
|
1170
|
-
return castSlice(strSymbols, start, end).join('');
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
var lodash_trim = trim;
|
|
1174
|
-
|
|
1175
|
-
/**
|
|
1176
|
-
* @name string-remove-thousand-separators
|
|
1177
|
-
* @fileoverview Detects and removes thousand separators (dot/comma/quote/space) from string-type digits
|
|
1178
|
-
* @version 5.0.16
|
|
1179
|
-
* @author Roy Revelt, Codsen Ltd
|
|
1180
|
-
* @license MIT
|
|
1181
|
-
* {@link https://codsen.com/os/string-remove-thousand-separators/}
|
|
1182
|
-
*/
|
|
1183
|
-
function remSep(str, originalOpts) {
|
|
1184
|
-
let allOK = true;
|
|
1185
|
-
const knownSeparatorsArray = [".", ",", "'", " "];
|
|
1186
|
-
let firstSeparator;
|
|
1187
|
-
if (typeof str !== "string") {
|
|
1188
|
-
throw new TypeError(`string-remove-thousand-separators/remSep(): [THROW_ID_01] Input must be string! Currently it's: ${typeof str}, equal to:\n${JSON.stringify(str, null, 4)}`);
|
|
1189
|
-
}
|
|
1190
|
-
if (originalOpts && typeof originalOpts !== "object") {
|
|
1191
|
-
throw new TypeError(`string-remove-thousand-separators/remSep(): [THROW_ID_02] Options object must be a plain object! Currently it's: ${typeof originalOpts}, equal to:\n${JSON.stringify(originalOpts, null, 4)}`);
|
|
1192
|
-
}
|
|
1193
|
-
const defaults = {
|
|
1194
|
-
removeThousandSeparatorsFromNumbers: true,
|
|
1195
|
-
padSingleDecimalPlaceNumbers: true,
|
|
1196
|
-
forceUKStyle: false
|
|
1197
|
-
};
|
|
1198
|
-
const opts = { ...defaults,
|
|
1199
|
-
...originalOpts
|
|
1200
|
-
};
|
|
1201
|
-
const res = lodash_trim(str.trim(), '"');
|
|
1202
|
-
if (res === "") {
|
|
1203
|
-
return res;
|
|
1204
|
-
}
|
|
1205
|
-
const rangesToDelete = new Ranges();
|
|
1206
|
-
for (let i = 0, len = res.length; i < len; i++) {
|
|
1207
|
-
if (opts.removeThousandSeparatorsFromNumbers && res[i].trim() === "") {
|
|
1208
|
-
rangesToDelete.add(i, i + 1);
|
|
1209
|
-
}
|
|
1210
|
-
if (opts.removeThousandSeparatorsFromNumbers && res[i] === "'") {
|
|
1211
|
-
rangesToDelete.add(i, i + 1);
|
|
1212
|
-
if (res[i + 1] === "'") {
|
|
1213
|
-
allOK = false;
|
|
1214
|
-
break;
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
if (knownSeparatorsArray.includes(res[i])) {
|
|
1218
|
-
if (res[i + 1] !== undefined && /^\d*$/.test(res[i + 1])) {
|
|
1219
|
-
if (res[i + 2] !== undefined) {
|
|
1220
|
-
if (/^\d*$/.test(res[i + 2])) {
|
|
1221
|
-
if (res[i + 3] !== undefined) {
|
|
1222
|
-
if (/^\d*$/.test(res[i + 3])) {
|
|
1223
|
-
if (res[i + 4] !== undefined && /^\d*$/.test(res[i + 4])) {
|
|
1224
|
-
allOK = false;
|
|
1225
|
-
break;
|
|
1226
|
-
} else {
|
|
1227
|
-
if (opts.removeThousandSeparatorsFromNumbers) {
|
|
1228
|
-
rangesToDelete.add(i, i + 1);
|
|
1229
|
-
}
|
|
1230
|
-
if (!firstSeparator) {
|
|
1231
|
-
firstSeparator = res[i];
|
|
1232
|
-
} else if (res[i] !== firstSeparator) {
|
|
1233
|
-
allOK = false;
|
|
1234
|
-
break;
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
} else {
|
|
1238
|
-
allOK = false;
|
|
1239
|
-
break;
|
|
1240
|
-
}
|
|
1241
|
-
} else if (opts.removeThousandSeparatorsFromNumbers && opts.forceUKStyle && res[i] === ",") {
|
|
1242
|
-
rangesToDelete.add(i, i + 1, ".");
|
|
1243
|
-
}
|
|
1244
|
-
} else {
|
|
1245
|
-
allOK = false;
|
|
1246
|
-
break;
|
|
1247
|
-
}
|
|
1248
|
-
} else {
|
|
1249
|
-
if (opts.forceUKStyle && res[i] === ",") {
|
|
1250
|
-
rangesToDelete.add(i, i + 1, ".");
|
|
1251
|
-
}
|
|
1252
|
-
if (opts.padSingleDecimalPlaceNumbers) {
|
|
1253
|
-
rangesToDelete.add(i + 2, i + 2, "0");
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
} else if (!/^\d*$/.test(res[i])) {
|
|
1258
|
-
allOK = false;
|
|
1259
|
-
break;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
if (allOK && rangesToDelete.current()) {
|
|
1263
|
-
return rApply(res, rangesToDelete.current());
|
|
1264
|
-
}
|
|
1265
|
-
return res;
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
/**
|
|
1269
|
-
* @name csv-split-easy
|
|
1270
|
-
* @fileoverview Splits the CSV string into array of arrays, each representing a row of columns
|
|
1271
|
-
* @version 5.0.16
|
|
1272
|
-
* @author Roy Revelt, Codsen Ltd
|
|
1273
|
-
* @license MIT
|
|
1274
|
-
* {@link https://codsen.com/os/csv-split-easy/}
|
|
1275
|
-
*/
|
|
1276
|
-
const defaults$1 = {
|
|
1277
|
-
removeThousandSeparatorsFromNumbers: true,
|
|
1278
|
-
padSingleDecimalPlaceNumbers: true,
|
|
1279
|
-
forceUKStyle: false
|
|
1280
|
-
};
|
|
1281
|
-
function splitEasy(str, originalOpts) {
|
|
1282
|
-
let colStarts = 0;
|
|
1283
|
-
let lineBreakStarts = 0;
|
|
1284
|
-
let rowArray = [];
|
|
1285
|
-
const resArray = [];
|
|
1286
|
-
let ignoreCommasThatFollow = false;
|
|
1287
|
-
let thisRowContainsOnlyEmptySpace = true;
|
|
1288
|
-
if (originalOpts && typeof originalOpts !== "object") {
|
|
1289
|
-
throw new Error(`csv-split-easy/split(): [THROW_ID_02] Options object must be a plain object! Currently it's of a type ${typeof originalOpts} equal to:\n${JSON.stringify(originalOpts, null, 4)}`);
|
|
1290
|
-
}
|
|
1291
|
-
const opts = { ...defaults$1,
|
|
1292
|
-
...originalOpts
|
|
1293
|
-
};
|
|
1294
|
-
if (typeof str !== "string") {
|
|
1295
|
-
throw new TypeError(`csv-split-easy/split(): [THROW_ID_04] input must be string! Currently it's: ${typeof str}, equal to: ${JSON.stringify(str, null, 4)}`);
|
|
1296
|
-
} else {
|
|
1297
|
-
if (str === "") {
|
|
1298
|
-
return [[""]];
|
|
1299
|
-
}
|
|
1300
|
-
str = str.trim();
|
|
1301
|
-
}
|
|
1302
|
-
for (let i = 0, len = str.length; i < len; i++) {
|
|
1303
|
-
if (thisRowContainsOnlyEmptySpace && str[i] !== '"' && str[i] !== "," && str[i].trim() !== "") {
|
|
1304
|
-
thisRowContainsOnlyEmptySpace = false;
|
|
1305
|
-
}
|
|
1306
|
-
if (str[i] === '"') {
|
|
1307
|
-
if (ignoreCommasThatFollow && str[i + 1] === '"') {
|
|
1308
|
-
i += 1;
|
|
1309
|
-
} else if (ignoreCommasThatFollow) {
|
|
1310
|
-
ignoreCommasThatFollow = false;
|
|
1311
|
-
const newElem = str.slice(colStarts, i);
|
|
1312
|
-
if (newElem.trim() !== "") {
|
|
1313
|
-
thisRowContainsOnlyEmptySpace = false;
|
|
1314
|
-
}
|
|
1315
|
-
const processedElem = /""/.test(newElem) ? newElem.replace(/""/g, '"') : remSep(newElem, {
|
|
1316
|
-
removeThousandSeparatorsFromNumbers: opts.removeThousandSeparatorsFromNumbers,
|
|
1317
|
-
padSingleDecimalPlaceNumbers: opts.padSingleDecimalPlaceNumbers,
|
|
1318
|
-
forceUKStyle: opts.forceUKStyle
|
|
1319
|
-
});
|
|
1320
|
-
rowArray.push(processedElem);
|
|
1321
|
-
} else {
|
|
1322
|
-
ignoreCommasThatFollow = true;
|
|
1323
|
-
colStarts = i + 1;
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
else if (!ignoreCommasThatFollow && str[i] === ",") {
|
|
1327
|
-
if (str[i - 1] !== '"' && !ignoreCommasThatFollow) {
|
|
1328
|
-
const newElem = str.slice(colStarts, i);
|
|
1329
|
-
if (newElem.trim() !== "") {
|
|
1330
|
-
thisRowContainsOnlyEmptySpace = false;
|
|
1331
|
-
}
|
|
1332
|
-
rowArray.push(remSep(newElem,
|
|
1333
|
-
{
|
|
1334
|
-
removeThousandSeparatorsFromNumbers: opts.removeThousandSeparatorsFromNumbers,
|
|
1335
|
-
padSingleDecimalPlaceNumbers: opts.padSingleDecimalPlaceNumbers,
|
|
1336
|
-
forceUKStyle: opts.forceUKStyle
|
|
1337
|
-
}));
|
|
1338
|
-
}
|
|
1339
|
-
colStarts = i + 1;
|
|
1340
|
-
if (lineBreakStarts) {
|
|
1341
|
-
lineBreakStarts = 0;
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
else if (str[i] === "\n" || str[i] === "\r") {
|
|
1345
|
-
if (!lineBreakStarts) {
|
|
1346
|
-
lineBreakStarts = i;
|
|
1347
|
-
if (!ignoreCommasThatFollow && str[i - 1] !== '"') {
|
|
1348
|
-
const newElem = str.slice(colStarts, i);
|
|
1349
|
-
if (newElem.trim() !== "") {
|
|
1350
|
-
thisRowContainsOnlyEmptySpace = false;
|
|
1351
|
-
}
|
|
1352
|
-
rowArray.push(remSep(newElem, {
|
|
1353
|
-
removeThousandSeparatorsFromNumbers: opts.removeThousandSeparatorsFromNumbers,
|
|
1354
|
-
padSingleDecimalPlaceNumbers: opts.padSingleDecimalPlaceNumbers,
|
|
1355
|
-
forceUKStyle: opts.forceUKStyle
|
|
1356
|
-
}));
|
|
1357
|
-
}
|
|
1358
|
-
if (!thisRowContainsOnlyEmptySpace) {
|
|
1359
|
-
resArray.push(rowArray);
|
|
1360
|
-
} else {
|
|
1361
|
-
rowArray.length = 0;
|
|
1362
|
-
}
|
|
1363
|
-
thisRowContainsOnlyEmptySpace = true;
|
|
1364
|
-
rowArray = [];
|
|
1365
|
-
}
|
|
1366
|
-
colStarts = i + 1;
|
|
1367
|
-
}
|
|
1368
|
-
else if (lineBreakStarts) {
|
|
1369
|
-
lineBreakStarts = 0;
|
|
1370
|
-
colStarts = i;
|
|
1371
|
-
}
|
|
1372
|
-
if (i + 1 === len) {
|
|
1373
|
-
if (str[i] !== '"') {
|
|
1374
|
-
const newElem = str.slice(colStarts, i + 1);
|
|
1375
|
-
if (newElem.trim()) {
|
|
1376
|
-
thisRowContainsOnlyEmptySpace = false;
|
|
1377
|
-
}
|
|
1378
|
-
rowArray.push(remSep(newElem, {
|
|
1379
|
-
removeThousandSeparatorsFromNumbers: opts.removeThousandSeparatorsFromNumbers,
|
|
1380
|
-
padSingleDecimalPlaceNumbers: opts.padSingleDecimalPlaceNumbers,
|
|
1381
|
-
forceUKStyle: opts.forceUKStyle
|
|
1382
|
-
}));
|
|
1383
|
-
}
|
|
1384
|
-
if (!thisRowContainsOnlyEmptySpace) {
|
|
1385
|
-
resArray.push(rowArray);
|
|
1386
|
-
} else {
|
|
1387
|
-
rowArray = [];
|
|
1388
|
-
}
|
|
1389
|
-
thisRowContainsOnlyEmptySpace = true;
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
if (resArray.length === 0) {
|
|
1393
|
-
return [[""]];
|
|
1394
|
-
}
|
|
1395
|
-
return resArray;
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
/*!
|
|
1399
|
-
* currency.js - v2.0.3
|
|
1400
|
-
* http://scurker.github.io/currency.js
|
|
1401
|
-
*
|
|
1402
|
-
* Copyright (c) 2020 Jason Wilson
|
|
1403
|
-
* Released under MIT license
|
|
1404
|
-
*/
|
|
1405
|
-
|
|
1406
|
-
var defaults = {
|
|
1407
|
-
symbol: '$',
|
|
1408
|
-
separator: ',',
|
|
1409
|
-
decimal: '.',
|
|
1410
|
-
errorOnInvalid: false,
|
|
1411
|
-
precision: 2,
|
|
1412
|
-
pattern: '!#',
|
|
1413
|
-
negativePattern: '-!#',
|
|
1414
|
-
format: format,
|
|
1415
|
-
fromCents: false
|
|
1416
|
-
};
|
|
1417
|
-
|
|
1418
|
-
var round = function round(v) {
|
|
1419
|
-
return Math.round(v);
|
|
1420
|
-
};
|
|
1421
|
-
|
|
1422
|
-
var pow = function pow(p) {
|
|
1423
|
-
return Math.pow(10, p);
|
|
1424
|
-
};
|
|
1425
|
-
|
|
1426
|
-
var rounding = function rounding(value, increment) {
|
|
1427
|
-
return round(value / increment) * increment;
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
var groupRegex = /(\d)(?=(\d{3})+\b)/g;
|
|
1431
|
-
var vedicRegex = /(\d)(?=(\d\d)+\d\b)/g;
|
|
1432
|
-
/**
|
|
1433
|
-
* Create a new instance of currency.js
|
|
1434
|
-
* @param {number|string|currency} value
|
|
1435
|
-
* @param {object} [opts]
|
|
1436
|
-
*/
|
|
1437
|
-
|
|
1438
|
-
function currency(value, opts) {
|
|
1439
|
-
var that = this;
|
|
1440
|
-
|
|
1441
|
-
if (!(that instanceof currency)) {
|
|
1442
|
-
return new currency(value, opts);
|
|
1443
|
-
}
|
|
1444
|
-
|
|
1445
|
-
var settings = Object.assign({}, defaults, opts),
|
|
1446
|
-
precision = pow(settings.precision),
|
|
1447
|
-
v = parse(value, settings);
|
|
1448
|
-
that.intValue = v;
|
|
1449
|
-
that.value = v / precision; // Set default incremental value
|
|
1450
|
-
|
|
1451
|
-
settings.increment = settings.increment || 1 / precision; // Support vedic numbering systems
|
|
1452
|
-
// see: https://en.wikipedia.org/wiki/Indian_numbering_system
|
|
1453
|
-
|
|
1454
|
-
if (settings.useVedic) {
|
|
1455
|
-
settings.groups = vedicRegex;
|
|
1456
|
-
} else {
|
|
1457
|
-
settings.groups = groupRegex;
|
|
1458
|
-
} // Intended for internal usage only - subject to change
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
this.s = settings;
|
|
1462
|
-
this.p = precision;
|
|
1463
|
-
}
|
|
1464
|
-
|
|
1465
|
-
function parse(value, opts) {
|
|
1466
|
-
var useRounding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
1467
|
-
var v = 0,
|
|
1468
|
-
decimal = opts.decimal,
|
|
1469
|
-
errorOnInvalid = opts.errorOnInvalid,
|
|
1470
|
-
decimals = opts.precision,
|
|
1471
|
-
fromCents = opts.fromCents,
|
|
1472
|
-
precision = pow(decimals),
|
|
1473
|
-
isNumber = typeof value === 'number',
|
|
1474
|
-
isCurrency = value instanceof currency;
|
|
1475
|
-
|
|
1476
|
-
if (isCurrency && fromCents) {
|
|
1477
|
-
return value.intValue;
|
|
1478
|
-
}
|
|
1479
|
-
|
|
1480
|
-
if (isNumber || isCurrency) {
|
|
1481
|
-
v = isCurrency ? value.value : value;
|
|
1482
|
-
} else if (typeof value === 'string') {
|
|
1483
|
-
var regex = new RegExp('[^-\\d' + decimal + ']', 'g'),
|
|
1484
|
-
decimalString = new RegExp('\\' + decimal, 'g');
|
|
1485
|
-
v = value.replace(/\((.*)\)/, '-$1') // allow negative e.g. (1.99)
|
|
1486
|
-
.replace(regex, '') // replace any non numeric values
|
|
1487
|
-
.replace(decimalString, '.'); // convert any decimal values
|
|
1488
|
-
|
|
1489
|
-
v = v || 0;
|
|
1490
|
-
} else {
|
|
1491
|
-
if (errorOnInvalid) {
|
|
1492
|
-
throw Error('Invalid Input');
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
v = 0;
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
if (!fromCents) {
|
|
1499
|
-
v *= precision; // scale number to integer value
|
|
1500
|
-
|
|
1501
|
-
v = v.toFixed(4); // Handle additional decimal for proper rounding.
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
return useRounding ? round(v) : v;
|
|
1505
|
-
}
|
|
1506
|
-
/**
|
|
1507
|
-
* Formats a currency object
|
|
1508
|
-
* @param currency
|
|
1509
|
-
* @param {object} [opts]
|
|
1510
|
-
*/
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
function format(currency, settings) {
|
|
1514
|
-
var pattern = settings.pattern,
|
|
1515
|
-
negativePattern = settings.negativePattern,
|
|
1516
|
-
symbol = settings.symbol,
|
|
1517
|
-
separator = settings.separator,
|
|
1518
|
-
decimal = settings.decimal,
|
|
1519
|
-
groups = settings.groups,
|
|
1520
|
-
split = ('' + currency).replace(/^-/, '').split('.'),
|
|
1521
|
-
dollars = split[0],
|
|
1522
|
-
cents = split[1];
|
|
1523
|
-
return (currency.value >= 0 ? pattern : negativePattern).replace('!', symbol).replace('#', dollars.replace(groups, '$1' + separator) + (cents ? decimal + cents : ''));
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
currency.prototype = {
|
|
1527
|
-
/**
|
|
1528
|
-
* Adds values together.
|
|
1529
|
-
* @param {number} number
|
|
1530
|
-
* @returns {currency}
|
|
1531
|
-
*/
|
|
1532
|
-
add: function add(number) {
|
|
1533
|
-
var intValue = this.intValue,
|
|
1534
|
-
_settings = this.s,
|
|
1535
|
-
_precision = this.p;
|
|
1536
|
-
return currency((intValue += parse(number, _settings)) / (_settings.fromCents ? 1 : _precision), _settings);
|
|
1537
|
-
},
|
|
1538
|
-
|
|
1539
|
-
/**
|
|
1540
|
-
* Subtracts value.
|
|
1541
|
-
* @param {number} number
|
|
1542
|
-
* @returns {currency}
|
|
1543
|
-
*/
|
|
1544
|
-
subtract: function subtract(number) {
|
|
1545
|
-
var intValue = this.intValue,
|
|
1546
|
-
_settings = this.s,
|
|
1547
|
-
_precision = this.p;
|
|
1548
|
-
return currency((intValue -= parse(number, _settings)) / (_settings.fromCents ? 1 : _precision), _settings);
|
|
1549
|
-
},
|
|
1550
|
-
|
|
1551
|
-
/**
|
|
1552
|
-
* Multiplies values.
|
|
1553
|
-
* @param {number} number
|
|
1554
|
-
* @returns {currency}
|
|
1555
|
-
*/
|
|
1556
|
-
multiply: function multiply(number) {
|
|
1557
|
-
var intValue = this.intValue,
|
|
1558
|
-
_settings = this.s;
|
|
1559
|
-
return currency((intValue *= number) / (_settings.fromCents ? 1 : pow(_settings.precision)), _settings);
|
|
1560
|
-
},
|
|
1561
|
-
|
|
1562
|
-
/**
|
|
1563
|
-
* Divides value.
|
|
1564
|
-
* @param {number} number
|
|
1565
|
-
* @returns {currency}
|
|
1566
|
-
*/
|
|
1567
|
-
divide: function divide(number) {
|
|
1568
|
-
var intValue = this.intValue,
|
|
1569
|
-
_settings = this.s;
|
|
1570
|
-
return currency(intValue /= parse(number, _settings, false), _settings);
|
|
1571
|
-
},
|
|
1572
|
-
|
|
1573
|
-
/**
|
|
1574
|
-
* Takes the currency amount and distributes the values evenly. Any extra pennies
|
|
1575
|
-
* left over from the distribution will be stacked onto the first set of entries.
|
|
1576
|
-
* @param {number} count
|
|
1577
|
-
* @returns {array}
|
|
1578
|
-
*/
|
|
1579
|
-
distribute: function distribute(count) {
|
|
1580
|
-
var intValue = this.intValue,
|
|
1581
|
-
_precision = this.p,
|
|
1582
|
-
_settings = this.s,
|
|
1583
|
-
distribution = [],
|
|
1584
|
-
split = Math[intValue >= 0 ? 'floor' : 'ceil'](intValue / count),
|
|
1585
|
-
pennies = Math.abs(intValue - split * count),
|
|
1586
|
-
precision = _settings.fromCents ? 1 : _precision;
|
|
1587
|
-
|
|
1588
|
-
for (; count !== 0; count--) {
|
|
1589
|
-
var item = currency(split / precision, _settings); // Add any left over pennies
|
|
1590
|
-
|
|
1591
|
-
pennies-- > 0 && (item = item[intValue >= 0 ? 'add' : 'subtract'](1 / precision));
|
|
1592
|
-
distribution.push(item);
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
return distribution;
|
|
1596
|
-
},
|
|
1597
|
-
|
|
1598
|
-
/**
|
|
1599
|
-
* Returns the dollar value.
|
|
1600
|
-
* @returns {number}
|
|
1601
|
-
*/
|
|
1602
|
-
dollars: function dollars() {
|
|
1603
|
-
return ~~this.value;
|
|
1604
|
-
},
|
|
1605
|
-
|
|
1606
|
-
/**
|
|
1607
|
-
* Returns the cent value.
|
|
1608
|
-
* @returns {number}
|
|
1609
|
-
*/
|
|
1610
|
-
cents: function cents() {
|
|
1611
|
-
var intValue = this.intValue,
|
|
1612
|
-
_precision = this.p;
|
|
1613
|
-
return ~~(intValue % _precision);
|
|
1614
|
-
},
|
|
1615
|
-
|
|
1616
|
-
/**
|
|
1617
|
-
* Formats the value as a string according to the formatting settings.
|
|
1618
|
-
* @param {boolean} useSymbol - format with currency symbol
|
|
1619
|
-
* @returns {string}
|
|
1620
|
-
*/
|
|
1621
|
-
format: function format(options) {
|
|
1622
|
-
var _settings = this.s;
|
|
1623
|
-
|
|
1624
|
-
if (typeof options === 'function') {
|
|
1625
|
-
return options(this, _settings);
|
|
1626
|
-
}
|
|
1627
|
-
|
|
1628
|
-
return _settings.format(this, Object.assign({}, _settings, options));
|
|
1629
|
-
},
|
|
1630
|
-
|
|
1631
|
-
/**
|
|
1632
|
-
* Formats the value as a string according to the formatting settings.
|
|
1633
|
-
* @returns {string}
|
|
1634
|
-
*/
|
|
1635
|
-
toString: function toString() {
|
|
1636
|
-
var intValue = this.intValue,
|
|
1637
|
-
_precision = this.p,
|
|
1638
|
-
_settings = this.s;
|
|
1639
|
-
return rounding(intValue / _precision, _settings.increment).toFixed(_settings.precision);
|
|
1640
|
-
},
|
|
1641
|
-
|
|
1642
|
-
/**
|
|
1643
|
-
* Value for JSON serialization.
|
|
1644
|
-
* @returns {float}
|
|
1645
|
-
*/
|
|
1646
|
-
toJSON: function toJSON() {
|
|
1647
|
-
return this.value;
|
|
1648
|
-
}
|
|
1649
|
-
};
|
|
1650
|
-
|
|
1651
|
-
function isNumeric(str) {
|
|
1652
|
-
// if (typeof str === "number") {
|
|
1653
|
-
// return true;
|
|
1654
|
-
// }
|
|
1655
|
-
// if (!String(str).trim()) {
|
|
1656
|
-
if (!str.trim()) {
|
|
1657
|
-
return false;
|
|
1658
|
-
}
|
|
1659
|
-
return Number(str) === Number(str);
|
|
1660
|
-
}
|
|
1661
|
-
const currencySigns = [
|
|
1662
|
-
"د.إ",
|
|
1663
|
-
"؋",
|
|
1664
|
-
"L",
|
|
1665
|
-
"֏",
|
|
1666
|
-
"ƒ",
|
|
1667
|
-
"Kz",
|
|
1668
|
-
"$",
|
|
1669
|
-
"ƒ",
|
|
1670
|
-
"₼",
|
|
1671
|
-
"KM",
|
|
1672
|
-
"৳",
|
|
1673
|
-
"лв",
|
|
1674
|
-
".د.ب",
|
|
1675
|
-
"FBu",
|
|
1676
|
-
"$b",
|
|
1677
|
-
"R$",
|
|
1678
|
-
"฿",
|
|
1679
|
-
"Nu.",
|
|
1680
|
-
"P",
|
|
1681
|
-
"p.",
|
|
1682
|
-
"BZ$",
|
|
1683
|
-
"FC",
|
|
1684
|
-
"CHF",
|
|
1685
|
-
"¥",
|
|
1686
|
-
"₡",
|
|
1687
|
-
"₱",
|
|
1688
|
-
"Kč",
|
|
1689
|
-
"Fdj",
|
|
1690
|
-
"kr",
|
|
1691
|
-
"RD$",
|
|
1692
|
-
"دج",
|
|
1693
|
-
"kr",
|
|
1694
|
-
"Nfk",
|
|
1695
|
-
"Br",
|
|
1696
|
-
"Ξ",
|
|
1697
|
-
"€",
|
|
1698
|
-
"₾",
|
|
1699
|
-
"₵",
|
|
1700
|
-
"GH₵",
|
|
1701
|
-
"D",
|
|
1702
|
-
"FG",
|
|
1703
|
-
"Q",
|
|
1704
|
-
"L",
|
|
1705
|
-
"kn",
|
|
1706
|
-
"G",
|
|
1707
|
-
"Ft",
|
|
1708
|
-
"Rp",
|
|
1709
|
-
"₪",
|
|
1710
|
-
"₹",
|
|
1711
|
-
"ع.د",
|
|
1712
|
-
"﷼",
|
|
1713
|
-
"kr",
|
|
1714
|
-
"J$",
|
|
1715
|
-
"JD",
|
|
1716
|
-
"¥",
|
|
1717
|
-
"KSh",
|
|
1718
|
-
"лв",
|
|
1719
|
-
"៛",
|
|
1720
|
-
"CF",
|
|
1721
|
-
"₩",
|
|
1722
|
-
"₩",
|
|
1723
|
-
"KD",
|
|
1724
|
-
"лв",
|
|
1725
|
-
"₭",
|
|
1726
|
-
"₨",
|
|
1727
|
-
"M",
|
|
1728
|
-
"Ł",
|
|
1729
|
-
"Lt",
|
|
1730
|
-
"Ls",
|
|
1731
|
-
"LD",
|
|
1732
|
-
"MAD",
|
|
1733
|
-
"lei",
|
|
1734
|
-
"Ar",
|
|
1735
|
-
"ден",
|
|
1736
|
-
"K",
|
|
1737
|
-
"₮",
|
|
1738
|
-
"MOP$",
|
|
1739
|
-
"UM",
|
|
1740
|
-
"₨",
|
|
1741
|
-
"Rf",
|
|
1742
|
-
"MK",
|
|
1743
|
-
"RM",
|
|
1744
|
-
"MT",
|
|
1745
|
-
"₦",
|
|
1746
|
-
"C$",
|
|
1747
|
-
"kr",
|
|
1748
|
-
"₨",
|
|
1749
|
-
"﷼",
|
|
1750
|
-
"B/.",
|
|
1751
|
-
"S/.",
|
|
1752
|
-
"K",
|
|
1753
|
-
"₱",
|
|
1754
|
-
"₨",
|
|
1755
|
-
"zł",
|
|
1756
|
-
"Gs",
|
|
1757
|
-
"﷼",
|
|
1758
|
-
"¥",
|
|
1759
|
-
"lei",
|
|
1760
|
-
"Дин.",
|
|
1761
|
-
"₽",
|
|
1762
|
-
"R₣",
|
|
1763
|
-
"﷼",
|
|
1764
|
-
"₨",
|
|
1765
|
-
"ج.س.",
|
|
1766
|
-
"kr",
|
|
1767
|
-
"£",
|
|
1768
|
-
"Le",
|
|
1769
|
-
"S",
|
|
1770
|
-
"Db",
|
|
1771
|
-
"E",
|
|
1772
|
-
"฿",
|
|
1773
|
-
"SM",
|
|
1774
|
-
"T",
|
|
1775
|
-
"د.ت",
|
|
1776
|
-
"T$",
|
|
1777
|
-
"₤",
|
|
1778
|
-
"₺",
|
|
1779
|
-
"TT$",
|
|
1780
|
-
"NT$",
|
|
1781
|
-
"TSh",
|
|
1782
|
-
"₴",
|
|
1783
|
-
"USh",
|
|
1784
|
-
"$U",
|
|
1785
|
-
"лв",
|
|
1786
|
-
"Bs",
|
|
1787
|
-
"₫",
|
|
1788
|
-
"VT",
|
|
1789
|
-
"WS$",
|
|
1790
|
-
"FCFA",
|
|
1791
|
-
"Ƀ",
|
|
1792
|
-
"CFA",
|
|
1793
|
-
"₣",
|
|
1794
|
-
"﷼",
|
|
1795
|
-
"R",
|
|
1796
|
-
"Z$",
|
|
1797
|
-
];
|
|
1798
|
-
function findType(something) {
|
|
1799
|
-
/* istanbul ignore next */
|
|
1800
|
-
if (typeof something !== "string") {
|
|
1801
|
-
throw new Error(`csv-sort/util/findType(): input must be string! Currently it's: ${typeof something}`);
|
|
1802
|
-
}
|
|
1803
|
-
if (isNumeric(something)) {
|
|
1804
|
-
return "numeric";
|
|
1805
|
-
}
|
|
1806
|
-
/* istanbul ignore next */
|
|
1807
|
-
if (currencySigns.some((singleSign) =>
|
|
1808
|
-
// We remove all known currency symbols one by one from this input string.
|
|
1809
|
-
// If at least one passes as numeric after the currency symbol-removing, it's numeric.
|
|
1810
|
-
isNumeric(something.replace(singleSign, "").replace(/[,.]/g, "")))) {
|
|
1811
|
-
return "numeric";
|
|
1812
|
-
}
|
|
1813
|
-
if (!something.trim()) {
|
|
1814
|
-
return "empty";
|
|
1815
|
-
}
|
|
1816
|
-
return "text";
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
/**
|
|
1820
|
-
* Sorts double-entry bookkeeping CSV coming from internet banking
|
|
1821
|
-
*/
|
|
1822
|
-
function sort(input) {
|
|
1823
|
-
let msgContent = null;
|
|
1824
|
-
let msgType = null;
|
|
1825
|
-
// step 1.
|
|
1826
|
-
// ===========================
|
|
1827
|
-
// depends what was passed in,
|
|
1828
|
-
if (typeof input !== "string") {
|
|
1829
|
-
throw new TypeError(`csv-sort/csvSort(): [THROW_ID_01] The input is of a wrong type! We accept either string of array of arrays. We got instead: ${typeof input}, equal to:\n${JSON.stringify(input, null, 4)}`);
|
|
1830
|
-
}
|
|
1831
|
-
else if (!input.trim()) {
|
|
1832
|
-
return { res: [[""]], msgContent, msgType };
|
|
1833
|
-
}
|
|
1834
|
-
let content = splitEasy(input);
|
|
1835
|
-
// step 2.
|
|
1836
|
-
// ===========================
|
|
1837
|
-
// - iterate from the bottom
|
|
1838
|
-
// - calculate schema as you go to save calculation rounds
|
|
1839
|
-
// - first row can have different amount of columns
|
|
1840
|
-
// - think about 2D trim feature
|
|
1841
|
-
let schema = [];
|
|
1842
|
-
let stateHeaderRowPresent = false;
|
|
1843
|
-
let stateDataColumnRowLengthIsConsistent = true;
|
|
1844
|
-
const stateColumnsContainingSameValueEverywhere = [];
|
|
1845
|
-
// used for 2D trimming:
|
|
1846
|
-
let indexAtWhichEmptyCellsStart = null;
|
|
1847
|
-
for (let i = content.length - 1; i >= 0; i--) {
|
|
1848
|
-
if (!schema.length) {
|
|
1849
|
-
// prevention against last blank row:
|
|
1850
|
-
/* istanbul ignore next */
|
|
1851
|
-
if (content[i].length !== 1 || content[i][0] !== "") {
|
|
1852
|
-
for (let y = 0, len = content[i].length; y < len; y++) {
|
|
1853
|
-
schema.push(findType(content[i][y].trim()));
|
|
1854
|
-
if (indexAtWhichEmptyCellsStart === null &&
|
|
1855
|
-
findType(content[i][y].trim()) === "empty") {
|
|
1856
|
-
indexAtWhichEmptyCellsStart = y;
|
|
1857
|
-
}
|
|
1858
|
-
if (indexAtWhichEmptyCellsStart !== null &&
|
|
1859
|
-
findType(content[i][y].trim()) !== "empty") {
|
|
1860
|
-
indexAtWhichEmptyCellsStart = null;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
else {
|
|
1866
|
-
if (i === 0) {
|
|
1867
|
-
// Check is this header row.
|
|
1868
|
-
// Header rows should consist of only text content.
|
|
1869
|
-
// Let's iterate through all elements and find out.
|
|
1870
|
-
stateHeaderRowPresent = content[i].every((el) => findType(el) === "text" || findType(el) === "empty");
|
|
1871
|
-
// if schema was calculated (this means there's header row and at least one content row),
|
|
1872
|
-
// find out if the column length in the header differs from schema's
|
|
1873
|
-
// if (stateHeaderRowPresent && (schema.length !== content[i].length)) {
|
|
1874
|
-
// }
|
|
1875
|
-
}
|
|
1876
|
-
/* istanbul ignore else */
|
|
1877
|
-
if (!stateHeaderRowPresent && schema.length !== content[i].length) {
|
|
1878
|
-
stateDataColumnRowLengthIsConsistent = false;
|
|
1879
|
-
}
|
|
1880
|
-
let perRowIndexAtWhichEmptyCellsStart = null;
|
|
1881
|
-
for (let y = 0, len = content[i].length; y < len; y++) {
|
|
1882
|
-
// trim
|
|
1883
|
-
/* istanbul ignore else */
|
|
1884
|
-
if (perRowIndexAtWhichEmptyCellsStart === null &&
|
|
1885
|
-
findType(content[i][y].trim()) === "empty") {
|
|
1886
|
-
perRowIndexAtWhichEmptyCellsStart = y;
|
|
1887
|
-
}
|
|
1888
|
-
/* istanbul ignore else */
|
|
1889
|
-
if (perRowIndexAtWhichEmptyCellsStart !== null &&
|
|
1890
|
-
findType(content[i][y].trim()) !== "empty") {
|
|
1891
|
-
perRowIndexAtWhichEmptyCellsStart = null;
|
|
1892
|
-
}
|
|
1893
|
-
// checking schema
|
|
1894
|
-
/* istanbul ignore else */
|
|
1895
|
-
if (findType(content[i][y].trim()) !== schema[y] &&
|
|
1896
|
-
!stateHeaderRowPresent) {
|
|
1897
|
-
const toAdd = findType(content[i][y].trim());
|
|
1898
|
-
/* istanbul ignore else */
|
|
1899
|
-
if (Array.isArray(schema[y])) {
|
|
1900
|
-
if (!schema[y].includes(toAdd)) {
|
|
1901
|
-
schema[y].push(findType(content[i][y].trim()));
|
|
1902
|
-
}
|
|
1903
|
-
}
|
|
1904
|
-
else if (schema[y] !== toAdd) {
|
|
1905
|
-
const temp = schema[y];
|
|
1906
|
-
schema[y] = [];
|
|
1907
|
-
schema[y].push(temp);
|
|
1908
|
-
schema[y].push(toAdd);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
// when row has finished, get the perRowIndexAtWhichEmptyCellsStart
|
|
1913
|
-
// that's to cover cases where last row got schema calculated, but it
|
|
1914
|
-
// had more empty columns than the following rows:
|
|
1915
|
-
//
|
|
1916
|
-
// [8, 9, 0, 1, , ]
|
|
1917
|
-
// [4, 5, 6, 7, , ] <<< perRowIndexAtWhichEmptyCellsStart would be 3 (indexes start at zero)
|
|
1918
|
-
// [1, 2, 3, , , ] <<< indexAtWhichEmptyCellsStart would be here 2 (indexes start at zero)
|
|
1919
|
-
//
|
|
1920
|
-
// as a result, indexAtWhichEmptyCellsStart above would be assigned to 3, not 2
|
|
1921
|
-
//
|
|
1922
|
-
// That's still an achievement, we "trimmed" CSV by two places.
|
|
1923
|
-
// I'm saying "trimmed", but we're not really trimming yet, we're only
|
|
1924
|
-
// setting inner variable which we will later use to limit the traversal,
|
|
1925
|
-
// so algorithm skips those empty columns.
|
|
1926
|
-
//
|
|
1927
|
-
/* istanbul ignore next */
|
|
1928
|
-
if (indexAtWhichEmptyCellsStart !== null &&
|
|
1929
|
-
perRowIndexAtWhichEmptyCellsStart !== null &&
|
|
1930
|
-
perRowIndexAtWhichEmptyCellsStart > indexAtWhichEmptyCellsStart &&
|
|
1931
|
-
(!stateHeaderRowPresent || (stateHeaderRowPresent && i !== 0))) {
|
|
1932
|
-
indexAtWhichEmptyCellsStart = perRowIndexAtWhichEmptyCellsStart;
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
/* istanbul ignore else */
|
|
1937
|
-
if (!indexAtWhichEmptyCellsStart) {
|
|
1938
|
-
indexAtWhichEmptyCellsStart = schema.length;
|
|
1939
|
-
}
|
|
1940
|
-
// find out at which index non-empty columns start. This is effectively left-side trimming.
|
|
1941
|
-
let nonEmptyColsStartAt = 0;
|
|
1942
|
-
for (let i = 0, len = schema.length; i < len; i++) {
|
|
1943
|
-
if (schema[i] === "empty") {
|
|
1944
|
-
nonEmptyColsStartAt = i;
|
|
1945
|
-
}
|
|
1946
|
-
else {
|
|
1947
|
-
break;
|
|
1948
|
-
}
|
|
1949
|
-
}
|
|
1950
|
-
// if there are empty column in front, trim (via slice) both content and schema
|
|
1951
|
-
/* istanbul ignore else */
|
|
1952
|
-
if (nonEmptyColsStartAt !== 0) {
|
|
1953
|
-
content = content.map((arr) => arr.slice(nonEmptyColsStartAt + 1, indexAtWhichEmptyCellsStart));
|
|
1954
|
-
schema = schema.slice(nonEmptyColsStartAt + 1, indexAtWhichEmptyCellsStart);
|
|
1955
|
-
}
|
|
1956
|
-
// step 3.
|
|
1957
|
-
// ===========================
|
|
1958
|
-
// CHALLENGE: without any assumptions, identify "current balance" and "debit",
|
|
1959
|
-
// "credit" columns by analysing their values.
|
|
1960
|
-
//
|
|
1961
|
-
// - double entry accounting rows will have the "current balance" which will
|
|
1962
|
-
// be strictly numeric, and will be present across all rows. These are the
|
|
1963
|
-
// two first signs of a "current balance" column.
|
|
1964
|
-
// - "current balance" should also match up with at least one field under it,
|
|
1965
|
-
// if subracted/added the value from one field in its row
|
|
1966
|
-
// swoop in traversing the schema array to get "numeric" columns:
|
|
1967
|
-
// ----------------
|
|
1968
|
-
const numericSchemaColumns = [];
|
|
1969
|
-
let balanceColumnIndex;
|
|
1970
|
-
schema.forEach((colType, i) => {
|
|
1971
|
-
if (colType === "numeric") {
|
|
1972
|
-
numericSchemaColumns.push(i);
|
|
1973
|
-
}
|
|
1974
|
-
});
|
|
1975
|
-
const traverseUpToThisIndexAtTheTop = stateHeaderRowPresent ? 1 : 0;
|
|
1976
|
-
if (numericSchemaColumns.length === 1) {
|
|
1977
|
-
// Bob's your uncle, the only numeric column is your Balance column
|
|
1978
|
-
balanceColumnIndex = numericSchemaColumns[0];
|
|
1979
|
-
}
|
|
1980
|
-
else if (numericSchemaColumns.length === 0) {
|
|
1981
|
-
throw new Error('csv-sort/csvSort(): [THROW_ID_03] Your CSV file does not contain numeric-only columns and computer was not able to detect the "Balance" column!');
|
|
1982
|
-
}
|
|
1983
|
-
else {
|
|
1984
|
-
// So (numericSchemaColumns > 0) and we'll have to do some work.
|
|
1985
|
-
// Fine.
|
|
1986
|
-
//
|
|
1987
|
-
// Clone numericSchemaColumns array, remove columns that have the same value
|
|
1988
|
-
// among consecutive rows.
|
|
1989
|
-
// For example, accounting CSV's will have "Account number" repeated.
|
|
1990
|
-
// Balance is never the same on two rows, otherwise what's the point of
|
|
1991
|
-
// accounting if nothing happened?
|
|
1992
|
-
// Traverse the CSV vertically on each column from numericSchemaColumns and
|
|
1993
|
-
// find out `balanceColumnIndex`:
|
|
1994
|
-
// ----------------
|
|
1995
|
-
let potentialBalanceColumnIndexesList = Array.from(numericSchemaColumns);
|
|
1996
|
-
// iterate through `potentialBalanceColumnIndexesList`
|
|
1997
|
-
const deleteFromPotentialBalanceColumnIndexesList = [];
|
|
1998
|
-
for (let i = 0, len = potentialBalanceColumnIndexesList.length; i < len; i++) {
|
|
1999
|
-
// if any two rows are in sequence currently and they are equal, this column is out
|
|
2000
|
-
const suspectedBalanceColumnsIndexNumber = potentialBalanceColumnIndexesList[i];
|
|
2001
|
-
// we traverse column suspected to be "Balance" with index `index` vertically,
|
|
2002
|
-
// from the top to bottom. Depending if there's heading row, we start at 0 or 1,
|
|
2003
|
-
// which is set by `traverseUpToThisIndexAtTheTop`.
|
|
2004
|
-
// We will look for two rows having the same value. If it's found that column is
|
|
2005
|
-
// not "Balance":
|
|
2006
|
-
// EASY ATTEMPT TO RULE-OUT NOT-BALANCE COLUMNS
|
|
2007
|
-
let previousValue; // to check if two consecutive are the same
|
|
2008
|
-
let lookForTwoEqualAndConsecutive = true;
|
|
2009
|
-
let firstValue; // to check if all are the same
|
|
2010
|
-
let lookForAllTheSame = true;
|
|
2011
|
-
for (let rowNum = traverseUpToThisIndexAtTheTop, len2 = content.length; rowNum < len2; rowNum++) {
|
|
2012
|
-
// 1. check for two consecutive equal values
|
|
2013
|
-
/* istanbul ignore else */
|
|
2014
|
-
if (lookForTwoEqualAndConsecutive) {
|
|
2015
|
-
// deliberate == to catch undefined and null
|
|
2016
|
-
if (previousValue == null) {
|
|
2017
|
-
previousValue = content[rowNum][suspectedBalanceColumnsIndexNumber];
|
|
2018
|
-
}
|
|
2019
|
-
else if (previousValue ===
|
|
2020
|
-
content[rowNum][suspectedBalanceColumnsIndexNumber]) {
|
|
2021
|
-
// potentialBalanceColumnIndexesList.splice(suspectedBalanceColumnsIndexNumber, 1)
|
|
2022
|
-
// don't mutate the `potentialBalanceColumnIndexesList`, do it later.
|
|
2023
|
-
// Let's compile TO-DELETE list instead:
|
|
2024
|
-
deleteFromPotentialBalanceColumnIndexesList.push(suspectedBalanceColumnsIndexNumber);
|
|
2025
|
-
lookForTwoEqualAndConsecutive = false;
|
|
2026
|
-
}
|
|
2027
|
-
else {
|
|
2028
|
-
previousValue = content[rowNum][suspectedBalanceColumnsIndexNumber];
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
// 2. also, tell if ALL values are the same:
|
|
2032
|
-
/* istanbul ignore else */
|
|
2033
|
-
if (lookForAllTheSame) {
|
|
2034
|
-
// deliberate == to catch undefined and null
|
|
2035
|
-
if (firstValue == null) {
|
|
2036
|
-
firstValue = content[rowNum][suspectedBalanceColumnsIndexNumber];
|
|
2037
|
-
}
|
|
2038
|
-
else if (content[rowNum][suspectedBalanceColumnsIndexNumber] !== firstValue) {
|
|
2039
|
-
lookForAllTheSame = false;
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
if (!lookForTwoEqualAndConsecutive) {
|
|
2043
|
-
break;
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
/* istanbul ignore else */
|
|
2047
|
-
if (lookForAllTheSame) {
|
|
2048
|
-
stateColumnsContainingSameValueEverywhere.push(suspectedBalanceColumnsIndexNumber);
|
|
2049
|
-
}
|
|
2050
|
-
}
|
|
2051
|
-
// now mutate the `potentialBalanceColumnIndexesList` using
|
|
2052
|
-
// `deleteFromPotentialBalanceColumnIndexesList`:
|
|
2053
|
-
potentialBalanceColumnIndexesList = lodash_pull(potentialBalanceColumnIndexesList, ...deleteFromPotentialBalanceColumnIndexesList);
|
|
2054
|
-
/* istanbul ignore else */
|
|
2055
|
-
if (potentialBalanceColumnIndexesList.length === 1) {
|
|
2056
|
-
balanceColumnIndex = potentialBalanceColumnIndexesList[0];
|
|
2057
|
-
}
|
|
2058
|
-
else if (potentialBalanceColumnIndexesList.length === 0) {
|
|
2059
|
-
throw new Error('csv-sort/csvSort(): [THROW_ID_04] The computer can\'t find the "Balance" column! It saw some numeric-only columns, but they all seem to have certain rows with the same values as rows right below/above them!');
|
|
2060
|
-
}
|
|
2061
|
-
else ;
|
|
2062
|
-
// at this point 99% of normal-size, real-life bank account CSV's should have
|
|
2063
|
-
// "Balance" column identified because there will be both "Credit" and "Debit"
|
|
2064
|
-
// transaction rows which will be not exclusively numeric, but ["empty", "numeric"] type.
|
|
2065
|
-
// Even Lloyds Business banking CSV's that output account numbers
|
|
2066
|
-
// will have "Balance" column identified this stage.
|
|
2067
|
-
}
|
|
2068
|
-
if (!balanceColumnIndex) {
|
|
2069
|
-
throw new Error("csv-sort/csvSort(): [THROW_ID_05] Sadly computer couldn't find its way in this CSV and had to stop working on it.");
|
|
2070
|
-
}
|
|
2071
|
-
// step 4.
|
|
2072
|
-
// ===========================
|
|
2073
|
-
// query the schema and find out potential Credit/Debit columns
|
|
2074
|
-
// take schema, filter all indexes that are equal to or are arrays and have
|
|
2075
|
-
// "numeric" among their values, then remove the index of "Balance" column:
|
|
2076
|
-
const potentialCreditDebitColumns = lodash_pull(Array.from(schema.reduce((result, el, index) => {
|
|
2077
|
-
if ((typeof el === "string" && el === "numeric") ||
|
|
2078
|
-
(Array.isArray(el) && el.includes("numeric"))) {
|
|
2079
|
-
result.push(index);
|
|
2080
|
-
}
|
|
2081
|
-
return result;
|
|
2082
|
-
}, [])), balanceColumnIndex, ...stateColumnsContainingSameValueEverywhere);
|
|
2083
|
-
// step 5.
|
|
2084
|
-
// ===========================
|
|
2085
|
-
const resContent = [];
|
|
2086
|
-
// Now that we know the `balanceColumnIndex`, traverse the CSV rows again,
|
|
2087
|
-
// assembling a new array
|
|
2088
|
-
// step 5.1. Put the last row into the new array.
|
|
2089
|
-
// ---------------------------------------------------------------------------
|
|
2090
|
-
// Worst case scenario, if it doesn't match with anything, we'll throw in the end.
|
|
2091
|
-
// For now, let's assume CSV is correct, only rows are mixed.
|
|
2092
|
-
resContent.push(content[content.length - 1].slice(0, indexAtWhichEmptyCellsStart));
|
|
2093
|
-
const usedUpRows = [];
|
|
2094
|
-
const bottom = stateHeaderRowPresent ? 1 : 0;
|
|
2095
|
-
for (let y = content.length - 2; y >= bottom; y--) {
|
|
2096
|
-
// for each row above the last-one (which is already in place), we'll traverse
|
|
2097
|
-
// all the rows above to find the match.
|
|
2098
|
-
// go through all the rows and pick the right row which matches to the above:
|
|
2099
|
-
for (let suspectedRowsIndex = content.length - 2; suspectedRowsIndex >= bottom; suspectedRowsIndex--) {
|
|
2100
|
-
if (!usedUpRows.includes(suspectedRowsIndex)) {
|
|
2101
|
-
// go through each of the suspected Credit/Debit columns:
|
|
2102
|
-
let thisRowIsDone = false;
|
|
2103
|
-
for (let suspectedColIndex = 0, len = potentialCreditDebitColumns.length; suspectedColIndex < len; suspectedColIndex++) {
|
|
2104
|
-
let diffVal = null;
|
|
2105
|
-
if (content[suspectedRowsIndex][potentialCreditDebitColumns[suspectedColIndex]] !== "") {
|
|
2106
|
-
diffVal = currency(content[suspectedRowsIndex][potentialCreditDebitColumns[suspectedColIndex]]);
|
|
2107
|
-
}
|
|
2108
|
-
let totalVal = null;
|
|
2109
|
-
/* istanbul ignore else */
|
|
2110
|
-
if (content[suspectedRowsIndex][balanceColumnIndex] !== "") {
|
|
2111
|
-
totalVal = currency(content[suspectedRowsIndex][balanceColumnIndex]);
|
|
2112
|
-
}
|
|
2113
|
-
let topmostResContentBalance = null;
|
|
2114
|
-
/* istanbul ignore else */
|
|
2115
|
-
if (resContent[0][balanceColumnIndex] !== "") {
|
|
2116
|
-
topmostResContentBalance = currency(resContent[0][balanceColumnIndex]).format();
|
|
2117
|
-
}
|
|
2118
|
-
let currentRowsDiffVal = null;
|
|
2119
|
-
/* istanbul ignore else */
|
|
2120
|
-
if (resContent[resContent.length - 1][potentialCreditDebitColumns[suspectedColIndex]] !== "") {
|
|
2121
|
-
currentRowsDiffVal = currency(resContent[resContent.length - 1][potentialCreditDebitColumns[suspectedColIndex]]).format();
|
|
2122
|
-
}
|
|
2123
|
-
let lastResContentRowsBalance = null;
|
|
2124
|
-
/* istanbul ignore else */
|
|
2125
|
-
if (resContent[resContent.length - 1][balanceColumnIndex] !== "") {
|
|
2126
|
-
lastResContentRowsBalance = currency(resContent[resContent.length - 1][balanceColumnIndex]);
|
|
2127
|
-
}
|
|
2128
|
-
/* istanbul ignore else */
|
|
2129
|
-
if (diffVal &&
|
|
2130
|
-
totalVal.add(diffVal).format() ===
|
|
2131
|
-
topmostResContentBalance) {
|
|
2132
|
-
// ADD THIS ROW ABOVE EVERYTHING
|
|
2133
|
-
// add this row above the current HEAD in resContent lines array (index `0`)
|
|
2134
|
-
resContent.unshift(content[suspectedRowsIndex].slice(0, indexAtWhichEmptyCellsStart));
|
|
2135
|
-
usedUpRows.push(suspectedRowsIndex);
|
|
2136
|
-
thisRowIsDone = true;
|
|
2137
|
-
break;
|
|
2138
|
-
}
|
|
2139
|
-
else if (diffVal &&
|
|
2140
|
-
totalVal.subtract(diffVal).format() ===
|
|
2141
|
-
topmostResContentBalance) {
|
|
2142
|
-
// ADD THIS ROW ABOVE EVERYTHING
|
|
2143
|
-
resContent.unshift(content[suspectedRowsIndex].slice(0, indexAtWhichEmptyCellsStart));
|
|
2144
|
-
usedUpRows.push(suspectedRowsIndex);
|
|
2145
|
-
thisRowIsDone = true;
|
|
2146
|
-
break;
|
|
2147
|
-
}
|
|
2148
|
-
else if (currentRowsDiffVal &&
|
|
2149
|
-
lastResContentRowsBalance
|
|
2150
|
-
.add(currentRowsDiffVal)
|
|
2151
|
-
.format() === totalVal.format()) {
|
|
2152
|
-
// ADD THIS ROW BELOW EVERYTHING
|
|
2153
|
-
resContent.push(content[suspectedRowsIndex].slice(0, indexAtWhichEmptyCellsStart));
|
|
2154
|
-
usedUpRows.push(suspectedRowsIndex);
|
|
2155
|
-
thisRowIsDone = true;
|
|
2156
|
-
break;
|
|
2157
|
-
}
|
|
2158
|
-
else if (currentRowsDiffVal &&
|
|
2159
|
-
lastResContentRowsBalance
|
|
2160
|
-
.subtract(currentRowsDiffVal)
|
|
2161
|
-
.format() === totalVal.format()) {
|
|
2162
|
-
// ADD THIS ROW BELOW EVERYTHING
|
|
2163
|
-
resContent.push(content[suspectedRowsIndex].slice(0, indexAtWhichEmptyCellsStart));
|
|
2164
|
-
usedUpRows.push(suspectedRowsIndex);
|
|
2165
|
-
thisRowIsDone = true;
|
|
2166
|
-
break;
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
/* istanbul ignore else */
|
|
2170
|
-
if (thisRowIsDone) {
|
|
2171
|
-
thisRowIsDone = false;
|
|
2172
|
-
break;
|
|
2173
|
-
}
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
// restore title row if present
|
|
2178
|
-
/* istanbul ignore else */
|
|
2179
|
-
if (stateHeaderRowPresent) {
|
|
2180
|
-
// trim header row of trailing empty columns if they protrude outside of the (consistent row length) schema
|
|
2181
|
-
if (stateDataColumnRowLengthIsConsistent &&
|
|
2182
|
-
content[0].length > schema.length) {
|
|
2183
|
-
content[0].length = schema.length;
|
|
2184
|
-
}
|
|
2185
|
-
// push header row on top of the results array:
|
|
2186
|
-
resContent.unshift(content[0].slice(0, indexAtWhichEmptyCellsStart));
|
|
2187
|
-
}
|
|
2188
|
-
/* istanbul ignore else */
|
|
2189
|
-
if (content.length - (stateHeaderRowPresent ? 2 : 1) !== usedUpRows.length) {
|
|
2190
|
-
msgContent = "Not all rows were recognised!";
|
|
2191
|
-
msgType = "alert";
|
|
2192
|
-
}
|
|
2193
|
-
return {
|
|
2194
|
-
res: resContent,
|
|
2195
|
-
msgContent,
|
|
2196
|
-
msgType,
|
|
2197
|
-
};
|
|
2198
|
-
}
|
|
2199
|
-
|
|
2200
|
-
exports.sort = sort;
|
|
2201
|
-
|
|
2202
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2203
|
-
|
|
2204
|
-
})));
|