@lowentry/utils 0.2.1 → 1.0.1

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/LeTypes.js CHANGED
@@ -1,16 +1,3 @@
1
- import FastDeepEqual from 'fast-deep-equal';
2
-
3
-
4
- /**
5
- * A deep equals implementation (npm package "fast-deep-equal").
6
- *
7
- * @param {*} value The value to compare.
8
- * @param {*} other The other value to compare.
9
- * @returns {boolean} Returns true if the values are equivalent.
10
- */
11
- export const EQUAL = FastDeepEqual;
12
-
13
-
14
1
  /**
15
2
  * Returns true if the value is set (not undefined and not null).
16
3
  *
package/LeUtils.js CHANGED
@@ -1,7 +1,49 @@
1
+ import FastDeepEqual from 'fast-deep-equal';
1
2
  import {ISSET, IS_OBJECT, STRING, INT_LAX, FLOAT_LAX, INT_LAX_ANY, FLOAT_LAX_ANY} from './LeTypes.js';
2
3
 
3
4
 
5
+ /**
6
+ * @param {LeUtils~TransactionalValue} transactionalValue
7
+ */
8
+ const checkTransactionalValue = (transactionalValue) =>
9
+ {
10
+ if(!LeUtils.isTransactionalValueValid(transactionalValue))
11
+ {
12
+ console.error('The given value is not a valid TransactionalValue:');
13
+ console.error(transactionalValue);
14
+ throw new Error('The given value is not a valid TransactionalValue');
15
+ }
16
+ };
17
+
18
+ /**
19
+ * @param {LeUtils~TransactionalValue} transactionalValue
20
+ * @param {string} changeId
21
+ * @returns {{index:number, value:*}|null}
22
+ */
23
+ const findTransactionalValueChange = (transactionalValue, changeId) =>
24
+ {
25
+ for(let i = 0; i < transactionalValue.changes.length; i++)
26
+ {
27
+ const change = transactionalValue.changes[i];
28
+ if(change.id === changeId)
29
+ {
30
+ return {index:i, value:change.value};
31
+ }
32
+ }
33
+ return null;
34
+ };
35
+
36
+
4
37
  export const LeUtils = {
38
+ /**
39
+ * A deep equals implementation (npm package "fast-deep-equal").
40
+ *
41
+ * @param {*} value The value to compare.
42
+ * @param {*} other The other value to compare.
43
+ * @returns {boolean} Returns true if the values are equivalent.
44
+ */
45
+ equals:FastDeepEqual,
46
+
5
47
  /**
6
48
  * Parses the given version string, and returns an object with the major, minor, and patch numbers, as well as some comparison functions.
7
49
  *
@@ -738,18 +780,7 @@ export const LeUtils = {
738
780
  * @returns {number}
739
781
  */
740
782
  compare:
741
- (a, b) =>
742
- {
743
- if(a < b)
744
- {
745
- return -1;
746
- }
747
- if(a > b)
748
- {
749
- return 1;
750
- }
751
- return 0;
752
- },
783
+ (a, b) => (a < b) ? -1 : ((a > b) ? 1 : 0),
753
784
 
754
785
  /**
755
786
  * Compares two numbers. Primarily used for sorting.
@@ -1377,6 +1408,40 @@ export const LeUtils = {
1377
1408
  return messageParts[messageParts.length - 1].trim();
1378
1409
  },
1379
1410
 
1411
+ /**
1412
+ * Generates all permutations of the given names.
1413
+ *
1414
+ * For example, if you pass "foo" and "bar", it will return:
1415
+ * - foobar
1416
+ * - fooBar
1417
+ * - FooBar
1418
+ * - foo-bar
1419
+ * - foo_bar
1420
+ *
1421
+ * @param {string} names
1422
+ * @returns {string[]}
1423
+ */
1424
+ generateNamePermutations:
1425
+ (...names) =>
1426
+ {
1427
+ names = LeUtils.flattenArray(names)
1428
+ .map(name => STRING(name).trim().toLowerCase())
1429
+ .filter(name => (name.length > 0));
1430
+ let results = [];
1431
+ if(names.length > 0)
1432
+ {
1433
+ results.push(names.join('')); //foobar
1434
+ results.push(names.map(LeUtils.capitalize).join('')); //FooBar
1435
+ }
1436
+ if(names.length > 1)
1437
+ {
1438
+ results.push([names[0]].concat(names.slice(1).map(LeUtils.capitalize)).join('')); //fooBar
1439
+ results.push(names.join('-')); //foo-bar
1440
+ results.push(names.join('_')); //foo_bar
1441
+ }
1442
+ return results;
1443
+ },
1444
+
1380
1445
  /**
1381
1446
  * Increases the given numeric string by 1, this allows you to increase a numeric string without a limit.
1382
1447
  *
@@ -1608,27 +1673,27 @@ export const LeUtils = {
1608
1673
  },
1609
1674
 
1610
1675
  /**
1611
- * Returns the Lab of the given RGB.
1676
+ * Returns the RGB(A) of the given hex color.
1612
1677
  *
1613
- * @param {number[]} rgb
1678
+ * @param {string} hexstring
1614
1679
  * @returns {number[]}
1615
1680
  */
1616
- rgbToLab:
1617
- (rgb) =>
1681
+ hexToRgb:
1682
+ (hexstring) =>
1618
1683
  {
1619
- let r = rgb[0] / 255;
1620
- let g = rgb[1] / 255;
1621
- let b = rgb[2] / 255;
1622
- r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : r / 12.92;
1623
- g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : g / 12.92;
1624
- b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : b / 12.92;
1625
- let x = (r * 0.4124 + g * 0.3576 + b * 0.1805) / 0.95047;
1626
- let y = (r * 0.2126 + g * 0.7152 + b * 0.0722);
1627
- let z = (r * 0.0193 + g * 0.1192 + b * 0.9505) / 1.08883;
1628
- x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + 16 / 116;
1629
- y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + 16 / 116;
1630
- z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + 16 / 116;
1631
- return [(116 * y) - 16, 500 * (x - y), 200 * (y - z)];
1684
+ hexstring = hexstring.replace(/[^0-9A-F]/gi, '');
1685
+ const hasAlpha = ((hexstring.length === 4) || (hexstring.length === 8));
1686
+ while(hexstring.length < 6)
1687
+ {
1688
+ hexstring = hexstring.replace(/(.)/g, '$1$1');
1689
+ }
1690
+ const result = hexstring.match(/\w{2}/g).map((a) => parseInt(a, 16));
1691
+ return [
1692
+ result[0],
1693
+ result[1],
1694
+ result[2],
1695
+ ...(hasAlpha ? [result[3]] : []),
1696
+ ];
1632
1697
  },
1633
1698
 
1634
1699
  /**
@@ -1643,11 +1708,9 @@ export const LeUtils = {
1643
1708
  const r = rgb[0] / 255;
1644
1709
  const g = rgb[1] / 255;
1645
1710
  const b = rgb[2] / 255;
1646
-
1647
1711
  const max = Math.max(r, g, b);
1648
1712
  const min = Math.min(r, g, b);
1649
1713
  let h, s, l = (max + min) / 2;
1650
-
1651
1714
  if(max === min)
1652
1715
  {
1653
1716
  h = s = 0;
@@ -1670,16 +1733,90 @@ export const LeUtils = {
1670
1733
  }
1671
1734
  h /= 6;
1672
1735
  }
1673
-
1674
- if(rgb.length >= 4)
1736
+ return [h, s, l, ...((rgb.length >= 4) ? [rgb[3] / 255] : [])];
1737
+ },
1738
+
1739
+ /**
1740
+ * Returns the RGB(A) of the given HSL(A).
1741
+ *
1742
+ * @param {number[]} hsl
1743
+ * @returns {number[]}
1744
+ */
1745
+ hslToRgb:
1746
+ (() =>
1747
+ {
1748
+ const hue2rgb = (p, q, t) =>
1675
1749
  {
1676
- return [h, s, l, rgb[3] / 255];
1677
- }
1678
- return [h, s, l];
1750
+ if(t < 0)
1751
+ {
1752
+ t += 1;
1753
+ }
1754
+ if(t > 1)
1755
+ {
1756
+ t -= 1;
1757
+ }
1758
+ if(t < 1 / 6)
1759
+ {
1760
+ return p + (q - p) * 6 * t;
1761
+ }
1762
+ if(t < 1 / 2)
1763
+ {
1764
+ return q;
1765
+ }
1766
+ if(t < 2 / 3)
1767
+ {
1768
+ return p + (q - p) * (2 / 3 - t) * 6;
1769
+ }
1770
+ return p;
1771
+ };
1772
+ return (hsl) =>
1773
+ {
1774
+ const h = hsl[0];
1775
+ const s = hsl[1];
1776
+ const l = hsl[2];
1777
+ let r, g, b;
1778
+ if(s === 0)
1779
+ {
1780
+ r = g = b = l;
1781
+ }
1782
+ else
1783
+ {
1784
+ const q = (l < 0.5) ? (l * (1 + s)) : (l + s - (l * s));
1785
+ const p = (2 * l) - q;
1786
+ r = hue2rgb(p, q, h + (1 / 3));
1787
+ g = hue2rgb(p, q, h);
1788
+ b = hue2rgb(p, q, h - (1 / 3));
1789
+ }
1790
+ return [r * 255, g * 255, b * 255, ...((hsl.length >= 4) ? [hsl[3] * 255] : [])].map((c) => Math.max(0, Math.min(255, Math.round(c))));
1791
+ };
1792
+ })(),
1793
+
1794
+ /**
1795
+ * Returns the LAB(A) of the given RGB(A).
1796
+ *
1797
+ * @param {number[]} rgb
1798
+ * @returns {number[]}
1799
+ */
1800
+ rgbToLab:
1801
+ (rgb) =>
1802
+ {
1803
+ let r = rgb[0] / 255;
1804
+ let g = rgb[1] / 255;
1805
+ let b = rgb[2] / 255;
1806
+ r = (r > 0.04045) ? Math.pow((r + 0.055) / 1.055, 2.4) : (r / 12.92);
1807
+ g = (g > 0.04045) ? Math.pow((g + 0.055) / 1.055, 2.4) : (g / 12.92);
1808
+ b = (b > 0.04045) ? Math.pow((b + 0.055) / 1.055, 2.4) : (b / 12.92);
1809
+ let x = ((r * 0.4124) + (g * 0.3576) + (b * 0.1805)) / 0.95047;
1810
+ let y = ((r * 0.2126) + (g * 0.7152) + (b * 0.0722));
1811
+ let z = ((r * 0.0193) + (g * 0.1192) + (b * 0.9505)) / 1.08883;
1812
+ x = (x > 0.008856) ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);
1813
+ y = (y > 0.008856) ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);
1814
+ z = (z > 0.008856) ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);
1815
+ return [(116 * y) - 16, 500 * (x - y), 200 * (y - z), ...((rgb.length >= 4) ? [rgb[3] / 255] : [])];
1679
1816
  },
