@nejs/basic-extensions 2.4.0 → 2.6.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.
- package/README.md +151 -118
- package/dist/@nejs/basic-extensions.bundle.2.5.0.js +8 -0
- package/dist/@nejs/basic-extensions.bundle.2.5.0.js.map +7 -0
- package/dist/cjs/arrayextensions.js +56 -54
- package/dist/cjs/arrayextensions.js.map +1 -1
- package/dist/cjs/functionextensions.js +81 -79
- package/dist/cjs/functionextensions.js.map +1 -1
- package/dist/cjs/mapextensions.js +23 -21
- package/dist/cjs/mapextensions.js.map +1 -1
- package/dist/cjs/objectextensions.js +49 -17
- package/dist/cjs/objectextensions.js.map +1 -1
- package/dist/cjs/setextensions.js +191 -189
- package/dist/cjs/setextensions.js.map +1 -1
- package/dist/cjs/stringextensions.js +69 -67
- package/dist/cjs/stringextensions.js.map +1 -1
- package/dist/mjs/arrayextensions.js +56 -54
- package/dist/mjs/arrayextensions.js.map +1 -1
- package/dist/mjs/functionextensions.js +81 -79
- package/dist/mjs/functionextensions.js.map +1 -1
- package/dist/mjs/mapextensions.js +23 -21
- package/dist/mjs/mapextensions.js.map +1 -1
- package/dist/mjs/objectextensions.js +49 -17
- package/dist/mjs/objectextensions.js.map +1 -1
- package/dist/mjs/setextensions.js +191 -189
- package/dist/mjs/setextensions.js.map +1 -1
- package/dist/mjs/stringextensions.js +69 -67
- package/dist/mjs/stringextensions.js.map +1 -1
- package/docs/index.html +636 -478
- package/package.json +5 -4
- package/src/arrayextensions.js +56 -55
- package/src/functionextensions.js +87 -85
- package/src/mapextensions.js +26 -24
- package/src/objectextensions.js +52 -17
- package/src/setextensions.js +216 -214
- package/src/stringextensions.js +69 -67
- package/dist/@nejs/basic-extensions.bundle.2.3.0.js +0 -8
- package/dist/@nejs/basic-extensions.bundle.2.3.0.js.map +0 -7
package/src/setextensions.js
CHANGED
|
@@ -1,242 +1,244 @@
|
|
|
1
1
|
import { Patch } from '@nejs/extension';
|
|
2
2
|
|
|
3
3
|
export const SetPrototypeExtensions = new Patch(Set.prototype, {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
[Patch.kMutablyHidden]: {
|
|
5
|
+
/**
|
|
6
|
+
* Merges multiple iterables into the set. Each element from the iterables
|
|
7
|
+
* is added to the set, ensuring uniqueness of all elements. This method
|
|
8
|
+
* mutates the original set.
|
|
9
|
+
*
|
|
10
|
+
* @param {...Iterable} iterables - One or more iterable objects (like Set
|
|
11
|
+
* or Array) whose elements will be added to the set.
|
|
12
|
+
*/
|
|
13
|
+
concat(...iterables) {
|
|
14
|
+
for (const iterable of iterables) {
|
|
15
|
+
if (
|
|
16
|
+
typeof iterable === 'string' ||
|
|
17
|
+
!Reflect.has(iterable, Symbol.iterator)
|
|
18
|
+
) {
|
|
19
|
+
this.add(iterable)
|
|
20
|
+
continue
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
for (const element of iterable) {
|
|
24
|
+
this.add(element)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Checks to see if any value within the `Set` loosely equals the supplied
|
|
31
|
+
* value.
|
|
32
|
+
*
|
|
33
|
+
* @param {*} value any value that might be loosely equal to an item in the
|
|
34
|
+
* set, as opposed to {@link Set.has} which is the equivalent of a strict or
|
|
35
|
+
* triple equals (`===`) check
|
|
36
|
+
* @returns {boolean} `true` if any value within the set is loosely equal to
|
|
37
|
+
* the supplied value, `false` otherwise
|
|
38
|
+
*/
|
|
39
|
+
contains(value) {
|
|
40
|
+
for (const element of this) {
|
|
41
|
+
if (value == element) {
|
|
42
|
+
return true
|
|
43
|
+
}
|
|
20
44
|
}
|
|
21
45
|
|
|
22
|
-
|
|
23
|
-
|
|
46
|
+
return false
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Checks if every element in the set passes the test implemented by the
|
|
51
|
+
* provided function. The function is called with each element of the set.
|
|
52
|
+
* Note: Since sets do not have indices, the index parameter is always NaN.
|
|
53
|
+
*
|
|
54
|
+
* @param {Function} everyFn - The function to test each element. Receives
|
|
55
|
+
* the element, index (always NaN), and the set itself.
|
|
56
|
+
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
57
|
+
* `everyFn`.
|
|
58
|
+
* @throws {TypeError} If `everyFn` is not a function.
|
|
59
|
+
* @returns {boolean} True if every element passes the test, false otherwise.
|
|
60
|
+
*/
|
|
61
|
+
every(everyFn, thisArg) {
|
|
62
|
+
if (typeof everyFn !== 'function') {
|
|
63
|
+
throw new TypeError(
|
|
64
|
+
`everyFn must be a function! Received ${String(everyFn)}`
|
|
65
|
+
)
|
|
24
66
|
}
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
67
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* triple equals (`===`) check
|
|
35
|
-
* @returns {boolean} `true` if any value within the set is loosely equal to
|
|
36
|
-
* the supplied value, `false` otherwise
|
|
37
|
-
*/
|
|
38
|
-
contains(value) {
|
|
39
|
-
for (const element of this) {
|
|
40
|
-
if (value == element) {
|
|
41
|
-
return true
|
|
68
|
+
let found = 0
|
|
69
|
+
|
|
70
|
+
for (const element of this) {
|
|
71
|
+
if (everyFn.call(thisArg, element, NaN, this)) {
|
|
72
|
+
found++
|
|
73
|
+
}
|
|
42
74
|
}
|
|
43
|
-
}
|
|
44
75
|
|
|
45
|
-
|
|
46
|
-
|
|
76
|
+
return (found === this.size)
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Finds the first element in the set satisfying the provided testing
|
|
82
|
+
* function. If no elements satisfy the testing function, undefined is
|
|
83
|
+
* returned. The function is called with each element of the set.
|
|
84
|
+
* Note: Since sets do not have indices, the index parameter is always NaN.
|
|
85
|
+
*
|
|
86
|
+
* @param {Function} findFn - The function to execute on each element. It
|
|
87
|
+
* receives the element, index (always NaN), and the set itself.
|
|
88
|
+
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
89
|
+
* `findFn`.
|
|
90
|
+
* @throws {TypeError} If `findFn` is not a function.
|
|
91
|
+
* @returns {*} The first element that satisfies `findFn`, or undefined.
|
|
92
|
+
*/
|
|
93
|
+
find(findFn, thisArg) {
|
|
94
|
+
if (typeof findFn !== 'function') {
|
|
95
|
+
throw new TypeError(
|
|
96
|
+
`findFn must be a function! Received ${String(findFn)}`
|
|
97
|
+
)
|
|
98
|
+
}
|
|
47
99
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* @param {Function} everyFn - The function to test each element. Receives
|
|
54
|
-
* the element, index (always NaN), and the set itself.
|
|
55
|
-
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
56
|
-
* `everyFn`.
|
|
57
|
-
* @throws {TypeError} If `everyFn` is not a function.
|
|
58
|
-
* @returns {boolean} True if every element passes the test, false otherwise.
|
|
59
|
-
*/
|
|
60
|
-
every(everyFn, thisArg) {
|
|
61
|
-
if (typeof everyFn !== 'function') {
|
|
62
|
-
throw new TypeError(
|
|
63
|
-
`everyFn must be a function! Received ${String(everyFn)}`
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
let found = 0
|
|
68
|
-
|
|
69
|
-
for (const element of this) {
|
|
70
|
-
if (everyFn.call(thisArg, element, NaN, this)) {
|
|
71
|
-
found++
|
|
100
|
+
for (const element of this) {
|
|
101
|
+
const match = findFn.call(thisArg, element, NaN, this)
|
|
102
|
+
if (match) {
|
|
103
|
+
return element
|
|
104
|
+
}
|
|
72
105
|
}
|
|
73
|
-
}
|
|
74
106
|
|
|
75
|
-
|
|
76
|
-
|
|
107
|
+
return undefined
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Finds the last element in the set satisfying the provided testing function.
|
|
112
|
+
* If no elements satisfy the testing function, undefined is returned. The
|
|
113
|
+
* function is called with each element of the set in reverse order.
|
|
114
|
+
* Note: Since sets do not have indices, the index parameter is always NaN.
|
|
115
|
+
*
|
|
116
|
+
* @param {Function} findFn - The function to execute on each element. It
|
|
117
|
+
* receives the element, index (always NaN), and the set itself.
|
|
118
|
+
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
119
|
+
* `findFn`.
|
|
120
|
+
* @throws {TypeError} If `findFn` is not a function.
|
|
121
|
+
* @returns {*} The last element that satisfies `findFn`, or undefined.
|
|
122
|
+
*/
|
|
123
|
+
findLast(findFn, thisArg) {
|
|
124
|
+
if (typeof findFn !== 'function') {
|
|
125
|
+
throw new TypeError(
|
|
126
|
+
`findFn must be a function! Received ${String(findFn)}`
|
|
127
|
+
)
|
|
128
|
+
}
|
|
77
129
|
|
|
130
|
+
const found = []
|
|
78
131
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
*
|
|
85
|
-
* @param {Function} findFn - The function to execute on each element. It
|
|
86
|
-
* receives the element, index (always NaN), and the set itself.
|
|
87
|
-
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
88
|
-
* `findFn`.
|
|
89
|
-
* @throws {TypeError} If `findFn` is not a function.
|
|
90
|
-
* @returns {*} The first element that satisfies `findFn`, or undefined.
|
|
91
|
-
*/
|
|
92
|
-
find(findFn, thisArg) {
|
|
93
|
-
if (typeof findFn !== 'function') {
|
|
94
|
-
throw new TypeError(
|
|
95
|
-
`findFn must be a function! Received ${String(findFn)}`
|
|
96
|
-
)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
for (const element of this) {
|
|
100
|
-
const match = findFn.call(thisArg, element, NaN, this)
|
|
101
|
-
if (match) {
|
|
102
|
-
return element
|
|
132
|
+
for (const element of this) {
|
|
133
|
+
const match = findFn.call(thisArg, element, NaN, this)
|
|
134
|
+
if (match) {
|
|
135
|
+
found.push(element)
|
|
136
|
+
}
|
|
103
137
|
}
|
|
104
|
-
}
|
|
105
138
|
|
|
106
|
-
|
|
107
|
-
|
|
139
|
+
if (found.length) {
|
|
140
|
+
return found[found.length - 1]
|
|
141
|
+
}
|
|
108
142
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
return undefined
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A getter property that returns the number of elements in the set.
|
|
148
|
+
* This is an alias for the `size` property of the set.
|
|
149
|
+
*
|
|
150
|
+
* @returns {number} The number of elements in the set.
|
|
151
|
+
*/
|
|
152
|
+
get length() {
|
|
153
|
+
return this.size
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Creates a new array populated with the results of calling the provided
|
|
158
|
+
* function on every element in the set. The function is called with each
|
|
159
|
+
* element of the set. Note: Since sets do not have indices, the index
|
|
160
|
+
* parameter is always NaN.
|
|
161
|
+
*
|
|
162
|
+
* @param {Function} mapFn - The function to execute on each element. It
|
|
163
|
+
* receives the element, index (always NaN), and the set itself.
|
|
164
|
+
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
165
|
+
* `mapFn`.
|
|
166
|
+
* @throws {TypeError} If `mapFn` is not a function.
|
|
167
|
+
* @returns {Array} A new array with each element being the result of the
|
|
168
|
+
* `mapFn`.
|
|
169
|
+
*/
|
|
170
|
+
map(mapFn, thisArg) {
|
|
171
|
+
if (typeof mapFn !== 'function') {
|
|
172
|
+
throw new TypeError(
|
|
173
|
+
`mapFn must be a function! Received ${String(mapFn)}`
|
|
174
|
+
)
|
|
135
175
|
}
|
|
136
|
-
}
|
|
137
176
|
|
|
138
|
-
|
|
139
|
-
return found[found.length - 1]
|
|
140
|
-
}
|
|
177
|
+
const transformed = []
|
|
141
178
|
|
|
142
|
-
|
|
143
|
-
|
|
179
|
+
for (const element of this) {
|
|
180
|
+
transformed.push(mapFn.call(thisArg, element, NaN, this))
|
|
181
|
+
}
|
|
144
182
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
183
|
+
return transformed
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Applies a function against an accumulator and each element in the set to
|
|
188
|
+
* reduce it to a single value. The function is called with each element of
|
|
189
|
+
* the set. Note: Since sets do not have indices, the index parameter is
|
|
190
|
+
* always NaN.
|
|
191
|
+
*
|
|
192
|
+
* @param {Function} reduceFn - The function to execute on each element. It
|
|
193
|
+
* receives the accumulator, element, index (always NaN), and the set itself.
|
|
194
|
+
* @param {*} initialValue - The initial value to start reducing from.
|
|
195
|
+
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
196
|
+
* `reduceFn`.
|
|
197
|
+
* @throws {TypeError} If `reduceFn` is not a function.
|
|
198
|
+
* @returns {*} The reduced value.
|
|
199
|
+
*/
|
|
200
|
+
reduce(reduceFn, initialValue, thisArg) {
|
|
201
|
+
if (typeof reduceFn !== 'function') {
|
|
202
|
+
throw new TypeError(
|
|
203
|
+
`reduceFn must be a Function! Received ${String(reduceFn)}`
|
|
204
|
+
)
|
|
205
|
+
}
|
|
154
206
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
* parameter is always NaN.
|
|
160
|
-
*
|
|
161
|
-
* @param {Function} mapFn - The function to execute on each element. It
|
|
162
|
-
* receives the element, index (always NaN), and the set itself.
|
|
163
|
-
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
164
|
-
* `mapFn`.
|
|
165
|
-
* @throws {TypeError} If `mapFn` is not a function.
|
|
166
|
-
* @returns {Array} A new array with each element being the result of the
|
|
167
|
-
* `mapFn`.
|
|
168
|
-
*/
|
|
169
|
-
map(mapFn, thisArg) {
|
|
170
|
-
if (typeof mapFn !== 'function') {
|
|
171
|
-
throw new TypeError(
|
|
172
|
-
`mapFn must be a function! Received ${String(mapFn)}`
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const transformed = []
|
|
177
|
-
|
|
178
|
-
for (const element of this) {
|
|
179
|
-
transformed.push(mapFn.call(thisArg, element, NaN, this))
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return transformed
|
|
183
|
-
},
|
|
207
|
+
let accumulator = initialValue
|
|
208
|
+
for (const element of this) {
|
|
209
|
+
accumulator = reduceFn.call(thisArg, accumulator, element, NaN, this)
|
|
210
|
+
}
|
|
184
211
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
for (const element of this) {
|
|
208
|
-
accumulator = reduceFn.call(thisArg, accumulator, element, NaN, this)
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return accumulator
|
|
212
|
-
},
|
|
212
|
+
return accumulator
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Tests whether at least one element in the set passes the test implemented
|
|
217
|
+
* by the provided function. The function is called with each element of the
|
|
218
|
+
* set. Note: Since sets do not have indices, the index parameter is always NaN.
|
|
219
|
+
*
|
|
220
|
+
* @param {Function} someFn - The function to test each element. It receives
|
|
221
|
+
* the element, index (always NaN), and the set itself.
|
|
222
|
+
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
223
|
+
* `someFn`.
|
|
224
|
+
* @throws {TypeError} If `someFn` is not a function.
|
|
225
|
+
* @returns {boolean} True if at least one element passes the test, false
|
|
226
|
+
* otherwise.
|
|
227
|
+
*/
|
|
228
|
+
some(someFn, thisArg) {
|
|
229
|
+
if (typeof someFn !== 'function') {
|
|
230
|
+
throw new TypeError(
|
|
231
|
+
`someFn must be a function! Received ${String(someFn)}`
|
|
232
|
+
)
|
|
233
|
+
}
|
|
213
234
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
*
|
|
219
|
-
* @param {Function} someFn - The function to test each element. It receives
|
|
220
|
-
* the element, index (always NaN), and the set itself.
|
|
221
|
-
* @param {Object} [thisArg] - Optional. Value to use as `this` when executing
|
|
222
|
-
* `someFn`.
|
|
223
|
-
* @throws {TypeError} If `someFn` is not a function.
|
|
224
|
-
* @returns {boolean} True if at least one element passes the test, false
|
|
225
|
-
* otherwise.
|
|
226
|
-
*/
|
|
227
|
-
some(someFn, thisArg) {
|
|
228
|
-
if (typeof someFn !== 'function') {
|
|
229
|
-
throw new TypeError(
|
|
230
|
-
`someFn must be a function! Received ${String(someFn)}`
|
|
231
|
-
)
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
for (const element of this) {
|
|
235
|
-
if (someFn.call(thisArg, element, NaN, this)) {
|
|
236
|
-
return true
|
|
235
|
+
for (const element of this) {
|
|
236
|
+
if (someFn.call(thisArg, element, NaN, this)) {
|
|
237
|
+
return true
|
|
238
|
+
}
|
|
237
239
|
}
|
|
238
|
-
}
|
|
239
240
|
|
|
240
|
-
|
|
241
|
+
return false
|
|
242
|
+
},
|
|
241
243
|
},
|
|
242
244
|
})
|
package/src/stringextensions.js
CHANGED
|
@@ -85,80 +85,82 @@ export const StringExtensions = new Patch(String, {
|
|
|
85
85
|
* making string manipulation tasks more convenient and expressive.
|
|
86
86
|
*/
|
|
87
87
|
export const StringPrototypeExtensions = new Patch(String.prototype, {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
88
|
+
[Patch.kMutablyHidden]: {
|
|
89
|
+
/**
|
|
90
|
+
* Extracts a substring from the current string, starting at a given offset
|
|
91
|
+
* and bounded by specified opening and closing tokens. This method is
|
|
92
|
+
* particularly useful for parsing nested structures or quoted strings,
|
|
93
|
+
* where the level of nesting or the presence of escape characters must
|
|
94
|
+
* be considered.
|
|
95
|
+
*
|
|
96
|
+
* @param {number} offset The position in the string from which to start the
|
|
97
|
+
* search for the substring.
|
|
98
|
+
* @param {[string, string]} tokens An array containing two strings: the
|
|
99
|
+
* opening and closing tokens that define the boundaries of the substring
|
|
100
|
+
* to be extracted.
|
|
101
|
+
* @returns {Object} An object with two properties: `extracted`, the
|
|
102
|
+
* extracted substring, and `newOffset`, the position in the original
|
|
103
|
+
* string immediately after the end of the extracted substring. If no
|
|
104
|
+
* substring is found, `extracted` is `null` and `newOffset` is the same
|
|
105
|
+
* as the input offset.
|
|
106
|
+
*/
|
|
107
|
+
extractSubstring(offset = 0, tokens = parenthesisPair) {
|
|
108
|
+
let [openToken, closeToken] = tokens;
|
|
109
|
+
let depth = 0;
|
|
110
|
+
let start = -1;
|
|
111
|
+
let end = -1;
|
|
112
|
+
let leadingToken = '';
|
|
113
|
+
let firstToken = 0;
|
|
113
114
|
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
for (let i = offset; i < this.length; i++) {
|
|
116
|
+
const char = this[i];
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
118
|
+
if (char === openToken) {
|
|
119
|
+
depth++;
|
|
120
|
+
if (start === -1)
|
|
121
|
+
start = i;
|
|
122
|
+
}
|
|
123
|
+
else if (char === closeToken) {
|
|
124
|
+
depth--;
|
|
125
|
+
if (depth === 0) {
|
|
126
|
+
end = i;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
|
-
}
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
let lRange = [
|
|
133
|
+
Math.max(0, start - 100),
|
|
134
|
+
start
|
|
135
|
+
];
|
|
136
|
+
let leading = [...this.substring(lRange[0], lRange[1])].reverse().join('')
|
|
137
|
+
let reversedLeadingToken;
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
139
|
+
try {
|
|
140
|
+
reversedLeadingToken = /([^ \,\"\'\`]+)/.exec(leading)[1] ?? '';
|
|
141
|
+
leadingToken = [...reversedLeadingToken].reverse().join('');
|
|
142
|
+
}
|
|
143
|
+
catch(ignored) { }
|
|
143
144
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
145
|
+
if (start !== -1 && end !== -1) {
|
|
146
|
+
const sliceRange = [start, end + 1];
|
|
147
|
+
const extracted = this.slice(sliceRange[0], sliceRange[1]);
|
|
147
148
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
149
|
+
return {
|
|
150
|
+
extracted,
|
|
151
|
+
range: [start, end],
|
|
152
|
+
newOffset: end + 1,
|
|
153
|
+
leadingToken,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
return {
|
|
158
|
+
extracted: null,
|
|
159
|
+
range: [start, end],
|
|
160
|
+
newOffset: offset,
|
|
161
|
+
leadingToken,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
},
|
|
163
165
|
},
|
|
164
166
|
})
|