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