Skip to content

Commit d4b216b

Browse files
committed
refactor from-to
1 parent a1bfbe6 commit d4b216b

File tree

7 files changed

+347
-438
lines changed

7 files changed

+347
-438
lines changed

dist/index.cjs

Lines changed: 47 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -14,51 +14,18 @@ var arrayBack = require('array-back');
1414
* arr {string[]} - Input array. Only mutated if `options.remove` is set.
1515
* [options.rtol] {boolean} - Enable right-to-left scans. Either that or pass in a custom iterator. TODO.
1616
* [options.remove] {boolean} - Remove from source array
17-
* [options.inclusive] {boolean} - If `true` includes the to item.
18-
* [options.from] {string[]|function[]}
19-
* [options.to] {string[]|function[]} - A "Stop Here" function. Set one or more strings as the terminating arg. Or, from the function `fn(arg, index, argv, valueIndex)`, return true for the first arg that is out of range. Set `inclusive` to also include it.
20-
* [options.toInclude] {string[]|function[]} - From the function `fn(arg, index, argv, valueIndex)`, return true for the first arg that is out of range. Set `inclusive` to also include it.
21-
* [options.noFurtherThan] {function}
22-
* [options.toEnd] {boolean}
17+
* [options.from] {string[]|function[]} - String literal or a [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) callback function.
18+
* [options.to] {string[]|function[]} - A "Stop Here" function. Set one or more strings as the terminating arg. Or, from the function `fn(arg, index, argv, valueIndex)`, return true for the first arg that is out of range. Set `inclusive` to also include it. To will always search to the end of the input array.
2319
* @returns string[]
2420
*/
25-
function fromTo (arr, options = {}) {
26-
let { from: fromFn, to: toFn, noFurtherThan, remove, inclusive, toEnd } = options;
27-
28-
if (inclusive === undefined && !noFurtherThan && toFn) {
29-
inclusive = true;
30-
}
31-
toFn = toFn || noFurtherThan;
32-
fromFn = arrayBack(fromFn).map(fn => {
33-
if (typeof fn === 'string') {
34-
return function (val) { return val === fn }
35-
} else {
36-
return fn
37-
}
38-
});
39-
40-
if (fromFn.length === 0) {
41-
throw new Error('from required')
42-
}
43-
44-
toFn = arrayBack(toFn).map(fn => {
45-
if (typeof fn === 'string') {
46-
return function (item) { return item === fn }
47-
} else {
48-
return fn
49-
}
50-
});
5121

52-
let fromIndex;
53-
for (const fn of fromFn) {
54-
fromIndex = arr.findIndex(fn);
55-
if (fromIndex > -1) {
56-
break
57-
}
58-
}
22+
/* TODO: rename to extractFromTo? Rename `options.remove` to `extract`. */
23+
function fromTo (arr, options = {}) {
24+
const fromIndex = getFromIndex(arr, options.from);
5925

60-
let toIndex;
61-
if (toFn) {
26+
const toFn = arrayBack(options.to).map(convertToFunction);
27+
let toIndex = -1;
28+
if (toFn.length) {
6229
for (const fn of toFn) {
6330
toIndex = arr.findIndex((item, index, arr) => {
6431
if (index > fromIndex) {
@@ -68,54 +35,57 @@ function fromTo (arr, options = {}) {
6835
return false
6936
}
7037
});
38+
/* Keep looping until a match is found. */
7139
if (toIndex > -1) {
7240
break
7341
}
7442
}
7543
}
7644

77-
if (remove) {
78-
let deleteCount;
79-
if (toEnd) {
80-
deleteCount = arr.length;
81-
}
45+
const output = toIndex === -1
46+
? arr.slice(fromIndex) /* Return all to the end */
47+
: arr.slice(fromIndex, toIndex);
48+
49+
if (options.remove) {
8250
if (toIndex === -1) {
83-
/* TODO: If to is not found, should it behave the same as "no to" (just return the from value)? Scanning to the end supports `--option value value` */
84-
deleteCount = arr.length;
85-
} else if (toIndex === undefined) {
86-
/* When to is omitted, just pick the single value at the from index */
87-
/* This differs to arr.slice which slices to the end of the array if end is omitted */
88-
deleteCount = 1;
51+
arr.splice(fromIndex);
8952
} else {
90-
if (inclusive) {
91-
deleteCount = toIndex - fromIndex;
92-
} else {
93-
deleteCount = toIndex - fromIndex - 1;
94-
}
53+
arr.splice(fromIndex, toIndex - fromIndex);
9554
}
96-
return arr.splice(fromIndex, deleteCount)
97-
/* deleteCount: An integer indicating the number of elements in the array to remove from start. */
98-
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice */
55+
}
56+
57+
return output
58+
}
59+
60+
function convertToFunction (fn) {
61+
if (typeof fn === 'string') {
62+
return function (val) { return val === fn }
63+
} else if (fn instanceof RegExp) {
64+
return function (val) { return fn.test(val) }
9965
} else {
100-
if (toEnd) {
101-
toIndex = arr.length + 1;
102-
}
103-
if (toIndex === -1) {
104-
return arr.slice(fromIndex)
105-
} else if (toIndex === undefined) {
106-
/* When to is omitted, just pick the single value at the from index */
107-
/* This differs to arr.slice which slices to the end of the array if end is omitted */
108-
return arr.slice(fromIndex, fromIndex + 1)
109-
} else {
110-
if (inclusive) {
111-
return arr.slice(fromIndex, toIndex + 1)
112-
} else {
113-
return arr.slice(fromIndex, toIndex)
114-
}
66+
return fn
67+
}
68+
}
69+
70+
/**
71+
* Find the first value which matches the supplied `find` definition (one or more string or functions).
72+
*/
73+
function getFromIndex (arr, find) {
74+
const fromFns = arrayBack(find).map(convertToFunction);
75+
76+
if (fromFns.length === 0) {
77+
throw new Error('from required')
78+
}
79+
80+
let fromIndex;
81+
for (const fn of fromFns) {
82+
fromIndex = arr.findIndex(fn);
83+
if (fromIndex > -1) {
84+
break
11585
}
116-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
117-
/* End: Zero-based index at which to end extraction. slice() extracts up to but not including end. */
11886
}
87+
88+
return fromIndex
11989
}
12090

12191
class CommandLineArgs {

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import fromTo from './lib/from-to.js'
1+
import { fromTo } from './lib/from-to.js'
22

33
class CommandLineArgs {
44
constructor (args, optionDefinitions) {

lib/from-to.js

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,11 @@ import arrayBack from 'array-back'
1717
* @returns string[]
1818
*/
1919

20-
2120
/* TODO: rename to extractFromTo? Rename `options.remove` to `extract`. */
2221
function fromTo (arr, options = {}) {
23-
let { from, to: toFn, remove } = options
24-
25-
const fromIndex = getFromIndex(arr, from)
22+
const fromIndex = getFromIndex(arr, options.from)
2623

27-
toFn = arrayBack(toFn).map(convertToFunction)
24+
const toFn = arrayBack(options.to).map(convertToFunction)
2825
let toIndex = -1
2926
if (toFn.length) {
3027
for (const fn of toFn) {
@@ -61,11 +58,16 @@ function fromTo (arr, options = {}) {
6158
function convertToFunction (fn) {
6259
if (typeof fn === 'string') {
6360
return function (val) { return val === fn }
61+
} else if (fn instanceof RegExp) {
62+
return function (val) { return fn.test(val) }
6463
} else {
6564
return fn
6665
}
6766
}
6867

68+
/**
69+
* Find the first value which matches the supplied `find` definition (one or more string or functions).
70+
*/
6971
function getFromIndex (arr, find) {
7072
const fromFns = arrayBack(find).map(convertToFunction)
7173

@@ -84,14 +86,28 @@ function getFromIndex (arr, find) {
8486
return fromIndex
8587
}
8688

89+
/**
90+
* Return a single item from an array, optionally removing it from the input.
91+
*/
8792
function single (arr, item, options = {}) {
8893
const fromIndex = getFromIndex(arr, item)
8994

95+
const output = arr.slice(fromIndex, fromIndex + 1)
96+
if (options.remove && fromIndex > -1) {
97+
arr.splice(fromIndex, 1)
98+
}
99+
return output
100+
}
101+
102+
/**
103+
* Return a single item by index, optionally removing it from the input.
104+
*/
105+
function positional (arr, fromIndex, options = {}) {
90106
const output = arr.slice(fromIndex, fromIndex + 1)
91107
if (options.remove) {
92108
arr.splice(fromIndex, 1)
93109
}
94110
return output
95111
}
96112

97-
export { fromTo, single }
113+
export { fromTo, single, positional }

lib/option-definition.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,8 @@ class OptionDefinition {
22
name
33
from
44
to
5-
6-
/**
7-
* An additional alternative, or replacement, for `to`. Might result in easier code, e.g. "no further than a --option", rather than "stop here if the next item is an option or the end". This is also how slice() works: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
8-
*/
9-
noFurtherThan
5+
single
106
type
11-
def
127
}
138

149
export default OptionDefinition

0 commit comments

Comments
 (0)