@oscarpalmer/atoms 0.161.0 → 0.162.0

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.
@@ -11,8 +11,9 @@ import { indexOf } from "../internal/array/index-of.js";
11
11
  import { shuffle } from "../internal/array/shuffle.js";
12
12
  import { insert } from "./insert.js";
13
13
  import { intersection } from "./intersection.js";
14
- import { partition } from "./partition.js";
15
14
  import { endsWithArray, getArrayPosition, includesArray, indexOfArray, startsWithArray } from "./position.js";
15
+ import { move } from "./move.js";
16
+ import { partition } from "./partition.js";
16
17
  import { push } from "./push.js";
17
18
  import { select } from "./select.js";
18
19
  import { drop, slice, take } from "./slice.js";
@@ -23,4 +24,4 @@ import { toSet } from "./to-set.js";
23
24
  import { toggle } from "./toggle.js";
24
25
  import { union } from "./union.js";
25
26
  import { update } from "./update.js";
26
- export { chunk, compact, difference, drop, endsWithArray, exists, filter, find, flatten, getArray, getArrayPosition, includesArray, indexOf, indexOfArray, insert, intersection, partition, push, range, select, shuffle, slice, sort, splice, startsWithArray, swap, take, times, toSet, toggle, union, update };
27
+ export { chunk, compact, difference, drop, endsWithArray, exists, filter, find, flatten, getArray, getArrayPosition, includesArray, indexOf, indexOfArray, insert, intersection, move, partition, push, range, select, shuffle, slice, sort, splice, startsWithArray, swap, take, times, toSet, toggle, union, update };
@@ -0,0 +1,64 @@
1
+ import { arraysOverlap } from "../internal/array/overlap.js";
2
+ import { indexOfArray } from "./position.js";
3
+ //#region src/array/move.ts
4
+ function move(array, from, to, key) {
5
+ if (!Array.isArray(array)) return [];
6
+ const firstArray = Array.isArray(from) ? from : [from];
7
+ const secondArray = Array.isArray(to) ? to : [to];
8
+ if (firstArray.length === 0 || secondArray.length === 0) return array;
9
+ const firstPosition = indexOfArray(array, firstArray, key);
10
+ const secondPosition = indexOfArray(array, secondArray, key);
11
+ if (firstPosition === -1 || secondPosition === -1 || firstPosition === secondPosition) return array;
12
+ const { overlap } = arraysOverlap({
13
+ array: firstArray,
14
+ index: firstPosition
15
+ }, {
16
+ array: secondArray,
17
+ index: secondPosition
18
+ });
19
+ if (overlap) return array;
20
+ array.splice(firstPosition, firstArray.length);
21
+ const next = secondPosition < firstPosition ? secondPosition : secondPosition + secondArray.length - firstArray.length;
22
+ if (next >= array.length) array.push(...firstArray);
23
+ else array.splice(next, 0, ...firstArray);
24
+ return array;
25
+ }
26
+ move.indices = moveIndices;
27
+ move.toIndex = moveToIndex;
28
+ /**
29
+ * Move an item from one index to another within an array
30
+ *
31
+ * If the from index is out of bounds, the array will be returned unchanged
32
+ * @param array Array to move within
33
+ * @param from Index to move from
34
+ * @param to Index to move to
35
+ * @returns Original array with item moved _(or unchanged if unable to move)_
36
+ */
37
+ function moveIndices(array, from, to) {
38
+ if (!Array.isArray(array)) return [];
39
+ const { length } = array;
40
+ if (length === 0 || typeof from !== "number" || typeof to !== "number") return array;
41
+ const fromIndex = from < 0 ? length + from : from;
42
+ const toIndex = to < 0 ? length + to : to;
43
+ if (fromIndex === toIndex || fromIndex >= length || toIndex >= length) return array;
44
+ const spliced = array.splice(fromIndex, 1);
45
+ if (toIndex >= array.length) array.push(...spliced);
46
+ else array.splice(toIndex, 0, ...spliced);
47
+ return array;
48
+ }
49
+ function moveToIndex(array, value, index, key) {
50
+ if (!Array.isArray(array)) return [];
51
+ const { length } = array;
52
+ if (length === 0 || typeof index !== "number") return array;
53
+ const next = index < 0 ? length + index : index;
54
+ if (next >= length) return array;
55
+ const values = Array.isArray(value) ? value : [value];
56
+ const position = indexOfArray(array, values, key);
57
+ if (position === -1 || position === next) return array;
58
+ array.splice(position, values.length);
59
+ if (next >= array.length) array.push(...values);
60
+ else array.splice(next, 0, ...values);
61
+ return array;
62
+ }
63
+ //#endregion
64
+ export { move };
@@ -1,5 +1,6 @@
1
1
  import { getArrayCallback } from "../internal/array/callbacks.js";