1680
1817
 
1681
1818
  /**
1682
- * Returns the difference (calculated with DeltaE) of the Lab values of the given RGB values.
1819
+ * Returns the difference (calculated with DeltaE) of the LAB values of the given RGB values.
1683
1820
  *
1684
1821
  * Returns a number:
1685
1822
  *
@@ -1704,7 +1841,7 @@ export const LeUtils = {
1704
1841
  },
1705
1842
 
1706
1843
  /**
1707
- * Returns the difference (calculated with DeltaE) of the given Lab values.
1844
+ * Returns the difference (calculated with DeltaE) of the given LAB values. Ignores the Alpha channel.
1708
1845
  *
1709
1846
  * Returns a number:
1710
1847
  *
@@ -1737,7 +1874,7 @@ export const LeUtils = {
1737
1874
  const deltaCkcsc = deltaC / (sc);
1738
1875
  const deltaHkhsh = deltaH / (sh);
1739
1876
  const i = deltaLKlsl * deltaLKlsl + deltaCkcsc * deltaCkcsc + deltaHkhsh * deltaHkhsh;
1740
- return i < 0 ? 0 : Math.sqrt(i);
1877
+ return (i < 0) ? 0 : Math.sqrt(i);
1741
1878
  },
1742
1879
 
1743
1880
  /**
@@ -1930,7 +2067,7 @@ export const LeUtils = {
1930
2067
  base64ToUtf8:
1931
2068
  (base64string) =>
1932
2069
  {
1933
- return decodeURIComponent(LeUtils.atob(base64string).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''));
2070
+ return decodeURIComponent(LeUtils.atob(base64string.trim()).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)).join(''));
1934
2071
  },
1935
2072
 
1936
2073
  /**
@@ -1942,7 +2079,7 @@ export const LeUtils = {
1942
2079
  base64ToHex:
1943
2080
  (base64string) =>
1944
2081
  {
1945
- return LeUtils.atob(base64string).split('').map((c) => ('0' + c.charCodeAt(0).toString(16)).slice(-2)).join('');
2082
+ return LeUtils.atob(base64string.trim()).split('').map((c) => ('0' + c.charCodeAt(0).toString(16)).slice(-2)).join('');
1946
2083
  },
1947
2084
 
1948
2085
  /**
@@ -1954,7 +2091,7 @@ export const LeUtils = {
1954
2091
  hexToBase64:
1955
2092
  (hexstring) =>
1956
2093
  {
1957
- return LeUtils.btoa(hexstring.match(/\w{2}/g).map((a) => String.fromCharCode(parseInt(a, 16))).join(''));
2094
+ return LeUtils.btoa(hexstring.replace(/[^0-9A-F]/gi, '').match(/\w{2}/g).map((a) => String.fromCharCode(parseInt(a, 16))).join(''));
1958
2095
  },
1959
2096
 
1960
2097
  /**
@@ -1966,7 +2103,7 @@ export const LeUtils = {
1966
2103
  base64ToBytes:
1967
2104
  (base64string) =>
1968
2105
  {
1969
- const binary = LeUtils.atob(base64string);
2106
+ const binary = LeUtils.atob(base64string.trim());
1970
2107
  const len = binary.length;
1971
2108
  let data = new Uint8Array(len);
1972
2109
  for(let i = 0; i < len; i++)
@@ -1995,6 +2132,23 @@ export const LeUtils = {
1995
2132
  return LeUtils.btoa(binary);
1996
2133
  },
1997
2134
 
2135
+ /**
2136
+ * Downloads the given base64 string as a file.
2137
+ *
2138
+ * @param {string} base64string
2139
+ * @param {string} [fileName]
2140
+ * @param {string} [mimeType]
2141
+ */
2142
+ downloadFile:
2143
+ (base64string, fileName, mimeType) =>
2144
+ {
2145
+ const link = document.createElement('a');
2146
+ link.setAttribute('download', (typeof fileName === 'string') ? fileName : 'file');
2147
+ link.href = 'data:' + mimeType + ';base64,' + base64string;
2148
+ link.setAttribute('target', '_blank');
2149
+ link.click();
2150
+ },
2151
+
1998
2152
  /**
1999
2153
  * Loads the value from the browser, returns undefined if the value doesn't exist.
2000
2154
  *
@@ -2061,4 +2215,383 @@ export const LeUtils = {
2061
2215
  }
2062
2216
  window.localStorage.removeItem('LeUtils_' + id);
2063
2217
  },
2218
+
2219
+ /**
2220
+ * Creates and returns a new TreeSet.
2221
+ * A TreeSet is a set of elements, sorted by a comparator.
2222
+ * Binary search is used to find elements, which makes it very fast to find elements.
2223
+ *
2224
+ * The comparator is also used to determine if two values are equal to each other.
2225
+ * This way, you can have values that aren't the same be treated as if they are. This can be used to deal with issues such as floating point errors for example.
2226
+ *
2227
+ * @param {*[]} elements
2228
+ * @param {Function} comparator
2229
+ * @returns {{getElements: (function(): *[]), getComparator: (function(): Function), size: (function(): number), isEmpty: (function(): boolean), contains: (function(*): boolean), first: (function(): *|undefined), last: (function(): *|undefined), pollFirst: (function(): *|undefined), pollLast: (function(): *|undefined), add: function(*), addAll: function(*[]|object), getEqualValue: (function(*): (*)), getEqualValueOrAdd: (function(*): (*))}}
2230
+ */
2231
+ createTreeSet:
2232
+ (elements, comparator) =>
2233
+ {
2234
+ comparator = comparator || LeUtils.compare;
2235
+ elements = elements || [];
2236
+ elements.sort(comparator);
2237
+
2238
+ /**
2239
+ * Performs a binary search on the elements, and returns the result.
2240
+ *
2241
+ * @param {*} value
2242
+ * @returns {{found: boolean, index: number, value: *|undefined}}
2243
+ */
2244
+ const binarySearch = (value) =>
2245
+ {
2246
+ let low = 0;
2247
+ let high = elements.length - 1;
2248
+ while(low <= high)
2249
+ {
2250
+ const mid = Math.floor((low + high) / 2);
2251
+ const midValue = elements[mid];
2252
+ const cmp = comparator(midValue, value);
2253
+ if(cmp < 0)
2254
+ {
2255
+ low = mid + 1;
2256
+ }
2257
+ else if(cmp > 0)
2258
+ {
2259
+ high = mid - 1;
2260
+ }
2261
+ else
2262
+ {
2263
+ return {found:true, index:mid, value:midValue};
2264
+ }
2265
+ }
2266
+ return {found:false, index:low, value:undefined};
2267
+ };
2268
+
2269
+ const treeSet = {
2270
+ /**
2271
+ * Returns the elements of the set.
2272
+ *
2273
+ * @returns {*[]}
2274
+ */
2275
+ getElements:
2276
+ () => elements,
2277
+
2278
+ /**
2279
+ * Returns the comparator of the set.
2280
+ *
2281
+ * @returns {Function}
2282
+ */
2283
+ getComparator:
2284
+ () => comparator,
2285
+
2286
+ /**
2287
+ * Returns the size of the set.
2288
+ *
2289
+ * @returns {number}
2290
+ */
2291
+ size:
2292
+ () => elements.length,
2293
+
2294
+ /**
2295
+ * Returns true if the set is empty, false otherwise.
2296
+ *
2297
+ * @returns {boolean}
2298
+ */
2299
+ isEmpty:
2300
+ () => (elements.length <= 0),
2301
+
2302
+ /**
2303
+ * Returns true if the set contains a value that is equal to the given value, returns false otherwise.
2304
+ *
2305
+ * @param {*} value
2306
+ * @returns {boolean}
2307
+ */
2308
+ contains:
2309
+ (value) => binarySearch(value).found,
2310
+
2311
+ /**
2312
+ * Returns the first element of the set, or undefined if it is empty.
2313
+ *
2314
+ * @returns {*|undefined}
2315
+ */
2316
+ first:
2317
+ () => (elements.length > 0) ? elements[0] : undefined,
2318
+
2319
+ /**
2320
+ * Returns the last element of the set, or undefined if it is empty.
2321
+ *
2322
+ * @returns {*|undefined}
2323
+ */
2324
+ last:
2325
+ () => (elements.length > 0) ? elements[elements.length - 1] : undefined,
2326
+
2327
+ /**
2328
+ * Removes and returns the first element of the set, or undefined if it is empty.
2329
+ *
2330
+ * @returns {*|undefined}
2331
+ */
2332
+ pollFirst:
2333
+ () => (elements.length > 0) ? elements.splice(0, 1)[0] : undefined,
2334
+
2335
+ /**
2336
+ * Removes and returns the last element of the set, or undefined if it is empty.
2337
+ *
2338
+ * @returns {*|undefined}
2339
+ */
2340
+ pollLast:
2341
+ () => (elements.length > 0) ? elements.splice(elements.length - 1, 1)[0] : undefined,
2342
+
2343
+ /**
2344
+ * Adds the given value to the set. Will only do so if no equal value already exists.
2345
+ *
2346
+ * @param {*} value
2347
+ */
2348
+ add:
2349
+ (value) =>
2350
+ {
2351
+ const result = binarySearch(value);
2352
+ if(result.found)
2353
+ {
2354
+ return;
2355
+ }
2356
+ elements.splice(result.index, 0, value);
2357
+ },
2358
+
2359
+ /**
2360
+ * Adds all the given values to the set. Will only do so if no equal value already exists.
2361
+ *
2362
+ * @param {*[]|object} values
2363
+ */
2364
+ addAll:
2365
+ (values) =>
2366
+ {
2367
+ LeUtils.each(values, treeSet.add);
2368
+ },
2369
+
2370
+ /**
2371
+ * Returns an equal value that's already in the tree set, or undefined if no equal values in it exist.
2372
+ *
2373
+ * @param {*} value
2374
+ * @returns {*|undefined}
2375
+ */
2376
+ getEqualValue:
2377
+ (value) =>
2378
+ {
2379
+ const result = binarySearch(value);
2380
+ if(result.found)
2381
+ {
2382
+ return result.value;
2383
+ }
2384
+ return undefined;
2385
+ },
2386
+
2387
+ /**
2388
+ * Returns an equal value that's already in the tree set. If no equal values in it exist, the given value will be added and returned.
2389
+ *
2390
+ * @param {*} value
2391
+ * @returns {*}
2392
+ */
2393
+ getEqualValueOrAdd:
2394
+ (value) =>
2395
+ {
2396
+ const result = binarySearch(value);
2397
+ if(result.found)
2398
+ {
2399
+ return result.value;
2400
+ }
2401
+ elements.splice(result.index, 0, value);
2402
+ return value;
2403
+ },
2404
+ };
2405
+ return treeSet;
2406
+ },
2407
+
2408
+ /**
2409
+ * @typedef {Object} LeUtils~TransactionalValue
2410
+ * @property {*} value
2411
+ * @property {{id:string, value:*}[]} changes
2412
+ */
2413
+ /**
2414
+ * Creates and returns a new TransactionalValue object.
2415
+ * With a TransactionalValue, you can keep track of changes to a value, and commit or cancel them.
2416
+ *
2417
+ * Multiple uncommitted changes can be made at the same time, the last change will be the one that overwrites older changes.
2418
+ * If that change is cancelled, the previous change will be the one that overwrites older changes.
2419
+ * This allows you to make multiple unconfirmed changes, and confirm or cancel each of them individually at any time.
2420
+ *
2421
+ * @param {*} [value]
2422
+ * @returns {LeUtils~TransactionalValue}
2423
+ */
2424
+ createTransactionalValue:
2425
+ (value) =>
2426
+ {
2427
+ if(typeof value === 'undefined')
2428
+ {
2429
+ value = null;
2430
+ }
2431
+ return {value:value, changes:[]};
2432
+ },
2433
+
2434
+ /**
2435
+ * Returns true if the given value is a valid TransactionalValue, returns false if it isn't.
2436
+ *
2437
+ * @param {LeUtils~TransactionalValue} transactionalValue
2438
+ * @returns {boolean}
2439
+ */
2440
+ isTransactionalValueValid:
2441
+ (transactionalValue) =>
2442
+ {
2443
+ return ((typeof transactionalValue === 'object') && ('value' in transactionalValue) && ('changes' in transactionalValue) && Array.isArray(transactionalValue.changes));
2444
+ },
2445
+
2446
+ /**
2447
+ * Returns true if the given value is a TransactionalValue, false otherwise.
2448
+ *
2449
+ * @param {LeUtils~TransactionalValue} transactionalValue
2450
+ * @returns {string}
2451
+ */
2452
+ transactionalValueToString:
2453
+ (transactionalValue) =>
2454
+ {
2455
+ if(!LeUtils.isTransactionalValueValid(transactionalValue))
2456
+ {
2457
+ return transactionalValue + '';
2458
+ }
2459
+ if(transactionalValue.changes.length <= 0)
2460
+ {
2461
+ return '' + transactionalValue.value;
2462
+ }
2463
+ let valuesString = '' + transactionalValue.value;
2464
+ for(let i = 0; i < transactionalValue.changes.length; i++)
2465
+ {
2466
+ valuesString += ' -> ' + transactionalValue.changes[i].value;
2467
+ }
2468
+ return transactionalValue.changes[transactionalValue.changes.length - 1].value + ' (' + valuesString + ')';
2469
+ },
2470
+
2471
+ /**
2472
+ * Sets the committed value of the given TransactionalValue to the given value. Clears out the previously uncommitted changes.
2473
+ *
2474
+ * @param {LeUtils~TransactionalValue} transactionalValue
2475
+ * @param {*} value
2476
+ */
2477
+ transactionSetAndCommit:
2478
+ (transactionalValue, value) =>
2479
+ {
2480
+ checkTransactionalValue(transactionalValue);
2481
+ if(typeof value === 'undefined')
2482
+ {
2483
+ value = null;
2484
+ }
2485
+ transactionalValue.value = value;
2486
+ transactionalValue.changes = [];
2487
+ },
2488
+
2489
+ /**
2490
+ * Sets the value of the given TransactionalValue to the given value, without yet committing it, meaning it can be committed or cancelled later.
2491
+ * It returns the ID of the change, which can be used to commit or cancel the change later.
2492
+ *
2493
+ * @param {LeUtils~TransactionalValue} transactionalValue
2494
+ * @param {*} value
2495
+ * @returns {string}
2496
+ */
2497
+ transactionSetWithoutCommitting:
2498
+ (transactionalValue, value) =>
2499
+ {
2500
+ checkTransactionalValue(transactionalValue);
2501
+ if(typeof value === 'undefined')
2502
+ {
2503
+ value = null;
2504
+ }
2505
+ const id = LeUtils.uniqueId();
2506
+ transactionalValue.changes.push({id:id, value:value});
2507
+ return id;
2508
+ },
2509
+
2510
+ /**
2511
+ * Commits the change with the given ID, making it the new committed value.
2512
+ * Returns true if the change was found and committed, returns false if it was already overwritten by a newer committed change.
2513
+ *
2514
+ * @param {LeUtils~TransactionalValue} transactionalValue
2515
+ * @param {string} changeId
2516
+ * @returns {boolean}
2517
+ */
2518
+ transactionCommitChange:
2519
+ (transactionalValue, changeId) =>
2520
+ {
2521
+ checkTransactionalValue(transactionalValue);
2522
+ const change = findTransactionalValueChange(transactionalValue, changeId);
2523
+ if(change === null)
2524
+ {
2525
+ return false;
2526
+ }
2527
+ transactionalValue.value = change.value;
2528
+ transactionalValue.changes.splice(0, change.index + 1);
2529
+ return true;
2530
+ },
2531
+
2532
+ /**
2533
+ * Cancels the change with the given ID, removing it from the uncommitted changes.
2534
+ * Returns true if the change was found and removed, returns false if it was already overwritten by a newer committed change.
2535
+ *
2536
+ * @param {LeUtils~TransactionalValue} transactionalValue
2537
+ * @param {string} changeId
2538
+ * @returns {boolean}
2539
+ */
2540
+ transactionCancelChange:
2541
+ (transactionalValue, changeId) =>
2542
+ {
2543
+ checkTransactionalValue(transactionalValue);
2544
+ const change = findTransactionalValueChange(transactionalValue, changeId);
2545
+ if(change === null)
2546
+ {
2547
+ return false;
2548
+ }
2549
+ transactionalValue.changes.splice(change.index, 1);
2550
+ return true;
2551
+ },
2552
+
2553
+ /**
2554
+ * Returns true if the change was found, meaning it can still make a difference to the final committed value of this TransactionalValue.
2555
+ * Returns false if it was already overwritten by a newer committed change, meaning that this change can no longer make a difference to the final committed value of this TransactionalValue.
2556
+ *
2557
+ * @param {LeUtils~TransactionalValue} transactionalValue
2558
+ * @param {string} changeId
2559
+ * @returns {boolean}
2560
+ */
2561
+ transactionIsChangeRelevant:
2562
+ (transactionalValue, changeId) =>
2563
+ {
2564
+ checkTransactionalValue(transactionalValue);
2565
+ return (findTransactionalValueChange(transactionalValue, changeId) !== null);
2566
+ },
2567
+
2568
+ /**
2569
+ * Returns the committed value of the given TransactionalValue.
2570
+ *
2571
+ * @param {LeUtils~TransactionalValue} transactionalValue
2572
+ * @returns {*}
2573
+ */
2574
+ transactionGetCommittedValue:
2575
+ (transactionalValue) =>
2576
+ {
2577
+ checkTransactionalValue(transactionalValue);
2578
+ return transactionalValue.value;
2579
+ },
2580
+
2581
+ /**
2582
+ * Returns the value (including any uncommitted changes made to it) of the given TransactionalValue.
2583
+ *
2584
+ * @param {LeUtils~TransactionalValue} transactionalValue
2585
+ * @returns {*}
2586
+ */
2587
+ transactionGetValue:
2588
+ (transactionalValue) =>
2589
+ {
2590
+ checkTransactionalValue(transactionalValue);
2591
+ if(transactionalValue.changes.length <= 0)
2592
+ {
2593
+ return transactionalValue.value;
2594
+ }
2595
+ return transactionalValue.changes[transactionalValue.changes.length - 1].value;
2596
+ },
2064
2597
  };
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import {LeUtils} from './LeUtils.js';
2
- import {EQUAL, ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY} from './LeTypes.js';
2
+ import {ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY} from './LeTypes.js';
3
3
 
4
- export {LeUtils, EQUAL, ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY};
4
+ export {LeUtils, ISSET, IS_ARRAY, ARRAY, IS_OBJECT, OBJECT, STRING, STRING_ANY, INT, INT_ANY, FLOAT, FLOAT_ANY, INT_LAX, INT_LAX_ANY, FLOAT_LAX, FLOAT_LAX_ANY};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowentry/utils",
3
- "version": "0.2.1",
3
+ "version": "1.0.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Provides utilities for general JavaScript development.",