@qezor/structkit 1.0.0 → 1.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/README.md +81 -29
- package/index.d.ts +100 -12
- package/index.js +6 -21
- package/index.mjs +38 -5
- package/lib/array.js +139 -0
- package/lib/deep.js +435 -0
- package/lib/insert.js +62 -0
- package/lib/object.js +44 -0
- package/lib/range.js +55 -0
- package/lib/shared.js +64 -0
- package/lib/string.js +195 -0
- package/package.json +4 -11
- package/test.js +125 -6
- package/bridge.d.ts +0 -14
- package/bridge.js +0 -3
- package/bridge.mjs +0 -11
- package/lib/bridge.js +0 -49
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# @qezor/structkit
|
|
2
2
|
|
|
3
3
|
`@qezor/structkit` is a focused data-manipulation toolkit for:
|
|
4
|
+
- strings
|
|
4
5
|
- arrays
|
|
5
6
|
- objects
|
|
6
7
|
- path access
|
|
8
|
+
- iterative deep traversal and filtering
|
|
7
9
|
- iterative deep equality
|
|
8
10
|
- iterative deep merge and clone
|
|
9
11
|
|
|
@@ -21,12 +23,34 @@ npm install @qezor/structkit
|
|
|
21
23
|
- no callback-style APIs
|
|
22
24
|
- no recursion-heavy deep walkers
|
|
23
25
|
- predictable helpers for arrays, objects, and paths
|
|
24
|
-
-
|
|
26
|
+
- range-controlled string and array operations
|
|
27
|
+
- depth-controlled deep search and deep manipulation
|
|
28
|
+
- generator-based traversal so large structures do not need to be fully materialized
|
|
25
29
|
|
|
26
30
|
## Main Helpers
|
|
27
31
|
|
|
32
|
+
- `toText(value)`
|
|
33
|
+
- `sliceText(value, options)`
|
|
34
|
+
- `takeText(value, count)`
|
|
35
|
+
- `takeRightText(value, count)`
|
|
36
|
+
- `dropText(value, count)`
|
|
37
|
+
- `dropRightText(value, count)`
|
|
38
|
+
- `spliceText(value, deleteCount, insertion, options)`
|
|
39
|
+
- `insertText(value, insertion, options)`
|
|
40
|
+
- `replaceRangeText(value, replacement, options)`
|
|
41
|
+
- `truncate(value, options)`
|
|
42
|
+
- `findSubstring(value, needle, options)`
|
|
43
|
+
- `countSubstrings(value, needle, options)`
|
|
44
|
+
- `between(value, left, right, options)`
|
|
45
|
+
- `splitLines(value)`
|
|
46
|
+
- `splitWords(value)`
|
|
28
47
|
- `toArray(value)`
|
|
29
48
|
- `chunk(array, size)`
|
|
49
|
+
- `sliceRange(array, options)`
|
|
50
|
+
- `take(array, count)`
|
|
51
|
+
- `takeRight(array, count)`
|
|
52
|
+
- `drop(array, count)`
|
|
53
|
+
- `dropRight(array, count)`
|
|
30
54
|
- `compact(array)`
|
|
31
55
|
- `uniq(array)`
|
|
32
56
|
- `uniqBy(array, iteratee)`
|
|
@@ -38,11 +62,22 @@ npm install @qezor/structkit
|
|
|
38
62
|
- `keyBy(array, iteratee)`
|
|
39
63
|
- `sortBy(array, iteratee)`
|
|
40
64
|
- `flatMap(array, iteratee)`
|
|
65
|
+
- `spliceAt(array, index, deleteCount, items)`
|
|
66
|
+
- `insertAt(array, index, items)`
|
|
67
|
+
- `removeAt(array, index, count)`
|
|
68
|
+
- `replaceRange(array, replacement, options)`
|
|
69
|
+
- `move(array, fromIndex, toIndex)`
|
|
70
|
+
- `findIndexFrom(array, iteratee, options)`
|
|
71
|
+
- `findLastIndexFrom(array, iteratee, options)`
|
|
72
|
+
- `mapRange(array, iteratee, options)`
|
|
73
|
+
- `filterRange(array, iteratee, options)`
|
|
41
74
|
- `sumBy(array, iteratee)`
|
|
42
75
|
- `tokenizePath(path)`
|
|
43
76
|
- `get(value, path, defaultValue)`
|
|
44
77
|
- `has(value, path)`
|
|
45
78
|
- `set(value, path, nextValue)`
|
|
79
|
+
- `update(value, path, updater, options)`
|
|
80
|
+
- `insertAtPath(value, path, insertion, options)`
|
|
46
81
|
- `unset(value, path)`
|
|
47
82
|
- `pick(value, paths)`
|
|
48
83
|
- `omit(value, paths)`
|
|
@@ -53,47 +88,64 @@ npm install @qezor/structkit
|
|
|
53
88
|
- `cloneDeep(value)`
|
|
54
89
|
- `mergeDeep(target, ...sources)`
|
|
55
90
|
- `isEqual(left, right)`
|
|
91
|
+
- `iterateDeep(value, options)`
|
|
92
|
+
- `findDeep(value, predicate, options)`
|
|
93
|
+
- `filterDeep(value, predicate, options)`
|
|
94
|
+
- `findPaths(value, predicate, options)`
|
|
95
|
+
- `mapDeep(value, predicate, updater, options)`
|
|
96
|
+
- `removeDeep(value, predicate, options)`
|
|
97
|
+
- `insertDeep(value, predicate, insertion, options)`
|
|
56
98
|
|
|
57
99
|
## Usage
|
|
58
100
|
|
|
59
101
|
```js
|
|
60
102
|
const {
|
|
61
|
-
|
|
103
|
+
truncate,
|
|
104
|
+
insertAt,
|
|
105
|
+
insertText,
|
|
106
|
+
insertAtPath,
|
|
107
|
+
findDeep,
|
|
108
|
+
insertDeep,
|
|
62
109
|
get,
|
|
63
110
|
set,
|
|
64
|
-
mergeDeep,
|
|
65
|
-
isEqual,
|
|
66
111
|
} = require("@qezor/structkit")
|
|
67
112
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
{ id: "
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
113
|
+
const queue = {
|
|
114
|
+
region: { city: "Pune" },
|
|
115
|
+
buyers: [{ id: "u_1" }, { id: "u_2" }],
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
set(queue, "limits.moq", 500)
|
|
119
|
+
|
|
120
|
+
const title = truncate("Wholesale demand aggregation for notebooks", {
|
|
121
|
+
maxLength: 24,
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
const buyers = insertAt(queue.buyers, 1, { id: "u_1_5" })
|
|
125
|
+
const label = insertText("bulkbuy", "-", { after: "bulk" })
|
|
126
|
+
insertAtPath(queue, "buyers", { id: "u_0" }, { index: 0 })
|
|
127
|
+
const cityNode = findDeep(queue, { path: "region.city" })
|
|
128
|
+
const upgraded = insertDeep(
|
|
129
|
+
{ regions: [["Pune"], ["Mumbai"]] },
|
|
130
|
+
{ path: "regions[1]" },
|
|
131
|
+
"Nagpur",
|
|
132
|
+
{ index: 1 }
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
const city = get(queue, "region.city")
|
|
82
136
|
```
|
|
83
137
|
|
|
84
|
-
## Qezor Bridge
|
|
85
|
-
|
|
86
|
-
The root export carries bridge metadata through `Symbol.for("qezor.bridge")`.
|
|
87
|
-
|
|
88
|
-
That lets other Qezor libraries detect things like:
|
|
89
|
-
- `structure`
|
|
90
|
-
- `structure:array`
|
|
91
|
-
- `structure:object`
|
|
92
|
-
- `structure:path`
|
|
93
|
-
- `structure:compare`
|
|
94
|
-
|
|
95
138
|
## Notes
|
|
96
139
|
|
|
140
|
+
- string and array range operations use inclusive start and exclusive end semantics under the hood
|
|
141
|
+
- `between(..., { greedy: true })` uses the farthest right delimiter inside the active range
|
|
142
|
+
- `insertText()` can place content by index or relative to `before` / `after` markers, with optional greedy matching
|
|
143
|
+
- `spliceAt()` is the low-level array primitive behind insert/remove/replace behavior
|
|
144
|
+
- `update()` is the clean path-based updater when `get()` + `set()` would be noisy
|
|
145
|
+
- `insertAtPath()` and `insertDeep()` cover precise insertion without hand-writing clone/update boilerplate
|
|
146
|
+
- deep traversal is iterative and generator-based, so large structures can be walked progressively
|
|
147
|
+
- in deep helpers, `depth` means structural depth from `fromPath`, while `pathDepth` tracks raw path length from `fromPath`
|
|
148
|
+
- use `fromPath`, `minDepth`, `maxDepth`, `minPathDepth`, `maxPathDepth`, `greedy`, `limit`, and `maxNodes` to stay precise and resource-safe
|
|
97
149
|
- deep clone, deep merge, and deep equality use iterative walkers instead of recursion
|
|
98
150
|
- arrays are replaced during `mergeDeep()` instead of element-wise merged
|
|
99
151
|
- `omit()` works on cloned data, so the original input is left untouched
|
package/index.d.ts
CHANGED
|
@@ -6,23 +6,93 @@ export type Iteratee<T = unknown, R = unknown> =
|
|
|
6
6
|
| null
|
|
7
7
|
| undefined
|
|
8
8
|
|
|
9
|
-
export interface
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
dependencies: string[]
|
|
9
|
+
export interface RangeOptions {
|
|
10
|
+
from?: number
|
|
11
|
+
start?: number
|
|
12
|
+
to?: number
|
|
13
|
+
end?: number
|
|
14
|
+
count?: number
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
export interface TextInsertOptions extends RangeOptions {
|
|
18
|
+
at?: number
|
|
19
|
+
index?: number
|
|
20
|
+
before?: string
|
|
21
|
+
after?: string
|
|
22
|
+
greedy?: boolean
|
|
23
|
+
last?: boolean
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DeepEntry {
|
|
27
|
+
value: unknown
|
|
28
|
+
parent: unknown
|
|
29
|
+
key: string | null
|
|
30
|
+
tokens: PathToken[]
|
|
31
|
+
path: string
|
|
32
|
+
depth: number
|
|
33
|
+
pathDepth: number
|
|
34
|
+
absoluteDepth: number
|
|
35
|
+
type: string
|
|
36
|
+
isContainer: boolean
|
|
37
|
+
isLeaf: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface DeepOptions {
|
|
41
|
+
fromPath?: PathInput
|
|
42
|
+
scope?: PathInput
|
|
43
|
+
minDepth?: number
|
|
44
|
+
maxDepth?: number
|
|
45
|
+
includeRoot?: boolean
|
|
46
|
+
includeContainers?: boolean
|
|
47
|
+
includeLeaves?: boolean
|
|
48
|
+
order?: "dfs" | "bfs"
|
|
49
|
+
greedy?: boolean | "last" | "deepest" | "path" | "deepest-path"
|
|
50
|
+
limit?: number
|
|
51
|
+
maxNodes?: number
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export type DeepPredicate =
|
|
55
|
+
| ((entry: DeepEntry) => boolean)
|
|
56
|
+
| string
|
|
57
|
+
| {
|
|
58
|
+
path?: string
|
|
59
|
+
key?: string
|
|
60
|
+
value?: unknown
|
|
61
|
+
type?: string
|
|
62
|
+
depth?: number
|
|
63
|
+
pathDepth?: number
|
|
64
|
+
absoluteDepth?: number
|
|
65
|
+
minDepth?: number
|
|
66
|
+
maxDepth?: number
|
|
67
|
+
minPathDepth?: number
|
|
68
|
+
maxPathDepth?: number
|
|
69
|
+
includes?: string
|
|
70
|
+
}
|
|
71
|
+
| unknown
|
|
72
|
+
|
|
73
|
+
export function toText(value: unknown): string
|
|
74
|
+
export function sliceText(value: unknown, options?: RangeOptions): string
|
|
75
|
+
export function takeText(value: unknown, count?: number): string
|
|
76
|
+
export function takeRightText(value: unknown, count?: number): string
|
|
77
|
+
export function dropText(value: unknown, count?: number): string
|
|
78
|
+
export function dropRightText(value: unknown, count?: number): string
|
|
79
|
+
export function spliceText(value: unknown, deleteCount?: number, insertion?: unknown, options?: { at?: number; index?: number; from?: number; start?: number }): string
|
|
80
|
+
export function insertText(value: unknown, insertion: unknown, options?: TextInsertOptions): string
|
|
81
|
+
export function replaceRangeText(value: unknown, replacement: unknown, options?: RangeOptions): string
|
|
82
|
+
export function truncate(value: unknown, options?: { maxLength?: number; length?: number; omission?: string; position?: "start" | "middle" | "end" }): string
|
|
83
|
+
export function findSubstring(value: unknown, needle: unknown, options?: RangeOptions & { last?: boolean }): number
|
|
84
|
+
export function countSubstrings(value: unknown, needle: unknown, options?: RangeOptions & { allowOverlap?: boolean }): number
|
|
85
|
+
export function between(value: unknown, left: unknown, right: unknown, options?: RangeOptions & { includeDelimiters?: boolean; greedy?: boolean }): string
|
|
86
|
+
export function splitLines(value: unknown): string[]
|
|
87
|
+
export function splitWords(value: unknown): string[]
|
|
23
88
|
|
|
24
89
|
export function toArray<T = unknown>(value: unknown): T[]
|
|
25
90
|
export function chunk<T = unknown>(value: unknown, size?: number): T[][]
|
|
91
|
+
export function sliceRange<T = unknown>(value: unknown, options?: RangeOptions): T[]
|
|
92
|
+
export function take<T = unknown>(value: unknown, count?: number): T[]
|
|
93
|
+
export function takeRight<T = unknown>(value: unknown, count?: number): T[]
|
|
94
|
+
export function drop<T = unknown>(value: unknown, count?: number): T[]
|
|
95
|
+
export function dropRight<T = unknown>(value: unknown, count?: number): T[]
|
|
26
96
|
export function compact<T = unknown>(value: unknown): T[]
|
|
27
97
|
export function uniq<T = unknown>(value: unknown): T[]
|
|
28
98
|
export function uniqBy<T = unknown>(value: unknown, iteratee?: Iteratee<T, unknown>): T[]
|
|
@@ -34,12 +104,23 @@ export function countBy<T = unknown>(value: unknown, iteratee?: Iteratee<T, unkn
|
|
|
34
104
|
export function keyBy<T = unknown>(value: unknown, iteratee?: Iteratee<T, unknown>): Record<string, T>
|
|
35
105
|
export function sortBy<T = unknown>(value: unknown, iteratee?: Iteratee<T, unknown>): T[]
|
|
36
106
|
export function flatMap<T = unknown, R = unknown>(value: unknown, iteratee?: Iteratee<T, R | R[]>): R[]
|
|
107
|
+
export function spliceAt<T = unknown>(value: unknown, index: number, deleteCount?: number, items?: T | T[]): T[]
|
|
108
|
+
export function insertAt<T = unknown>(value: unknown, index: number, items: T | T[]): T[]
|
|
109
|
+
export function removeAt<T = unknown>(value: unknown, index: number, count?: number): T[]
|
|
110
|
+
export function replaceRange<T = unknown>(value: unknown, replacement: T | T[], options?: RangeOptions): T[]
|
|
111
|
+
export function move<T = unknown>(value: unknown, fromIndex: number, toIndex: number): T[]
|
|
112
|
+
export function findIndexFrom<T = unknown>(value: unknown, iteratee?: Iteratee<T, unknown>, options?: RangeOptions): number
|
|
113
|
+
export function findLastIndexFrom<T = unknown>(value: unknown, iteratee?: Iteratee<T, unknown>, options?: RangeOptions): number
|
|
114
|
+
export function mapRange<T = unknown, R = unknown>(value: unknown, iteratee?: Iteratee<T, R>, options?: RangeOptions): Array<T | R>
|
|
115
|
+
export function filterRange<T = unknown>(value: unknown, iteratee?: Iteratee<T, unknown>, options?: RangeOptions): T[]
|
|
37
116
|
export function sumBy<T = unknown>(value: unknown, iteratee?: Iteratee<T, number>): number
|
|
38
117
|
|
|
39
118
|
export function tokenizePath(path: PathInput): PathToken[]
|
|
40
119
|
export function get<T = unknown>(value: unknown, path: PathInput, defaultValue?: T): T
|
|
41
120
|
export function has(value: unknown, path: PathInput): boolean
|
|
42
121
|
export function set<T extends object>(target: T, path: PathInput, nextValue: unknown): T
|
|
122
|
+
export function update<T = unknown>(target: T, path: PathInput, updater: (value: unknown, entry: { value: unknown; path: string; tokens: PathToken[] }) => unknown, options?: { defaultValue?: unknown }): T
|
|
123
|
+
export function insertAtPath<T = unknown>(target: T, path: PathInput, insertion: unknown, options?: { at?: number; index?: number; before?: string; after?: string; greedy?: boolean; last?: boolean; key?: string; property?: string; merge?: boolean; createMissing?: boolean; kind?: "array" | "string" | "object" }): T
|
|
43
124
|
export function unset(target: object, path: PathInput): boolean
|
|
44
125
|
export function pick(value: unknown, paths: PathInput | PathInput[]): Record<string, unknown>
|
|
45
126
|
export function omit<T = unknown>(value: T, paths: PathInput | PathInput[]): T
|
|
@@ -51,3 +132,10 @@ export function cloneDeep<T = unknown>(value: T): T
|
|
|
51
132
|
export function mergeDeep<T extends Record<string, unknown>>(target: T, ...sources: Array<Record<string, unknown>>): T
|
|
52
133
|
|
|
53
134
|
export function isEqual(left: unknown, right: unknown): boolean
|
|
135
|
+
export function iterateDeep(value: unknown, options?: DeepOptions): IterableIterator<DeepEntry>
|
|
136
|
+
export function findDeep(value: unknown, predicate?: DeepPredicate, options?: DeepOptions): DeepEntry | undefined
|
|
137
|
+
export function filterDeep(value: unknown, predicate?: DeepPredicate, options?: DeepOptions): DeepEntry[]
|
|
138
|
+
export function findPaths(value: unknown, predicate?: DeepPredicate, options?: DeepOptions): string[]
|
|
139
|
+
export function mapDeep<T = unknown>(value: T, predicate: DeepPredicate, updater: (value: unknown, entry: DeepEntry) => unknown, options?: DeepOptions): T
|
|
140
|
+
export function removeDeep<T = unknown>(value: T, predicate: DeepPredicate, options?: DeepOptions): T | undefined
|
|
141
|
+
export function insertDeep<T = unknown>(value: T, predicate: DeepPredicate, insertion: unknown | ((value: unknown, entry: DeepEntry) => unknown), options?: DeepOptions & { at?: number; index?: number; before?: string; after?: string; greedy?: boolean | "last" | "deepest" | "path" | "deepest-path"; last?: boolean; key?: string; property?: string; merge?: boolean; createMissing?: boolean; kind?: "array" | "string" | "object" }): T
|
package/index.js
CHANGED
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
"use strict"
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const string = require("./lib/string.js")
|
|
4
4
|
const array = require("./lib/array.js")
|
|
5
5
|
const object = require("./lib/object.js")
|
|
6
6
|
const compare = require("./lib/compare.js")
|
|
7
|
+
const deep = require("./lib/deep.js")
|
|
7
8
|
|
|
8
|
-
module.exports =
|
|
9
|
+
module.exports = {
|
|
10
|
+
...string,
|
|
9
11
|
...array,
|
|
10
12
|
...object,
|
|
11
13
|
...compare,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
attachQezorBridge: bridge.attachQezorBridge,
|
|
15
|
-
readQezorBridge: bridge.readQezorBridge,
|
|
16
|
-
hasQezorCapability: bridge.hasQezorCapability,
|
|
17
|
-
}, {
|
|
18
|
-
name: "@qezor/structkit",
|
|
19
|
-
kind: "library",
|
|
20
|
-
version: "1.0.0",
|
|
21
|
-
capabilities: [
|
|
22
|
-
"bridge",
|
|
23
|
-
"structure",
|
|
24
|
-
"structure:array",
|
|
25
|
-
"structure:object",
|
|
26
|
-
"structure:path",
|
|
27
|
-
"structure:compare",
|
|
28
|
-
],
|
|
29
|
-
adapters: ["plain-data"],
|
|
30
|
-
})
|
|
14
|
+
...deep,
|
|
15
|
+
}
|
package/index.mjs
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
import mod from "./index.js"
|
|
2
2
|
|
|
3
3
|
export const {
|
|
4
|
+
toText,
|
|
5
|
+
sliceText,
|
|
6
|
+
takeText,
|
|
7
|
+
takeRightText,
|
|
8
|
+
dropText,
|
|
9
|
+
dropRightText,
|
|
10
|
+
spliceText,
|
|
11
|
+
insertText,
|
|
12
|
+
replaceRangeText,
|
|
13
|
+
truncate,
|
|
14
|
+
findSubstring,
|
|
15
|
+
countSubstrings,
|
|
16
|
+
between,
|
|
17
|
+
splitLines,
|
|
18
|
+
splitWords,
|
|
4
19
|
toArray,
|
|
5
20
|
chunk,
|
|
21
|
+
sliceRange,
|
|
22
|
+
take,
|
|
23
|
+
takeRight,
|
|
24
|
+
drop,
|
|
25
|
+
dropRight,
|
|
6
26
|
compact,
|
|
7
27
|
uniq,
|
|
8
28
|
uniqBy,
|
|
@@ -14,11 +34,22 @@ export const {
|
|
|
14
34
|
keyBy,
|
|
15
35
|
sortBy,
|
|
16
36
|
flatMap,
|
|
37
|
+
spliceAt,
|
|
38
|
+
insertAt,
|
|
39
|
+
removeAt,
|
|
40
|
+
replaceRange,
|
|
41
|
+
move,
|
|
42
|
+
findIndexFrom,
|
|
43
|
+
findLastIndexFrom,
|
|
44
|
+
mapRange,
|
|
45
|
+
filterRange,
|
|
17
46
|
sumBy,
|
|
18
47
|
tokenizePath,
|
|
19
48
|
get,
|
|
20
49
|
has,
|
|
21
50
|
set,
|
|
51
|
+
update,
|
|
52
|
+
insertAtPath,
|
|
22
53
|
unset,
|
|
23
54
|
pick,
|
|
24
55
|
omit,
|
|
@@ -29,11 +60,13 @@ export const {
|
|
|
29
60
|
cloneDeep,
|
|
30
61
|
mergeDeep,
|
|
31
62
|
isEqual,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
63
|
+
iterateDeep,
|
|
64
|
+
findDeep,
|
|
65
|
+
filterDeep,
|
|
66
|
+
findPaths,
|
|
67
|
+
mapDeep,
|
|
68
|
+
removeDeep,
|
|
69
|
+
insertDeep,
|
|
37
70
|
} = mod
|
|
38
71
|
|
|
39
72
|
export default mod
|
package/lib/array.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict"
|
|
2
2
|
|
|
3
3
|
const { createIteratee } = require("./shared.js")
|
|
4
|
+
const { normalizeRange, normalizeInsertIndex, normalizeCount } = require("./range.js")
|
|
4
5
|
|
|
5
6
|
function toArray(value) {
|
|
6
7
|
if (value == null) return []
|
|
@@ -21,6 +22,35 @@ function chunk(value, size = 1) {
|
|
|
21
22
|
return output
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
function sliceRange(value, options = {}) {
|
|
26
|
+
const list = toArray(value)
|
|
27
|
+
const range = normalizeRange(list.length, options)
|
|
28
|
+
return list.slice(range.start, range.end)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function take(value, count = 1) {
|
|
32
|
+
return sliceRange(value, {
|
|
33
|
+
start: 0,
|
|
34
|
+
count: normalizeCount(count, 1),
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function takeRight(value, count = 1) {
|
|
39
|
+
const list = toArray(value)
|
|
40
|
+
const amount = normalizeCount(count, 1)
|
|
41
|
+
return list.slice(Math.max(0, list.length - amount))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function drop(value, count = 1) {
|
|
45
|
+
const list = toArray(value)
|
|
46
|
+
return list.slice(Math.min(list.length, normalizeCount(count, 1)))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function dropRight(value, count = 1) {
|
|
50
|
+
const list = toArray(value)
|
|
51
|
+
return list.slice(0, Math.max(0, list.length - normalizeCount(count, 1)))
|
|
52
|
+
}
|
|
53
|
+
|
|
24
54
|
function compact(value) {
|
|
25
55
|
return toArray(value).filter(Boolean)
|
|
26
56
|
}
|
|
@@ -157,6 +187,101 @@ function flatMap(value, iteratee) {
|
|
|
157
187
|
return output
|
|
158
188
|
}
|
|
159
189
|
|
|
190
|
+
function spliceAt(value, index, deleteCount = 0, items = []) {
|
|
191
|
+
const list = toArray(value)
|
|
192
|
+
const at = normalizeInsertIndex(list.length, index, list.length)
|
|
193
|
+
const removeCount = normalizeCount(deleteCount, 0)
|
|
194
|
+
const insertItems = Array.isArray(items)
|
|
195
|
+
? items.slice()
|
|
196
|
+
: items === undefined
|
|
197
|
+
? []
|
|
198
|
+
: [items]
|
|
199
|
+
return [
|
|
200
|
+
...list.slice(0, at),
|
|
201
|
+
...insertItems,
|
|
202
|
+
...list.slice(Math.min(list.length, at + removeCount)),
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function insertAt(value, index, items) {
|
|
207
|
+
return spliceAt(value, index, 0, items)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function removeAt(value, index, count = 1) {
|
|
211
|
+
return spliceAt(value, index, count, [])
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function replaceRange(value, replacement, options = {}) {
|
|
215
|
+
const list = toArray(value)
|
|
216
|
+
const range = normalizeRange(list.length, options)
|
|
217
|
+
return spliceAt(list, range.start, range.length, replacement)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function move(value, fromIndex, toIndex) {
|
|
221
|
+
const list = toArray(value)
|
|
222
|
+
if (!list.length) return list
|
|
223
|
+
|
|
224
|
+
const from = normalizeInsertIndex(list.length, fromIndex, 0)
|
|
225
|
+
const to = normalizeInsertIndex(list.length, toIndex, list.length - 1)
|
|
226
|
+
if (from === to) return list
|
|
227
|
+
|
|
228
|
+
const item = list[from]
|
|
229
|
+
const without = removeAt(list, from, 1)
|
|
230
|
+
const adjustedTo = from < to ? to - 1 : to
|
|
231
|
+
return insertAt(without, adjustedTo, item)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function findIndexFrom(value, iteratee, options = {}) {
|
|
235
|
+
const list = toArray(value)
|
|
236
|
+
const resolve = createIteratee(iteratee)
|
|
237
|
+
const range = normalizeRange(list.length, options)
|
|
238
|
+
|
|
239
|
+
for (let index = range.start; index < range.end; index += 1) {
|
|
240
|
+
if (resolve(list[index], index, list)) return index
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return -1
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function findLastIndexFrom(value, iteratee, options = {}) {
|
|
247
|
+
const list = toArray(value)
|
|
248
|
+
const resolve = createIteratee(iteratee)
|
|
249
|
+
const range = normalizeRange(list.length, options)
|
|
250
|
+
|
|
251
|
+
for (let index = range.end - 1; index >= range.start; index -= 1) {
|
|
252
|
+
if (resolve(list[index], index, list)) return index
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return -1
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function mapRange(value, iteratee, options = {}) {
|
|
259
|
+
const list = toArray(value)
|
|
260
|
+
const resolve = createIteratee(iteratee)
|
|
261
|
+
const range = normalizeRange(list.length, options)
|
|
262
|
+
const output = list.slice()
|
|
263
|
+
|
|
264
|
+
for (let index = range.start; index < range.end; index += 1) {
|
|
265
|
+
output[index] = resolve(list[index], index, list)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return output
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function filterRange(value, iteratee, options = {}) {
|
|
272
|
+
const list = toArray(value)
|
|
273
|
+
const resolve = createIteratee(iteratee)
|
|
274
|
+
const range = normalizeRange(list.length, options)
|
|
275
|
+
const output = []
|
|
276
|
+
|
|
277
|
+
for (let index = range.start; index < range.end; index += 1) {
|
|
278
|
+
const item = list[index]
|
|
279
|
+
if (resolve(item, index, list)) output.push(item)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return output
|
|
283
|
+
}
|
|
284
|
+
|
|
160
285
|
function sumBy(value, iteratee) {
|
|
161
286
|
const list = toArray(value)
|
|
162
287
|
const resolve = createIteratee(iteratee)
|
|
@@ -173,6 +298,11 @@ function sumBy(value, iteratee) {
|
|
|
173
298
|
module.exports = {
|
|
174
299
|
toArray,
|
|
175
300
|
chunk,
|
|
301
|
+
sliceRange,
|
|
302
|
+
take,
|
|
303
|
+
takeRight,
|
|
304
|
+
drop,
|
|
305
|
+
dropRight,
|
|
176
306
|
compact,
|
|
177
307
|
uniq,
|
|
178
308
|
uniqBy,
|
|
@@ -184,5 +314,14 @@ module.exports = {
|
|
|
184
314
|
keyBy,
|
|
185
315
|
sortBy,
|
|
186
316
|
flatMap,
|
|
317
|
+
spliceAt,
|
|
318
|
+
insertAt,
|
|
319
|
+
removeAt,
|
|
320
|
+
replaceRange,
|
|
321
|
+
move,
|
|
322
|
+
findIndexFrom,
|
|
323
|
+
findLastIndexFrom,
|
|
324
|
+
mapRange,
|
|
325
|
+
filterRange,
|
|
187
326
|
sumBy,
|
|
188
327
|
}
|