Skip to content

Commit 18681b2

Browse files
committed
from-to rewrite
1 parent f10f0a5 commit 18681b2

File tree

8 files changed

+380
-86
lines changed

8 files changed

+380
-86
lines changed

.github/workflows/node.js.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
1-
# See: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
1+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
22

33
name: Node.js CI
44

55
on:
66
push:
7-
branches: [ master ]
7+
branches: [ master, next ]
88
pull_request:
99
branches: [ master ]
1010

1111
jobs:
1212
build:
1313

14-
runs-on: ubuntu-latest
14+
runs-on: ${{ matrix.os }}
1515

1616
strategy:
1717
matrix:
18-
node-version: [12, 14, 16, 18, 20, 22]
18+
os: [ubuntu-latest]
19+
node-version: [12, 14, 16, 18, 20, 22, 23]
1920

2021
steps:
2122
- uses: actions/checkout@v4
@@ -25,5 +26,5 @@ jobs:
2526
node-version: ${{ matrix.node-version }}
2627
cache: 'npm'
2728
- run: npm install
28-
- name: Run tests
29-
run: npm run test:ci
29+
- run: npm i @75lb/nature
30+
- run: npm run test:ci

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2014-24 Lloyd Brookes <75pound@gmail.com>
3+
Copyright (c) 2014-24 Lloyd Brookes <opensource@75lb.com>
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