2
2
  import { indexOf } from "../internal/array/index-of.js";
3
+ import { arraysOverlap } from "../internal/array/overlap.js";
3
4
  import { indexOfArray } from "./position.js";
4
5
  //#region src/array/swap.ts
5
6
  function swap(array, first, second, third) {
@@ -15,14 +16,16 @@ function swapArrays(array, from, to, key) {
15
16
  const fromIndex = indexOfArray(array, from, key);
16
17
  const toIndex = indexOfArray(array, to, key);
17
18
  if (fromIndex === -1 || toIndex === -1) return array;
18
- const first = fromIndex < toIndex ? from : to;
19
- const second = fromIndex < toIndex ? to : from;
20
- const firstIndex = first === from ? fromIndex : toIndex;
21
- const secondIndex = first === from ? toIndex : fromIndex;
22
- const firstEnd = firstIndex + first.length - 1;
23
- if (firstIndex <= secondIndex + second.length - 1 && firstEnd >= secondIndex) return array;
24
- array.splice(firstIndex, first.length, ...second);
25
- array.splice(secondIndex, second.length, ...first);
19
+ const { first, second, overlap } = arraysOverlap({
20
+ array: from,
21
+ index: fromIndex
22
+ }, {
23
+ array: to,
24
+ index: toIndex
25
+ });
26
+ if (overlap) return array;
27
+ array.splice(first.index, first.array.length, ...second.array);
28
+ array.splice(second.index + (second.array.length - first.array.length), second.array.length, ...first.array);
26
29
  return array;
27
30
  }
28
31
  /**
@@ -367,9 +367,23 @@ function insert(array, indexOrItems, items) {
367
367
  function intersection(first, second, key) {
368
368
  return compareSets(COMPARE_SETS_INTERSECTION, first, second, key);
369
369
  }
370
- function partition(array, ...parameters) {
371
- const { matched, notMatched } = findValues("all", array, parameters);
372
- return [matched, notMatched];
370
+ function arraysOverlap(first, second) {
371
+ const firstArray = first.index < second.index ? first.array : second.array;
372
+ const secondArray = first.index < second.index ? second.array : first.array;
373
+ const firstIndex = firstArray === first.array ? first.index : second.index;
374
+ const secondIndex = firstArray === first.array ? second.index : first.index;
375
+ const firstEnd = firstIndex + firstArray.length - 1;
376
+ return {
377
+ overlap: firstIndex <= secondIndex + secondArray.length - 1 && firstEnd >= secondIndex,
378
+ first: {
379
+ array: firstArray,
380
+ index: firstIndex
381
+ },
382
+ second: {
383
+ array: secondArray,
384
+ index: secondIndex
385
+ }
386
+ };
373
387
  }
374
388
  function endsWithArray(haystack, needle, key) {
375
389
  return endings.has(getPosition(haystack, needle, key)[1]);
@@ -425,6 +439,69 @@ const invalid = [-1, POSITION_INVALID];
425
439
  const outside = [-1, POSITION_OUTSIDE];
426
440
  const outsides = new Set([POSITION_INVALID, POSITION_OUTSIDE]);
427
441
  const starts = new Set([POSITION_START, POSITION_SAME]);
442
+ function move(array, from, to, key) {
443
+ if (!Array.isArray(array)) return [];
444
+ const firstArray = Array.isArray(from) ? from : [from];
445
+ const secondArray = Array.isArray(to) ? to : [to];
446
+ if (firstArray.length === 0 || secondArray.length === 0) return array;
447
+ const firstPosition = indexOfArray(array, firstArray, key);
448
+ const secondPosition = indexOfArray(array, secondArray, key);
449
+ if (firstPosition === -1 || secondPosition === -1 || firstPosition === secondPosition) return array;
450
+ const { overlap } = arraysOverlap({
451
+ array: firstArray,
452
+ index: firstPosition
453
+ }, {
454
+ array: secondArray,
455
+ index: secondPosition
456
+ });
457
+ if (overlap) return array;
458
+ array.splice(firstPosition, firstArray.length);
459
+ const next = secondPosition < firstPosition ? secondPosition : secondPosition + secondArray.length - firstArray.length;
460
+ if (next >= array.length) array.push(...firstArray);
461
+ else array.splice(next, 0, ...firstArray);
462
+ return array;
463
+ }
464
+ move.indices = moveIndices;
465
+ move.toIndex = moveToIndex;
466
+ /**
467
+ * Move an item from one index to another within an array
468
+ *
469
+ * If the from index is out of bounds, the array will be returned unchanged
470
+ * @param array Array to move within
471
+ * @param from Index to move from
472
+ * @param to Index to move to
473
+ * @returns Original array with item moved _(or unchanged if unable to move)_
474
+ */
475
+ function moveIndices(array, from, to) {
476
+ if (!Array.isArray(array)) return [];
477
+ const { length } = array;
478
+ if (length === 0 || typeof from !== "number" || typeof to !== "number") return array;
479
+ const fromIndex = from < 0 ? length + from : from;
480
+ const toIndex = to < 0 ? length + to : to;
481
+ if (fromIndex === toIndex || fromIndex >= length || toIndex >= length) return array;
482
+ const spliced = array.splice(fromIndex, 1);
483
+ if (toIndex >= array.length) array.push(...spliced);
484
+ else array.splice(toIndex, 0, ...spliced);
485
+ return array;
486
+ }
487
+ function moveToIndex(array, value, index, key) {
488
+ if (!Array.isArray(array)) return [];
489
+ const { length } = array;
490
+ if (length === 0 || typeof index !== "number") return array;
491
+ const next = index < 0 ? length + index : index;
492
+ if (next >= length) return array;
493
+ const values = Array.isArray(value) ? value : [value];
494
+ const position = indexOfArray(array, values, key);
495
+ if (position === -1 || position === next) return array;
496
+ array.splice(position, values.length);
497
+ if (next >= array.length) array.push(...values);
498
+ else array.splice(next, 0, ...values);
499
+ return array;
500
+ }
501
+ function partition(array, ...parameters) {
502
+ const { matched, notMatched } = findValues("all", array, parameters);
503
+ return [matched, notMatched];
504
+ }
428
505
  /**
429
506
  * Push items into an array _(at the end)_
430
507
  * @param array Original array
@@ -774,14 +851,16 @@ function swapArrays(array, from, to, key) {
774
851
  const fromIndex = indexOfArray(array, from, key);
775
852
  const toIndex = indexOfArray(array, to, key);
776
853
  if (fromIndex === -1 || toIndex === -1) return array;
777
- const first = fromIndex < toIndex ? from : to;
778
- const second = fromIndex < toIndex ? to : from;
779
- const firstIndex = first === from ? fromIndex : toIndex;
780
- const secondIndex = first === from ? toIndex : fromIndex;
781
- const firstEnd = firstIndex + first.length - 1;
782
- if (firstIndex <= secondIndex + second.length - 1 && firstEnd >= secondIndex) return array;
783
- array.splice(firstIndex, first.length, ...second);
784
- array.splice(secondIndex, second.length, ...first);
854
+ const { first, second, overlap } = arraysOverlap({
855
+ array: from,
856
+ index: fromIndex
857
+ }, {
858
+ array: to,
859
+ index: toIndex
860
+ });
861
+ if (overlap) return array;
862
+ array.splice(first.index, first.array.length, ...second.array);
863
+ array.splice(second.index + (second.array.length - first.array.length), second.array.length, ...first.array);
785
864
  return array;
786
865
  }
787
866
  /**
@@ -4144,4 +4223,4 @@ var SizedSet = class extends Set {
4144
4223
  }
4145
4224
  }
4146
4225
  };
4147
- export { CancelablePromise, PromiseTimeoutError, QueueError, RetryError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, toResult, fromQuery, toPromise as fromResult, toPromise, getArray, getArrayPosition, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
4226
+ export { CancelablePromise, PromiseTimeoutError, QueueError, RetryError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, toResult, fromQuery, toPromise as fromResult, toPromise, getArray, getArrayPosition, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, move, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
package/dist/index.js CHANGED
@@ -14,8 +14,9 @@ import { getRandomFloat, getRandomInteger } from "./internal/random.js";
14
14
  import { shuffle } from "./internal/array/shuffle.js";
15
15
  import { insert } from "./array/insert.js";
16
16
  import { intersection } from "./array/intersection.js";
17
- import { partition } from "./array/partition.js";
18
17
  import { endsWithArray, getArrayPosition, includesArray, indexOfArray, startsWithArray } from "./array/position.js";
18
+ import { move } from "./array/move.js";
19
+ import { partition } from "./array/partition.js";
19
20
  import { push } from "./array/push.js";
20
21
  import { select } from "./array/select.js";
21
22
  import { drop, slice, take } from "./array/slice.js";
@@ -79,4 +80,4 @@ import { fromQuery, toQuery } from "./query.js";
79
80
  import { QueueError, queue } from "./queue.js";
80
81
  import { getRandomBoolean, getRandomCharacters, getRandomColor, getRandomHex, getRandomItem, getRandomItems } from "./random.js";
81
82
  import { SizedSet } from "./sized/set.js";
82
- export { CancelablePromise, PromiseTimeoutError, QueueError, RetryError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, fromQuery, toPromise as fromResult, getArray, getArrayPosition, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toPromise, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
83
+ export { CancelablePromise, PromiseTimeoutError, QueueError, RetryError, SizedMap, SizedSet, attempt, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, toResult as fromPromise, fromQuery, toPromise as fromResult, getArray, getArrayPosition, getColor, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getUuid, getValue, groupBy, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, max, median, memoize, merge, min, move, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toPromise, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
@@ -0,0 +1,21 @@
1
+ //#region src/internal/array/overlap.ts
2
+ function arraysOverlap(first, second) {
3
+ const firstArray = first.index < second.index ? first.array : second.array;
4
+ const secondArray = first.index < second.index ? second.array : first.array;
5
+ const firstIndex = firstArray === first.array ? first.index : second.index;
6
+ const secondIndex = firstArray === first.array ? second.index : first.index;
7
+ const firstEnd = firstIndex + firstArray.length - 1;
8
+ return {
9
+ overlap: firstIndex <= secondIndex + secondArray.length - 1 && firstEnd >= secondIndex,
10
+ first: {
11
+ array: firstArray,
12
+ index: firstIndex
13
+ },
14
+ second: {
15
+ array: secondArray,
16
+ index: secondIndex
17
+ }
18
+ };
19
+ }
20
+ //#endregion
21
+ export { arraysOverlap };
package/package.json CHANGED
@@ -5,11 +5,11 @@
5
5
  },
6
6
  "description": "Atomic utilities for making your JavaScript better.",
7
7
  "devDependencies": {
8
- "@types/node": "^25.3",
8
+ "@types/node": "^25.4",
9
9
  "@vitest/coverage-istanbul": "^4",
10
10
  "jsdom": "^28.1",
11
- "oxfmt": "^0.36",
12
- "oxlint": "^1.51",
11
+ "oxfmt": "^0.38",
12
+ "oxlint": "^1.53",
13
13
  "rolldown": "1.0.0-rc.8",
14
14
  "tslib": "^2.8",
15
15
  "typescript": "^5.9",
@@ -184,5 +184,5 @@
184
184
  },
185
185
  "type": "module",
186
186
  "types": "./types/index.d.ts",
187
- "version": "0.161.0"
187
+ "version": "0.162.0"
188
188
  }
@@ -12,6 +12,7 @@ export * from './from';
12
12
  export * from './get';
13
13
  export * from './insert';
14
14
  export * from './intersection';
15
+ export * from './move';
15
16
  export * from './partition';
16
17
  export * from './position';
17
18
  export * from './push';
@@ -0,0 +1,228 @@
1
+ import {arraysOverlap} from '../internal/array/overlap';
2
+ import type {PlainObject} from '../models';
3
+ import {indexOfArray} from './position';
4
+
5
+ /**
6
+ * Move an item _(or array of items)_ to the position of another item _(or array of items)_ within an array
7
+ *
8
+ * When moving to the front of the array, the moved items will be placed __before__ the target item. When moving to the back of the array, the moved items will be placed __after__ the target item.
9
+ *
10
+ * If either of values are not present in the array, or if they overlap, the array will be returned unchanged
11
+ * @param array Array to move within
12
+ * @param from Item or items to move
13
+ * @param to Item or items to move to
14
+ * @param key Key to get an item's value for matching
15
+ * @returns Original array with items moved _(or unchanged if unable to move)_
16
+ */
17
+ export function move<Item extends PlainObject, Key extends keyof Item>(
18
+ array: Item[],
19
+ from: Item | Item[],
20
+ to: Item | Item[],
21
+ key: Key,
22
+ ): Item[];
23
+
24
+ /**
25
+ * Move an item _(or array of items)_ to the position of another item _(or array of items)_ within an array
26
+ *
27
+ * When moving to the front of the array, the moved items will be placed __before__ the target item. When moving to the back of the array, the moved items will be placed __after__ the target item.
28
+ *
29
+ * If either of values are not present in the array, or if they overlap, the array will be returned unchanged
30
+ * @param array Array to move within
31
+ * @param from Item or items to move
32
+ * @param to Item or items to move to
33
+ * @param callback Callback to get an item's value for matching
34
+ * @returns Original array with items moved _(or unchanged if unable to move)_
35
+ */
36
+ export function move<Item>(
37
+ array: Item[],
38
+ from: Item | Item[],
39
+ to: Item | Item[],
40
+ callback: (item: Item, index: number, array: Item[]) => unknown,
41
+ ): Item[];
42
+
43
+ /**
44
+ * Move an item _(or array of items)_ to the position of another item _(or array of items)_ within an array
45
+ *
46
+ * When moving to the front of the array, the moved items will be placed __before__ the target item. When moving to the back of the array, the moved items will be placed __after__ the target item.
47
+ *
48
+ * If either of values are not present in the array, or if they overlap, the array will be returned unchanged
49
+ * @param array Array to move within
50
+ * @param from Item or items to move
51
+ * @param to Item or items to move to
52
+ * @returns Original array with items moved _(or unchanged if unable to move)_
53
+ */
54
+ export function move<Item>(array: Item[], from: Item | Item[], to: Item | Item[]): Item[];
55
+
56
+ export function move(array: unknown[], from: unknown, to: unknown, key?: unknown): unknown[] {
57
+ if (!Array.isArray(array)) {
58
+ return [];
59
+ }
60
+
61
+ const firstArray = Array.isArray(from) ? from : [from];
62
+ const secondArray = Array.isArray(to) ? to : [to];
63
+
64
+ if (firstArray.length === 0 || secondArray.length === 0) {
65
+ return array;
66
+ }
67
+
68
+ const firstPosition = indexOfArray(array, firstArray, key as never);
69
+ const secondPosition = indexOfArray(array, secondArray, key as never);
70
+
71
+ if (firstPosition === -1 || secondPosition === -1 || firstPosition === secondPosition) {
72
+ return array;
73
+ }
74
+
75
+ const {overlap} = arraysOverlap(
76
+ {
77
+ array: firstArray,
78
+ index: firstPosition,
79
+ },
80
+ {
81
+ array: secondArray,
82
+ index: secondPosition,
83
+ },
84
+ );
85
+
86
+ if (overlap) {
87
+ // The arrays overlap, so we can't swap them without losing data
88
+
89
+ return array;
90
+ }
91
+
92
+ array.splice(firstPosition, firstArray.length);
93
+
94
+ const next =
95
+ secondPosition < firstPosition
96
+ ? secondPosition
97
+ : secondPosition + secondArray.length - firstArray.length;
98
+
99
+ if (next >= array.length) {
100
+ array.push(...firstArray);
101
+ } else {
102
+ array.splice(next, 0, ...firstArray);
103
+ }
104
+
105
+ return array;
106
+ }
107
+
108
+ move.indices = moveIndices;
109
+ move.toIndex = moveToIndex;
110
+
111
+ /**
112
+ * Move an item from one index to another within an array
113
+ *
114
+ * If the from index is out of bounds, the array will be returned unchanged
115
+ * @param array Array to move within
116
+ * @param from Index to move from
117
+ * @param to Index to move to
118
+ * @returns Original array with item moved _(or unchanged if unable to move)_
119
+ */
120
+ function moveIndices<Item>(array: Item[], from: number, to: number): Item[] {
121
+ if (!Array.isArray(array)) {
122
+ return [];
123
+ }
124
+
125
+ const {length} = array;
126
+
127
+ if (length === 0 || typeof from !== 'number' || typeof to !== 'number') {
128
+ return array;
129
+ }
130
+
131
+ const fromIndex = from < 0 ? length + from : from;
132
+ const toIndex = to < 0 ? length + to : to;
133
+
134
+ if (fromIndex === toIndex || fromIndex >= length || toIndex >= length) {
135
+ return array;
136
+ }
137
+
138
+ const spliced = array.splice(fromIndex, 1);
139
+
140
+ if (toIndex >= array.length) {
141
+ array.push(...spliced);
142
+ } else {
143
+ array.splice(toIndex, 0, ...spliced);
144
+ }
145
+
146
+ return array;
147
+ }
148
+
149
+ /**
150
+ * Move an item _(or array of items)_ to an index within an array
151
+ *
152
+ * If the value is not present in the array, or if the index is out of bounds, the array will be returned unchanged
153
+ * @param array Array to move within
154
+ * @param value Item or items to move
155
+ * @param index Index to move to
156
+ * @param key Key to get an item's value for matching
157
+ * @returns Original array with items moved _(or unchanged if unable to move)_
158
+ */
159
+ function moveToIndex<Item extends PlainObject, Key extends keyof Item>(
160
+ array: Item[],
161
+ value: Item | Item[],
162
+ index: number,
163
+ key: Key,
164
+ ): Item[];
165
+
166
+ /**
167
+ * Move an item _(or array of items)_ to an index within an array
168
+ *
169
+ * If the value is not present in the array, or if the index is out of bounds, the array will be returned unchanged
170
+ * @param array Array to move within
171
+ * @param value Item or items to move
172
+ * @param index Index to move to
173
+ * @param callback Callback to get an item's value for matching
174
+ * @returns Original array with items moved _(or unchanged if unable to move)_
175
+ */
176
+ function moveToIndex<Item>(
177
+ array: Item[],
178
+ value: Item | Item[],
179
+ index: number,
180
+ callback: (item: Item, index: number, array: Item[]) => unknown,
181
+ ): Item[];
182
+
183
+ /**
184
+ * Move an item _(or array of items)_ to an index within an array
185
+ *
186
+ * If the value is not present in the array, or if the index is out of bounds, the array will be returned unchanged
187
+ * @param array Array to move within
188
+ * @param value Item or items to move
189
+ * @param index Index to move to
190
+ * @returns Original array with items moved _(or unchanged if unable to move)_
191
+ */
192
+ function moveToIndex<Item>(array: Item[], value: Item | Item[], index: number): Item[];
193
+
194
+ function moveToIndex(array: unknown[], value: unknown, index: number, key?: unknown): unknown[] {
195
+ if (!Array.isArray(array)) {
196
+ return [];
197
+ }
198
+
199
+ const {length} = array;
200
+
201
+ if (length === 0 || typeof index !== 'number') {
202
+ return array;
203
+ }
204
+
205
+ const next = index < 0 ? length + index : index;
206
+
207
+ if (next >= length) {
208
+ return array;
209
+ }
210
+
211
+ const values = Array.isArray(value) ? value : [value];
212
+
213
+ const position = indexOfArray(array, values, key as never);
214
+
215
+ if (position === -1 || position === next) {
216
+ return array;
217
+ }
218
+
219
+ array.splice(position, values.length);
220
+
221
+ if (next >= array.length) {
222
+ array.push(...values);
223
+ } else {
224
+ array.splice(next, 0, ...values);
225
+ }
226
+
227
+ return array;
228
+ }
package/src/array/sort.ts CHANGED
@@ -213,7 +213,7 @@ export function sort(array: unknown[], first?: unknown, second?: unknown): unkno
213
213
  const direction =
214
214
  first === true || second === true ? SORT_DIRECTION_DESCENDING : SORT_DIRECTION_ASCENDING;
215
215
 
216
- const modifier = direction === SORT_DIRECTION_ASCENDING ? 1 : -1;
216
+ const modifier = direction === SORT_DIRECTION_ASCENDING ? 1 : -1;
217
217
 
218
218
  const sorters = (Array.isArray(first) ? first : [first])
219
219
  .map(item => getSorter(item, modifier))
package/src/array/swap.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import {getArrayCallback} from '../internal/array/callbacks';
2
2
  import {indexOf} from '../internal/array/index-of';
3
+ import {arraysOverlap} from '../internal/array/overlap';
3
4
  import type {PlainObject} from '../models';
4
5
  import {indexOfArray} from './position';
5
6
 
@@ -130,23 +131,30 @@ function swapArrays(array: unknown[], from: unknown[], to: unknown[], key: unkno
130
131
  return array;
131
132
  }
132
133
 
133
- const first = fromIndex < toIndex ? from : to;
134
- const second = fromIndex < toIndex ? to : from;
135
-
136
- const firstIndex = first === from ? fromIndex : toIndex;
137
- const secondIndex = first === from ? toIndex : fromIndex;
138
-
139
- const firstEnd = firstIndex + first.length - 1;
140
- const secondEnd = secondIndex + second.length - 1;
141
-
142
- if (firstIndex <= secondEnd && firstEnd >= secondIndex) {
134
+ const {first, second, overlap} = arraysOverlap(
135
+ {
136
+ array: from,
137
+ index: fromIndex,
138
+ },
139
+ {
140
+ array: to,
141
+ index: toIndex,
142
+ },
143
+ );
144
+
145
+ if (overlap) {
143
146
  // The arrays overlap, so we can't swap them without losing data
144
147
 
145
148
  return array;
146
149
  }
147
150
 
148
- array.splice(firstIndex, first.length, ...second);
149
- array.splice(secondIndex, second.length, ...first);
151
+ array.splice(first.index, first.array.length, ...second.array);
152
+
153
+ array.splice(
154
+ second.index + (second.array.length - first.array.length),
155
+ second.array.length,
156
+ ...first.array,
157
+ );
150
158
 
151
159
  return array;
152
160
  }
@@ -1,4 +1,4 @@
1
- import { SPACE_HSL, SPACE_RGB } from './constants';
1
+ import {SPACE_HSL, SPACE_RGB} from './constants';
2
2
  import {formatColor} from './misc';
3
3
  import {getAlpha} from './misc/alpha';
4
4
  import {getState, setHexColor, setHSLColor, setRGBColor} from './misc/state';
@@ -0,0 +1,35 @@
1
+ type OverlapItem = {
2
+ array: unknown[];
3
+ index: number;
4
+ };
5
+
6
+ type OverlapResult = {
7
+ first: OverlapItem;
8
+ second: OverlapItem;
9
+ overlap: boolean;
10
+ };
11
+
12
+ export function arraysOverlap(first: OverlapItem, second: OverlapItem): OverlapResult {
13
+ const firstArray = first.index < second.index ? first.array : second.array;
14
+ const secondArray = first.index < second.index ? second.array : first.array;
15
+
16
+ const firstIndex = firstArray === first.array ? first.index : second.index;
17
+ const secondIndex = firstArray === first.array ? second.index : first.index;
18
+
19
+ const firstEnd = firstIndex + firstArray.length - 1;
20
+ const secondEnd = secondIndex + secondArray.length - 1;
21
+
22
+ const overlap = firstIndex <= secondEnd && firstEnd >= secondIndex;
23
+
24
+ return {
25
+ overlap,
26
+ first: {
27
+ array: firstArray,
28
+ index: firstIndex,
29
+ },
30
+ second: {
31
+ array: secondArray,
32
+ index: secondIndex,
33
+ },
34
+ };
35
+ }
@@ -44,12 +44,7 @@ export function setValue<Data extends PlainObject>(
44
44
  ignoreCase?: boolean,
45
45
  ): Data;
46
46
 
47
- export function setValue(
48
- data: object,
49
- path: string,
50
- value: unknown,
51
- ignoreCase?: boolean,
52
- ): object {
47
+ export function setValue(data: object, path: string, value: unknown, ignoreCase?: boolean): object {
53
48
  if (
54
49
  typeof data !== 'object' ||
55
50
  data === null ||
@@ -58,9 +58,7 @@ export function getPromisesOptions(input: unknown): RequiredKeys<PromisesOptions
58
58
  };
59
59
  }
60
60
 
61
- export function getResultsFromPromises<Value>(
62
- promised: PromisesValue<Value>[],
63
- ): Result<Value>[] {
61
+ export function getResultsFromPromises<Value>(promised: PromisesValue<Value>[]): Result<Value>[] {
64
62
  return promised.map(result =>
65
63
  isFulfilled(result) ? ok(result.value) : error(result.reason),
66
64
  ) as Result<Value>[];
@@ -92,9 +90,7 @@ export function isRejected(value: unknown): value is RejectedPromise {
92
90
 
93
91
  function isType(value: unknown, type: string): boolean {
94
92
  return (
95
- typeof value === 'object' &&
96
- value !== null &&
97
- (value as PromisesValue<unknown>).status === type
93
+ typeof value === 'object' && value !== null && (value as PromisesValue<unknown>).status === type
98
94
  );
99
95
  }
100
96
 
@@ -11,6 +11,7 @@ export * from './from';
11
11
  export * from './get';
12
12
  export * from './insert';
13
13
  export * from './intersection';
14
+ export * from './move';
14
15
  export * from './partition';
15
16
  export * from './position';
16
17
  export * from './push';
@@ -0,0 +1,86 @@
1
+ import type { PlainObject } from '../models';
2
+ /**
3
+ * Move an item _(or array of items)_ to the position of another item _(or array of items)_ within an array
4
+ *
5
+ * When moving to the front of the array, the moved items will be placed __before__ the target item. When moving to the back of the array, the moved items will be placed __after__ the target item.
6
+ *
7
+ * If either of values are not present in the array, or if they overlap, the array will be returned unchanged
8
+ * @param array Array to move within
9
+ * @param from Item or items to move
10
+ * @param to Item or items to move to
11
+ * @param key Key to get an item's value for matching
12
+ * @returns Original array with items moved _(or unchanged if unable to move)_
13
+ */
14
+ export declare function move<Item extends PlainObject, Key extends keyof Item>(array: Item[], from: Item | Item[], to: Item | Item[], key: Key): Item[];
15
+ /**
16
+ * Move an item _(or array of items)_ to the position of another item _(or array of items)_ within an array
17
+ *
18
+ * When moving to the front of the array, the moved items will be placed __before__ the target item. When moving to the back of the array, the moved items will be placed __after__ the target item.
19
+ *
20
+ * If either of values are not present in the array, or if they overlap, the array will be returned unchanged
21
+ * @param array Array to move within
22
+ * @param from Item or items to move
23
+ * @param to Item or items to move to
24
+ * @param callback Callback to get an item's value for matching
25
+ * @returns Original array with items moved _(or unchanged if unable to move)_
26
+ */
27
+ export declare function move<Item>(array: Item[], from: Item | Item[], to: Item | Item[], callback: (item: Item, index: number, array: Item[]) => unknown): Item[];
28
+ /**
29
+ * Move an item _(or array of items)_ to the position of another item _(or array of items)_ within an array
30
+ *
31
+ * When moving to the front of the array, the moved items will be placed __before__ the target item. When moving to the back of the array, the moved items will be placed __after__ the target item.
32
+ *
33
+ * If either of values are not present in the array, or if they overlap, the array will be returned unchanged
34
+ * @param array Array to move within
35
+ * @param from Item or items to move
36
+ * @param to Item or items to move to
37
+ * @returns Original array with items moved _(or unchanged if unable to move)_
38
+ */
39
+ export declare function move<Item>(array: Item[], from: Item | Item[], to: Item | Item[]): Item[];
40
+ export declare namespace move {
41
+ var indices: typeof moveIndices;
42
+ var toIndex: typeof moveToIndex;
43
+ }
44
+ /**
45
+ * Move an item from one index to another within an array
46
+ *
47
+ * If the from index is out of bounds, the array will be returned unchanged
48
+ * @param array Array to move within
49
+ * @param from Index to move from
50
+ * @param to Index to move to
51
+ * @returns Original array with item moved _(or unchanged if unable to move)_
52
+ */
53
+ declare function moveIndices<Item>(array: Item[], from: number, to: number): Item[];
54
+ /**
55
+ * Move an item _(or array of items)_ to an index within an array
56
+ *
57
+ * If the value is not present in the array, or if the index is out of bounds, the array will be returned unchanged
58
+ * @param array Array to move within
59
+ * @param value Item or items to move
60
+ * @param index Index to move to
61
+ * @param key Key to get an item's value for matching
62
+ * @returns Original array with items moved _(or unchanged if unable to move)_
63
+ */
64
+ declare function moveToIndex<Item extends PlainObject, Key extends keyof Item>(array: Item[], value: Item | Item[], index: number, key: Key): Item[];
65
+ /**
66
+ * Move an item _(or array of items)_ to an index within an array
67
+ *
68
+ * If the value is not present in the array, or if the index is out of bounds, the array will be returned unchanged
69
+ * @param array Array to move within
70
+ * @param value Item or items to move
71
+ * @param index Index to move to
72
+ * @param callback Callback to get an item's value for matching
73
+ * @returns Original array with items moved _(or unchanged if unable to move)_
74
+ */
75
+ declare function moveToIndex<Item>(array: Item[], value: Item | Item[], index: number, callback: (item: Item, index: number, array: Item[]) => unknown): Item[];
76
+ /**
77
+ * Move an item _(or array of items)_ to an index within an array
78
+ *
79
+ * If the value is not present in the array, or if the index is out of bounds, the array will be returned unchanged
80
+ * @param array Array to move within
81
+ * @param value Item or items to move
82
+ * @param index Index to move to
83
+ * @returns Original array with items moved _(or unchanged if unable to move)_
84
+ */
85
+ declare function moveToIndex<Item>(array: Item[], value: Item | Item[], index: number): Item[];
86
+ export {};
@@ -0,0 +1,11 @@
1
+ type OverlapItem = {
2
+ array: unknown[];
3
+ index: number;
4
+ };
5
+ type OverlapResult = {
6
+ first: OverlapItem;
7
+ second: OverlapItem;
8
+ overlap: boolean;
9
+ };
10
+ export declare function arraysOverlap(first: OverlapItem, second: OverlapItem): OverlapResult;
11
+ export {};