dist/index.cjs

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
var arrayBack = require('array-back');
4+
35
/**
46
* Similar to find-replace with two exceptions:
57
* - fromTo finds multiple items, find-replace finds single items
@@ -9,56 +11,105 @@
911
* - Find one or more items and return (all return values are arrays)
1012
* - Find one or more items, return them, remove them from the input array
1113
*
14+
* arr {string[]} - Input array. Only mutated if `options.remove` is set.
1215
* [options.rtol] {boolean} - Enable right-to-left scans. Either that or pass in a custom iterator.
1316
* [options.remove] {boolean} - Remove from source array
14-
* [options.from] {boolean}
15-
* [options.to] {boolean}
17+
* [options.inclusive] {boolean} - If `true` includes the to item.
18+
* [options.from] {function}
19+
* [options.to] {function}
20+
* [options.noFurtherThan] {function}
1621
* @returns string[]
1722
*/
1823
function fromTo (arr, options = {}) {
19-
const { from: fromFn, to: toFn, noFurtherThan, remove } = options;
20-
const fromIndex = arr.findIndex(fromFn);
24+
let { from: fromFn, to: toFn, noFurtherThan, remove, inclusive, toEnd } = options;
25+
if (inclusive === undefined && !noFurtherThan && toFn) {
26+
inclusive = true;
27+
}
28+
toFn = toFn || noFurtherThan;
29+
fromFn = arrayBack(fromFn).map(fn => {
30+
if (typeof fn === 'string') {
31+
return function (val) { return val === fn }
32+
} else {
33+
return fn
34+
}
35+
});
36+
toFn = arrayBack(toFn).map(fn => {
37+
if (typeof fn === 'string') {
38+
return function (item, index, arr, valueIndex) { return item === fn }
39+
} else {
40+
return fn
41+
}
42+
});
43+
44+
let fromIndex;
45+
for (const fn of fromFn) {
46+
fromIndex = arr.findIndex(fn);
47+
if (fromIndex > -1) {
48+
break
49+
}
50+
}
51+
2152
let toIndex;
2253
if (toFn) {
23-
toIndex = arr.findIndex((item, index, arr) => {
24-
if (index > fromIndex) {
25-
const valueIndex = index - fromIndex;
26-
return toFn(valueIndex, item, index, arr)
27-
} else {
28-
return false
29-
}
30-
});
31-
} else if (noFurtherThan) {
32-
toIndex = arr.findIndex((item, index, arr) => {
33-
if (index > fromIndex) {
34-
const valueIndex = index - fromIndex;
35-
return noFurtherThan(valueIndex, item, index, arr)
36-
} else {
37-
return false
54+
for (const fn of toFn) {
55+
toIndex = arr.findIndex((item, index, arr) => {
56+
if (index > fromIndex) {
57+
const valueIndex = index - fromIndex;
58+
return fn(item, index, arr, valueIndex)
59+
} else {
60+
return false
61+
}
62+
});
63+
if (toIndex > -1) {
64+
break
3865
}
39-
});
40-
if (toIndex > 0) {
41-
toIndex -= 1;
42-
} else if (toIndex === -1) {
43-
toIndex = arr.length - 1;
4466
}
45-
} else {
46-
toIndex = fromIndex;
4767
}
68+
4869
if (remove) {
49-
return arr.splice(fromIndex, toIndex === -1 ? 1 : toIndex - fromIndex + 1)
70+
let deleteCount;
71+
if (toEnd) {
72+
deleteCount = arr.length;
73+
}
74+
if (toIndex === -1) {
75+
/* 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` */
76+
deleteCount = arr.length;
77+
} else if (toIndex === undefined) {
78+
/* When to is omitted, just pick the single value at the from index */
79+
/* This differs to arr.slice which slices to the end of the array if end is omitted */
80+
deleteCount = 1;
81+
} else {
82+
if (inclusive) {
83+
deleteCount = toIndex - fromIndex;
84+
} else {
85+
deleteCount = toIndex - fromIndex - 1;
86+
}
87+
}
88+
return arr.splice(fromIndex, deleteCount)
89+
/* deleteCount: An integer indicating the number of elements in the array to remove from start. */
90+
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice */
5091
} else {
51-
// return arr.slice(fromIndex, toIndex + 1)
92+
if (toEnd) {
93+
toIndex = arr.length + 1;
94+
}
95+
if (toIndex === -1) {
96+
return arr.slice(fromIndex)
97+
} else if (toIndex === undefined) {
98+
/* When to is omitted, just pick the single value at the from index */
99+
/* This differs to arr.slice which slices to the end of the array if end is omitted */
100+
return arr.slice(fromIndex, fromIndex + 1)
101+
} else {
102+
if (inclusive) {
103+
return arr.slice(fromIndex, toIndex + 1)
104+
} else {
105+
return arr.slice(fromIndex, toIndex)
106+
}
107+
}
52108
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
53-
return arr.slice(fromIndex, toIndex === -1 ? 1 : toIndex - fromIndex + 1)
109+
/* End: Zero-based index at which to end extraction. slice() extracts up to but not including end. */
54110
}
55111
}
56112

57-
/*
58-
TODO: add `noFurtherThan` function as 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
59-
60-
*/
61-
62113
class CommandLineArgs {
63114
constructor (args, optionDefinitions) {
64115
this.origArgv = args.slice();

lib/from-to.js

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import arrayBack from 'array-back'
2+
13
/**
24
* Similar to find-replace with two exceptions:
35
* - fromTo finds multiple items, find-replace finds single items
@@ -7,48 +9,102 @@
79
* - Find one or more items and return (all return values are arrays)
810
* - Find one or more items, return them, remove them from the input array
911
*
12+
* arr {string[]} - Input array. Only mutated if `options.remove` is set.
1013
* [options.rtol] {boolean} - Enable right-to-left scans. Either that or pass in a custom iterator.
1114
* [options.remove] {boolean} - Remove from source array
12-
* [options.from] {boolean}
13-
* [options.to] {boolean}
15+
* [options.inclusive] {boolean} - If `true` includes the to item.
16+
* [options.from] {function}
17+
* [options.to] {function}
18+
* [options.noFurtherThan] {function}
1419
* @returns string[]
1520
*/
1621
function fromTo (arr, options = {}) {
17-
const { from: fromFn, to: toFn, noFurtherThan, remove } = options
18-
const fromIndex = arr.findIndex(fromFn)
22+
let { from: fromFn, to: toFn, noFurtherThan, remove, inclusive, toEnd } = options
23+
if (inclusive === undefined && !noFurtherThan && toFn) {
24+
inclusive = true
25+
}
26+
toFn = toFn || noFurtherThan
27+
fromFn = arrayBack(fromFn).map(fn => {
28+
if (typeof fn === 'string') {
29+
return function (val) { return val === fn }
30+
} else {
31+
return fn
32+
}
33+
})
34+
toFn = arrayBack(toFn).map(fn => {
35+
if (typeof fn === 'string') {
36+
return function (item, index, arr, valueIndex) { return item === fn }
37+
} else {
38+
return fn
39+
}
40+
})
41+
42+
let fromIndex
43+
for (const fn of fromFn) {
44+
fromIndex = arr.findIndex(fn)
45+
if (fromIndex > -1) {
46+
break
47+
}
48+
}
49+
1950
let toIndex
2051
if (toFn) {
21-
toIndex = arr.findIndex((item, index, arr) => {
22-
if (index > fromIndex) {
23-
const valueIndex = index - fromIndex
24-
return toFn(valueIndex, item, index, arr)
25-
} else {
26-
return false
27-
}
28-
})
29-
} else if (noFurtherThan) {
30-
toIndex = arr.findIndex((item, index, arr) => {
31-
if (index > fromIndex) {
32-
const valueIndex = index - fromIndex
33-
return noFurtherThan(valueIndex, item, index, arr)
34-
} else {
35-
return false
52+
for (const fn of toFn) {
53+
toIndex = arr.findIndex((item, index, arr) => {
54+
if (index > fromIndex) {
55+
const valueIndex = index - fromIndex
56+
return fn(item, index, arr, valueIndex)
57+
} else {
58+
return false
59+
}
60+
})
61+
if (toIndex > -1) {
62+
break
3663
}
37-
})
38-
if (toIndex > 0) {
39-
toIndex -= 1
40-
} else if (toIndex === -1) {
41-
toIndex = arr.length - 1
4264
}
43-
} else {
44-
toIndex = fromIndex
4565
}
66+
4667
if (remove) {
47-
return arr.splice(fromIndex, toIndex === -1 ? 1 : toIndex - fromIndex + 1)
68+
let deleteCount
69+
if (toEnd) {
70+
deleteCount = arr.length
71+
}
72+
if (toIndex === -1) {
73+
/* 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` */
74+
deleteCount = arr.length
75+
} else if (toIndex === undefined) {
76+
/* When to is omitted, just pick the single value at the from index */
77+
/* This differs to arr.slice which slices to the end of the array if end is omitted */
78+
deleteCount = 1
79+
} else {
80+
if (inclusive) {
81+
deleteCount = toIndex - fromIndex
82+
} else {
83+
deleteCount = toIndex - fromIndex - 1
84+
}
85+
}
86+
return arr.splice(fromIndex, deleteCount)
87+
/* deleteCount: An integer indicating the number of elements in the array to remove from start. */
88+
/* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice */
4889
} else {
49-
// return arr.slice(fromIndex, toIndex + 1)
90+
if (toEnd) {
91+
toIndex = arr.length + 1
92+
}
93+
if (toIndex === -1) {
94+
return arr.slice(fromIndex)
95+
} else if (toIndex === undefined) {
96+
/* When to is omitted, just pick the single value at the from index */
97+
/* This differs to arr.slice which slices to the end of the array if end is omitted */
98+
return arr.slice(fromIndex, fromIndex + 1)
99+
} else {
100+
if (inclusive) {
101+
return arr.slice(fromIndex, toIndex + 1)
102+
} else {
103+
return arr.slice(fromIndex, toIndex)
104+
}
105+
}
50106
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
51-
return arr.slice(fromIndex, toIndex === -1 ? 1 : toIndex - fromIndex + 1)
107+
/* End: Zero-based index at which to end extraction. slice() extracts up to but not including end. */
52108
}
53109
}
54110

0 commit comments

Comments
 (0)