string-match-left-right 8.0.5 → 8.0.6
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name string-match-left-right
|
|
3
3
|
* @fileoverview Match substrings on the left or right of a given index, ignoring whitespace
|
|
4
|
-
* @version 8.0.
|
|
4
|
+
* @version 8.0.6
|
|
5
5
|
* @author Roy Revelt, Codsen Ltd
|
|
6
6
|
* @license MIT
|
|
7
7
|
* {@link https://codsen.com/os/string-match-left-right/}
|
|
@@ -10,296 +10,374 @@
|
|
|
10
10
|
import { arrayiffy } from 'arrayiffy-if-string';
|
|
11
11
|
|
|
12
12
|
function isObj(something) {
|
|
13
|
-
|
|
13
|
+
return (something && typeof something === "object" && !Array.isArray(something));
|
|
14
14
|
}
|
|
15
15
|
function isStr(something) {
|
|
16
|
-
|
|
16
|
+
return typeof something === "string";
|
|
17
17
|
}
|
|
18
18
|
const defaults = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
cb: undefined,
|
|
20
|
+
i: false,
|
|
21
|
+
trimBeforeMatching: false,
|
|
22
|
+
trimCharsBeforeMatching: [],
|
|
23
|
+
maxMismatches: 0,
|
|
24
|
+
firstMustMatch: false,
|
|
25
|
+
lastMustMatch: false,
|
|
26
|
+
hungry: false,
|
|
27
27
|
};
|
|
28
|
-
const defaultGetNextIdx = index => index + 1;
|
|
28
|
+
const defaultGetNextIdx = (index) => index + 1;
|
|
29
29
|
function march(str, position, whatToMatchVal, originalOpts, special = false, getNextIdx = defaultGetNextIdx) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
const opts = { ...defaults,
|
|
35
|
-
...originalOpts
|
|
36
|
-
};
|
|
37
|
-
if (position >= str.length && !special) {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
let charsToCheckCount = special ? 1 : whatToMatchVal.length;
|
|
41
|
-
let charsMatchedTotal = 0;
|
|
42
|
-
let patienceReducedBeforeFirstMatch = false;
|
|
43
|
-
let lastWasMismatched = false;
|
|
44
|
-
let atLeastSomethingWasMatched = false;
|
|
45
|
-
let patience = opts.maxMismatches;
|
|
46
|
-
let i = position;
|
|
47
|
-
let somethingFound = false;
|
|
48
|
-
let firstCharacterMatched = false;
|
|
49
|
-
let lastCharacterMatched = false;
|
|
50
|
-
function whitespaceInFrontOfFirstChar() {
|
|
51
|
-
return (
|
|
52
|
-
charsMatchedTotal === 1 &&
|
|
53
|
-
patience < opts.maxMismatches - 1
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
while (str[i]) {
|
|
57
|
-
const nextIdx = getNextIdx(i);
|
|
58
|
-
if (opts.trimBeforeMatching && str[i].trim() === "") {
|
|
59
|
-
if (!str[nextIdx] && special && whatToMatchVal === "EOL") {
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
i = getNextIdx(i);
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (opts && !opts.i && opts.trimCharsBeforeMatching && opts.trimCharsBeforeMatching.includes(str[i]) || opts && opts.i && opts.trimCharsBeforeMatching && opts.trimCharsBeforeMatching.map(val => val.toLowerCase()).includes(str[i].toLowerCase())) {
|
|
66
|
-
if (special && whatToMatchVal === "EOL" && !str[nextIdx]) {
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
i = getNextIdx(i);
|
|
70
|
-
continue;
|
|
30
|
+
const whatToMatchValVal = typeof whatToMatchVal === "function" ? whatToMatchVal() : whatToMatchVal;
|
|
31
|
+
if (+position < 0 && special && whatToMatchValVal === "EOL") {
|
|
32
|
+
return whatToMatchValVal;
|
|
71
33
|
}
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
if (!somethingFound) {
|
|
75
|
-
somethingFound = true;
|
|
76
|
-
}
|
|
77
|
-
if (!atLeastSomethingWasMatched) {
|
|
78
|
-
atLeastSomethingWasMatched = true;
|
|
79
|
-
}
|
|
80
|
-
if (charsToCheckCount === whatToMatchVal.length) {
|
|
81
|
-
firstCharacterMatched = true;
|
|
82
|
-
if (patience !== opts.maxMismatches) {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
} else if (charsToCheckCount === 1) {
|
|
86
|
-
lastCharacterMatched = true;
|
|
87
|
-
}
|
|
88
|
-
charsToCheckCount -= 1;
|
|
89
|
-
charsMatchedTotal++;
|
|
90
|
-
if (whitespaceInFrontOfFirstChar()) {
|
|
34
|
+
const opts = { ...defaults, ...originalOpts };
|
|
35
|
+
if (position >= str.length && !special) {
|
|
91
36
|
return false;
|
|
92
|
-
|
|
93
|
-
|
|
37
|
+
}
|
|
38
|
+
let charsToCheckCount = special ? 1 : whatToMatchVal.length;
|
|
39
|
+
let charsMatchedTotal = 0;
|
|
40
|
+
let patienceReducedBeforeFirstMatch = false;
|
|
41
|
+
let lastWasMismatched = false;
|
|
42
|
+
let atLeastSomethingWasMatched = false;
|
|
43
|
+
let patience = opts.maxMismatches;
|
|
44
|
+
let i = position;
|
|
45
|
+
let somethingFound = false;
|
|
46
|
+
let firstCharacterMatched = false;
|
|
47
|
+
let lastCharacterMatched = false;
|
|
48
|
+
function whitespaceInFrontOfFirstChar() {
|
|
94
49
|
return (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
50
|
+
charsMatchedTotal === 1 &&
|
|
51
|
+
patience < opts.maxMismatches - 1);
|
|
52
|
+
}
|
|
53
|
+
while (str[i]) {
|
|
54
|
+
const nextIdx = getNextIdx(i);
|
|
55
|
+
if (opts.trimBeforeMatching && str[i].trim() === "") {
|
|
56
|
+
if (!str[nextIdx] && special && whatToMatchVal === "EOL") {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
i = getNextIdx(i);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if ((opts &&
|
|
63
|
+
!opts.i &&
|
|
64
|
+
opts.trimCharsBeforeMatching &&
|
|
65
|
+
opts.trimCharsBeforeMatching.includes(str[i])) ||
|
|
66
|
+
(opts &&
|
|
67
|
+
opts.i &&
|
|
68
|
+
opts.trimCharsBeforeMatching &&
|
|
69
|
+
opts.trimCharsBeforeMatching
|
|
70
|
+
.map((val) => val.toLowerCase())
|
|
71
|
+
.includes(str[i].toLowerCase()))) {
|
|
72
|
+
if (special && whatToMatchVal === "EOL" && !str[nextIdx]) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
i = getNextIdx(i);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
const charToCompareAgainst = nextIdx > i
|
|
79
|
+
? whatToMatchVal[whatToMatchVal.length - charsToCheckCount]
|
|
80
|
+
: whatToMatchVal[charsToCheckCount - 1];
|
|
81
|
+
if ((!opts.i && str[i] === charToCompareAgainst) ||
|
|
82
|
+
(opts.i && str[i].toLowerCase() === charToCompareAgainst.toLowerCase())) {
|
|
83
|
+
if (!somethingFound) {
|
|
84
|
+
somethingFound = true;
|
|
85
|
+
}
|
|
86
|
+
if (!atLeastSomethingWasMatched) {
|
|
87
|
+
atLeastSomethingWasMatched = true;
|
|
88
|
+
}
|
|
89
|
+
if (charsToCheckCount === whatToMatchVal.length) {
|
|
90
|
+
firstCharacterMatched = true;
|
|
91
|
+
if (patience !== opts.maxMismatches) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (charsToCheckCount === 1) {
|
|
96
|
+
lastCharacterMatched = true;
|
|
97
|
+
}
|
|
98
|
+
charsToCheckCount -= 1;
|
|
111
99
|
charsMatchedTotal++;
|
|
112
100
|
if (whitespaceInFrontOfFirstChar()) {
|
|
113
|
-
|
|
101
|
+
return false;
|
|
114
102
|
}
|
|
115
|
-
charsToCheckCount
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
103
|
+
if (!charsToCheckCount) {
|
|
104
|
+
return (
|
|
105
|
+
charsMatchedTotal !== whatToMatchVal.length ||
|
|
106
|
+
patience === opts.maxMismatches ||
|
|
107
|
+
!patienceReducedBeforeFirstMatch
|
|
108
|
+
? i
|
|
109
|
+
: false);
|
|
122
110
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
if (!patienceReducedBeforeFirstMatch && !charsMatchedTotal) {
|
|
114
|
+
patienceReducedBeforeFirstMatch = true;
|
|
115
|
+
}
|
|
116
|
+
if (opts.maxMismatches && patience && i) {
|
|
117
|
+
patience -= 1;
|
|
118
|
+
for (let y = 0; y <= patience; y++) {
|
|
119
|
+
const nextCharToCompareAgainst = nextIdx > i
|
|
120
|
+
? whatToMatchVal[whatToMatchVal.length - charsToCheckCount + 1 + y]
|
|
121
|
+
: whatToMatchVal[charsToCheckCount - 2 - y];
|
|
122
|
+
const nextCharInSource = str[getNextIdx(i)];
|
|
123
|
+
if (nextCharToCompareAgainst &&
|
|
124
|
+
((!opts.i && str[i] === nextCharToCompareAgainst) ||
|
|
125
|
+
(opts.i &&
|
|
126
|
+
str[i].toLowerCase() ===
|
|
127
|
+
nextCharToCompareAgainst.toLowerCase())) &&
|
|
128
|
+
(!opts.firstMustMatch ||
|
|
129
|
+
charsToCheckCount !== whatToMatchVal.length)) {
|
|
130
|
+
charsMatchedTotal++;
|
|
131
|
+
if (whitespaceInFrontOfFirstChar()) {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
charsToCheckCount -= 2;
|
|
135
|
+
somethingFound = true;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
else if (nextCharInSource &&
|
|
139
|
+
nextCharToCompareAgainst &&
|
|
140
|
+
((!opts.i && nextCharInSource === nextCharToCompareAgainst) ||
|
|
141
|
+
(opts.i &&
|
|
142
|
+
nextCharInSource.toLowerCase() ===
|
|
143
|
+
nextCharToCompareAgainst.toLowerCase())) &&
|
|
144
|
+
(!opts.firstMustMatch ||
|
|
145
|
+
charsToCheckCount !== whatToMatchVal.length)) {
|
|
146
|
+
if (!charsMatchedTotal && !opts.hungry) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
charsToCheckCount -= 1;
|
|
150
|
+
somethingFound = true;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
else if (nextCharToCompareAgainst === undefined &&
|
|
154
|
+
patience >= 0 &&
|
|
155
|
+
somethingFound &&
|
|
156
|
+
(!opts.firstMustMatch || firstCharacterMatched) &&
|
|
157
|
+
(!opts.lastMustMatch || lastCharacterMatched)) {
|
|
158
|
+
return i;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!somethingFound) {
|
|
162
|
+
lastWasMismatched = i;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (i === 0 &&
|
|
166
|
+
charsToCheckCount === 1 &&
|
|
167
|
+
!opts.lastMustMatch &&
|
|
168
|
+
atLeastSomethingWasMatched) {
|
|
169
|
+
return 0;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (lastWasMismatched !== false && lastWasMismatched !== i) {
|
|
176
|
+
lastWasMismatched = false;
|
|
177
|
+
}
|
|
178
|
+
if (charsToCheckCount < 1) {
|
|
127
179
|
return i;
|
|
128
|
-
}
|
|
129
180
|
}
|
|
130
|
-
|
|
131
|
-
|
|
181
|
+
i = getNextIdx(i);
|
|
182
|
+
}
|
|
183
|
+
if (charsToCheckCount > 0) {
|
|
184
|
+
if (special && whatToMatchValVal === "EOL") {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
if (opts &&
|
|
188
|
+
opts.maxMismatches >= charsToCheckCount &&
|
|
189
|
+
atLeastSomethingWasMatched) {
|
|
190
|
+
return lastWasMismatched || 0;
|
|
132
191
|
}
|
|
133
|
-
} else if (i === 0 && charsToCheckCount === 1 && !opts.lastMustMatch && atLeastSomethingWasMatched) {
|
|
134
|
-
return 0;
|
|
135
|
-
} else {
|
|
136
192
|
return false;
|
|
137
|
-
}
|
|
138
193
|
}
|
|
139
|
-
|
|
140
|
-
|
|
194
|
+
}
|
|
195
|
+
function main(mode, str, position, originalWhatToMatch, originalOpts) {
|
|
196
|
+
if (isObj(originalOpts) &&
|
|
197
|
+
Object.prototype.hasOwnProperty.call(originalOpts, "trimBeforeMatching") &&
|
|
198
|
+
typeof originalOpts.trimBeforeMatching !== "boolean") {
|
|
199
|
+
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_09] opts.trimBeforeMatching should be boolean!${Array.isArray(originalOpts.trimBeforeMatching)
|
|
200
|
+
? ` Did you mean to use opts.trimCharsBeforeMatching?`
|
|
201
|
+
: ""}`);
|
|
141
202
|
}
|
|
142
|
-
|
|
143
|
-
|
|
203
|
+
const opts = { ...defaults, ...originalOpts };
|
|
204
|
+
if (typeof opts.trimCharsBeforeMatching === "string") {
|
|
205
|
+
opts.trimCharsBeforeMatching = arrayiffy(opts.trimCharsBeforeMatching);
|
|
144
206
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (special && whatToMatchValVal === "EOL") {
|
|
149
|
-
return true;
|
|
207
|
+
opts.trimCharsBeforeMatching = opts.trimCharsBeforeMatching.map((el) => (isStr(el) ? el : String(el)));
|
|
208
|
+
if (!isStr(str)) {
|
|
209
|
+
return false;
|
|
150
210
|
}
|
|
151
|
-
if (
|
|
152
|
-
|
|
211
|
+
if (!str.length) {
|
|
212
|
+
return false;
|
|
153
213
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
function main(mode, str, position, originalWhatToMatch, originalOpts) {
|
|
158
|
-
if (isObj(originalOpts) && Object.prototype.hasOwnProperty.call(originalOpts, "trimBeforeMatching") && typeof originalOpts.trimBeforeMatching !== "boolean") {
|
|
159
|
-
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_09] opts.trimBeforeMatching should be boolean!${Array.isArray(originalOpts.trimBeforeMatching) ? ` Did you mean to use opts.trimCharsBeforeMatching?` : ""}`);
|
|
160
|
-
}
|
|
161
|
-
const opts = { ...defaults,
|
|
162
|
-
...originalOpts
|
|
163
|
-
};
|
|
164
|
-
if (typeof opts.trimCharsBeforeMatching === "string") {
|
|
165
|
-
opts.trimCharsBeforeMatching = arrayiffy(opts.trimCharsBeforeMatching);
|
|
166
|
-
}
|
|
167
|
-
opts.trimCharsBeforeMatching = opts.trimCharsBeforeMatching.map(el => isStr(el) ? el : String(el));
|
|
168
|
-
if (!isStr(str)) {
|
|
169
|
-
return false;
|
|
170
|
-
}
|
|
171
|
-
if (!str.length) {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
if (!Number.isInteger(position) || position < 0) {
|
|
175
|
-
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_03] the second argument should be a natural number. Currently it's of a type: ${typeof position}, equal to:\n${JSON.stringify(position, null, 4)}`);
|
|
176
|
-
}
|
|
177
|
-
let whatToMatch;
|
|
178
|
-
let special;
|
|
179
|
-
if (isStr(originalWhatToMatch)) {
|
|
180
|
-
whatToMatch = [originalWhatToMatch];
|
|
181
|
-
} else if (Array.isArray(originalWhatToMatch)) {
|
|
182
|
-
whatToMatch = originalWhatToMatch;
|
|
183
|
-
} else if (!originalWhatToMatch) {
|
|
184
|
-
whatToMatch = originalWhatToMatch;
|
|
185
|
-
} else if (typeof originalWhatToMatch === "function") {
|
|
186
|
-
whatToMatch = [];
|
|
187
|
-
whatToMatch.push(originalWhatToMatch);
|
|
188
|
-
} else {
|
|
189
|
-
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_05] the third argument, whatToMatch, is neither string nor array of strings! It's ${typeof originalWhatToMatch}, equal to:\n${JSON.stringify(originalWhatToMatch, null, 4)}`);
|
|
190
|
-
}
|
|
191
|
-
if (originalOpts && !isObj(originalOpts)) {
|
|
192
|
-
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_06] the fourth argument, options object, should be a plain object. Currently it's of a type "${typeof originalOpts}", and equal to:\n${JSON.stringify(originalOpts, null, 4)}`);
|
|
193
|
-
}
|
|
194
|
-
let culpritsIndex = 0;
|
|
195
|
-
let culpritsVal = "";
|
|
196
|
-
if (opts && opts.trimCharsBeforeMatching && opts.trimCharsBeforeMatching.some((el, i) => {
|
|
197
|
-
if (el.length > 1) {
|
|
198
|
-
culpritsIndex = i;
|
|
199
|
-
culpritsVal = el;
|
|
200
|
-
return true;
|
|
214
|
+
if (!Number.isInteger(position) || position < 0) {
|
|
215
|
+
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_03] the second argument should be a natural number. Currently it's of a type: ${typeof position}, equal to:\n${JSON.stringify(position, null, 4)}`);
|
|
201
216
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (!whatToMatch || !Array.isArray(whatToMatch) ||
|
|
207
|
-
Array.isArray(whatToMatch) && !whatToMatch.length ||
|
|
208
|
-
Array.isArray(whatToMatch) && whatToMatch.length === 1 && isStr(whatToMatch[0]) && !whatToMatch[0].trim()
|
|
209
|
-
) {
|
|
210
|
-
if (typeof opts.cb === "function") {
|
|
211
|
-
let firstCharOutsideIndex;
|
|
212
|
-
let startingPosition = position;
|
|
213
|
-
if (mode === "matchLeftIncl" || mode === "matchRight") {
|
|
214
|
-
startingPosition += 1;
|
|
215
|
-
}
|
|
216
|
-
if (mode[5] === "L") {
|
|
217
|
-
for (let y = startingPosition; y--;) {
|
|
218
|
-
const currentChar = str[y];
|
|
219
|
-
if ((!opts.trimBeforeMatching || opts.trimBeforeMatching && currentChar !== undefined && currentChar.trim()) && (!opts.trimCharsBeforeMatching || !opts.trimCharsBeforeMatching.length || currentChar !== undefined && !opts.trimCharsBeforeMatching.includes(currentChar))) {
|
|
220
|
-
firstCharOutsideIndex = y;
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
} else if (mode.startsWith("matchRight")) {
|
|
225
|
-
for (let y = startingPosition; y < str.length; y++) {
|
|
226
|
-
const currentChar = str[y];
|
|
227
|
-
if ((!opts.trimBeforeMatching || opts.trimBeforeMatching && currentChar.trim()) && (!opts.trimCharsBeforeMatching || !opts.trimCharsBeforeMatching.length || !opts.trimCharsBeforeMatching.includes(currentChar))) {
|
|
228
|
-
firstCharOutsideIndex = y;
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
if (firstCharOutsideIndex === undefined) {
|
|
234
|
-
return false;
|
|
235
|
-
}
|
|
236
|
-
const wholeCharacterOutside = str[firstCharOutsideIndex];
|
|
237
|
-
const indexOfTheCharacterAfter = firstCharOutsideIndex + 1;
|
|
238
|
-
let theRemainderOfTheString = "";
|
|
239
|
-
if (indexOfTheCharacterAfter && indexOfTheCharacterAfter > 0) {
|
|
240
|
-
theRemainderOfTheString = str.slice(0, indexOfTheCharacterAfter);
|
|
241
|
-
}
|
|
242
|
-
if (mode[5] === "L") {
|
|
243
|
-
return opts.cb(wholeCharacterOutside, theRemainderOfTheString, firstCharOutsideIndex);
|
|
244
|
-
}
|
|
245
|
-
if (firstCharOutsideIndex && firstCharOutsideIndex > 0) {
|
|
246
|
-
theRemainderOfTheString = str.slice(firstCharOutsideIndex);
|
|
247
|
-
}
|
|
248
|
-
return opts.cb(wholeCharacterOutside, theRemainderOfTheString, firstCharOutsideIndex);
|
|
217
|
+
let whatToMatch;
|
|
218
|
+
let special;
|
|
219
|
+
if (isStr(originalWhatToMatch)) {
|
|
220
|
+
whatToMatch = [originalWhatToMatch];
|
|
249
221
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
extraNote = " More so, the whole options object, the fourth input argument, is missing!";
|
|
222
|
+
else if (Array.isArray(originalWhatToMatch)) {
|
|
223
|
+
whatToMatch = originalWhatToMatch;
|
|
253
224
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
for (let i = 0, len = whatToMatch.length; i < len; i++) {
|
|
257
|
-
special = typeof whatToMatch[i] === "function";
|
|
258
|
-
const whatToMatchVal = whatToMatch[i];
|
|
259
|
-
let fullCharacterInFront;
|
|
260
|
-
let indexOfTheCharacterInFront;
|
|
261
|
-
let restOfStringInFront = "";
|
|
262
|
-
let startingPosition = position;
|
|
263
|
-
if (mode === "matchRight") {
|
|
264
|
-
startingPosition += 1;
|
|
265
|
-
} else if (mode === "matchLeft") {
|
|
266
|
-
startingPosition -= 1;
|
|
225
|
+
else if (!originalWhatToMatch) {
|
|
226
|
+
whatToMatch = originalWhatToMatch;
|
|
267
227
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
228
|
+
else if (typeof originalWhatToMatch === "function") {
|
|
229
|
+
whatToMatch = [];
|
|
230
|
+
whatToMatch.push(originalWhatToMatch);
|
|
271
231
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (mode[5] === "L") {
|
|
275
|
-
restOfStringInFront = str.slice(0, found);
|
|
276
|
-
} else {
|
|
277
|
-
restOfStringInFront = str.slice(indexOfTheCharacterInFront);
|
|
278
|
-
}
|
|
232
|
+
else {
|
|
233
|
+
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_05] the third argument, whatToMatch, is neither string nor array of strings! It's ${typeof originalWhatToMatch}, equal to:\n${JSON.stringify(originalWhatToMatch, null, 4)}`);
|
|
279
234
|
}
|
|
280
|
-
if (
|
|
281
|
-
|
|
235
|
+
if (originalOpts && !isObj(originalOpts)) {
|
|
236
|
+
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_06] the fourth argument, options object, should be a plain object. Currently it's of a type "${typeof originalOpts}", and equal to:\n${JSON.stringify(originalOpts, null, 4)}`);
|
|
282
237
|
}
|
|
283
|
-
|
|
284
|
-
|
|
238
|
+
let culpritsIndex = 0;
|
|
239
|
+
let culpritsVal = "";
|
|
240
|
+
if (opts &&
|
|
241
|
+
opts.trimCharsBeforeMatching &&
|
|
242
|
+
opts.trimCharsBeforeMatching.some((el, i) => {
|
|
243
|
+
if (el.length > 1) {
|
|
244
|
+
culpritsIndex = i;
|
|
245
|
+
culpritsVal = el;
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
})) {
|
|
250
|
+
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_07] the fourth argument, options object contains trimCharsBeforeMatching. It was meant to list the single characters but one of the entries at index ${culpritsIndex} is longer than 1 character, ${culpritsVal.length} (equals to ${culpritsVal}). Please split it into separate characters and put into array as separate elements.`);
|
|
285
251
|
}
|
|
286
|
-
if (
|
|
287
|
-
|
|
252
|
+
if (!whatToMatch ||
|
|
253
|
+
!Array.isArray(whatToMatch) ||
|
|
254
|
+
(Array.isArray(whatToMatch) && !whatToMatch.length) ||
|
|
255
|
+
(Array.isArray(whatToMatch) &&
|
|
256
|
+
whatToMatch.length === 1 &&
|
|
257
|
+
isStr(whatToMatch[0]) &&
|
|
258
|
+
!whatToMatch[0].trim())
|
|
259
|
+
) {
|
|
260
|
+
if (typeof opts.cb === "function") {
|
|
261
|
+
let firstCharOutsideIndex;
|
|
262
|
+
let startingPosition = position;
|
|
263
|
+
if (mode === "matchLeftIncl" || mode === "matchRight") {
|
|
264
|
+
startingPosition += 1;
|
|
265
|
+
}
|
|
266
|
+
if (mode[5] === "L") {
|
|
267
|
+
for (let y = startingPosition; y--;) {
|
|
268
|
+
const currentChar = str[y];
|
|
269
|
+
if ((!opts.trimBeforeMatching ||
|
|
270
|
+
(opts.trimBeforeMatching &&
|
|
271
|
+
currentChar !== undefined &&
|
|
272
|
+
currentChar.trim())) &&
|
|
273
|
+
(!opts.trimCharsBeforeMatching ||
|
|
274
|
+
!opts.trimCharsBeforeMatching.length ||
|
|
275
|
+
(currentChar !== undefined &&
|
|
276
|
+
!opts.trimCharsBeforeMatching.includes(currentChar)))) {
|
|
277
|
+
firstCharOutsideIndex = y;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else if (mode.startsWith("matchRight")) {
|
|
283
|
+
for (let y = startingPosition; y < str.length; y++) {
|
|
284
|
+
const currentChar = str[y];
|
|
285
|
+
if ((!opts.trimBeforeMatching ||
|
|
286
|
+
(opts.trimBeforeMatching && currentChar.trim())) &&
|
|
287
|
+
(!opts.trimCharsBeforeMatching ||
|
|
288
|
+
!opts.trimCharsBeforeMatching.length ||
|
|
289
|
+
!opts.trimCharsBeforeMatching.includes(currentChar))) {
|
|
290
|
+
firstCharOutsideIndex = y;
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (firstCharOutsideIndex === undefined) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
const wholeCharacterOutside = str[firstCharOutsideIndex];
|
|
299
|
+
const indexOfTheCharacterAfter = firstCharOutsideIndex + 1;
|
|
300
|
+
let theRemainderOfTheString = "";
|
|
301
|
+
if (indexOfTheCharacterAfter && indexOfTheCharacterAfter > 0) {
|
|
302
|
+
theRemainderOfTheString = str.slice(0, indexOfTheCharacterAfter);
|
|
303
|
+
}
|
|
304
|
+
if (mode[5] === "L") {
|
|
305
|
+
return opts.cb(wholeCharacterOutside, theRemainderOfTheString, firstCharOutsideIndex);
|
|
306
|
+
}
|
|
307
|
+
if (firstCharOutsideIndex && firstCharOutsideIndex > 0) {
|
|
308
|
+
theRemainderOfTheString = str.slice(firstCharOutsideIndex);
|
|
309
|
+
}
|
|
310
|
+
return opts.cb(wholeCharacterOutside, theRemainderOfTheString, firstCharOutsideIndex);
|
|
311
|
+
}
|
|
312
|
+
let extraNote = "";
|
|
313
|
+
if (!originalOpts) {
|
|
314
|
+
extraNote =
|
|
315
|
+
" More so, the whole options object, the fourth input argument, is missing!";
|
|
316
|
+
}
|
|
317
|
+
throw new Error(`string-match-left-right/${mode}(): [THROW_ID_08] the third argument, "whatToMatch", was given as an empty string. This means, you intend to match purely by a callback. The callback was not set though, the opts key "cb" is not set!${extraNote}`);
|
|
318
|
+
}
|
|
319
|
+
for (let i = 0, len = whatToMatch.length; i < len; i++) {
|
|
320
|
+
special = typeof whatToMatch[i] === "function";
|
|
321
|
+
const whatToMatchVal = whatToMatch[i];
|
|
322
|
+
let fullCharacterInFront;
|
|
323
|
+
let indexOfTheCharacterInFront;
|
|
324
|
+
let restOfStringInFront = "";
|
|
325
|
+
let startingPosition = position;
|
|
326
|
+
if (mode === "matchRight") {
|
|
327
|
+
startingPosition += 1;
|
|
328
|
+
}
|
|
329
|
+
else if (mode === "matchLeft") {
|
|
330
|
+
startingPosition -= 1;
|
|
331
|
+
}
|
|
332
|
+
const found = march(str, startingPosition, whatToMatchVal, opts, special, (i2) => (mode[5] === "L" ? i2 - 1 : i2 + 1));
|
|
333
|
+
if (found &&
|
|
334
|
+
special &&
|
|
335
|
+
typeof whatToMatchVal === "function" &&
|
|
336
|
+
whatToMatchVal() === "EOL") {
|
|
337
|
+
return whatToMatchVal() &&
|
|
338
|
+
(opts.cb
|
|
339
|
+
? opts.cb(fullCharacterInFront, restOfStringInFront, indexOfTheCharacterInFront)
|
|
340
|
+
: true)
|
|
341
|
+
? whatToMatchVal()
|
|
342
|
+
: false;
|
|
343
|
+
}
|
|
344
|
+
if (Number.isInteger(found)) {
|
|
345
|
+
indexOfTheCharacterInFront = mode.startsWith("matchLeft")
|
|
346
|
+
? found - 1
|
|
347
|
+
: found + 1;
|
|
348
|
+
if (mode[5] === "L") {
|
|
349
|
+
restOfStringInFront = str.slice(0, found);
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
restOfStringInFront = str.slice(indexOfTheCharacterInFront);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (indexOfTheCharacterInFront < 0) {
|
|
356
|
+
indexOfTheCharacterInFront = undefined;
|
|
357
|
+
}
|
|
358
|
+
if (str[indexOfTheCharacterInFront]) {
|
|
359
|
+
fullCharacterInFront = str[indexOfTheCharacterInFront];
|
|
360
|
+
}
|
|
361
|
+
if (Number.isInteger(found) &&
|
|
362
|
+
(opts.cb
|
|
363
|
+
? opts.cb(fullCharacterInFront, restOfStringInFront, indexOfTheCharacterInFront)
|
|
364
|
+
: true)) {
|
|
365
|
+
return whatToMatchVal;
|
|
366
|
+
}
|
|
288
367
|
}
|
|
289
|
-
|
|
290
|
-
return false;
|
|
368
|
+
return false;
|
|
291
369
|
}
|
|
292
370
|
function matchLeftIncl(str, position, whatToMatch, opts) {
|
|
293
|
-
|
|
371
|
+
return main("matchLeftIncl", str, position, whatToMatch, opts);
|
|
294
372
|
}
|
|
295
373
|
function matchLeft(str, position, whatToMatch, opts) {
|
|
296
|
-
|
|
374
|
+
return main("matchLeft", str, position, whatToMatch, opts);
|
|
297
375
|
}
|
|
298
376
|
function matchRightIncl(str, position, whatToMatch, opts) {
|
|
299
|
-
|
|
377
|
+
return main("matchRightIncl", str, position, whatToMatch, opts);
|
|
300
378
|
}
|
|
301
379
|
function matchRight(str, position, whatToMatch, opts) {
|
|
302
|
-
|
|
380
|
+
return main("matchRight", str, position, whatToMatch, opts);
|
|
303
381
|
}
|
|
304
382
|
|
|
305
383
|
export { matchLeft, matchLeftIncl, matchRight, matchRightIncl };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @name string-match-left-right
|
|
3
3
|
* @fileoverview Match substrings on the left or right of a given index, ignoring whitespace
|
|
4
|
-
* @version 8.0.
|
|
4
|
+
* @version 8.0.6
|
|
5
5
|
* @author Roy Revelt, Codsen Ltd
|
|
6
6
|
* @license MIT
|
|
7
7
|
* {@link https://codsen.com/os/string-match-left-right/}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/**
|
|
12
12
|
* @name arrayiffy-if-string
|
|
13
13
|
* @fileoverview Put non-empty strings into arrays, turn empty-ones into empty arrays. Bypass everything else.
|
|
14
|
-
* @version 4.0.
|
|
14
|
+
* @version 4.0.6
|
|
15
15
|
* @author Roy Revelt, Codsen Ltd
|
|
16
16
|
* @license MIT
|
|
17
17
|
* {@link https://codsen.com/os/arrayiffy-if-string/}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "string-match-left-right",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.6",
|
|
4
4
|
"description": "Match substrings on the left or right of a given index, ignoring whitespace",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"left",
|
|
@@ -32,13 +32,12 @@
|
|
|
32
32
|
"types": "types/index.d.ts",
|
|
33
33
|
"scripts": {
|
|
34
34
|
"build": "rollup -c",
|
|
35
|
-
"
|
|
36
|
-
"
|
|
35
|
+
"build:esbuild": "node '../../scripts/esbuild.js'",
|
|
36
|
+
"build:esbuild:dev": "cross-env MODE=dev node '../../scripts/esbuild.js'",
|
|
37
|
+
"ci_test": "npm run build && npm run format && tap --no-only --reporter=silent",
|
|
37
38
|
"clean_types": "../../scripts/cleanTypes.js",
|
|
38
39
|
"dev": "rollup -c --dev",
|
|
39
40
|
"devunittest": "npm run dev && tap --only -R 'base'",
|
|
40
|
-
"esbuild": "node '../../scripts/esbuild.js'",
|
|
41
|
-
"esbuild_dev": "cross-env MODE=dev node '../../scripts/esbuild.js'",
|
|
42
41
|
"format": "npm run lect && npm run prettier && npm run lint",
|
|
43
42
|
"lect": "lect",
|
|
44
43
|
"lint": "../../node_modules/eslint/bin/eslint.js . --ext .js --ext .ts --fix --config \"../../.eslintrc.json\" --quiet",
|
|
@@ -47,17 +46,14 @@
|
|
|
47
46
|
"republish": "npm publish || :",
|
|
48
47
|
"tap": "tap",
|
|
49
48
|
"pretest": "npm run build",
|
|
50
|
-
"test": "npm run
|
|
49
|
+
"test": "npm run test:ci && npm run perf",
|
|
50
|
+
"test:ci": "npm run unittest && npm run test:examples && npm run format",
|
|
51
51
|
"test:examples": "../../scripts/test-examples.js && npm run lect && npm run prettier",
|
|
52
52
|
"tsc": "tsc",
|
|
53
|
-
"unittest": "tap --no-only --
|
|
53
|
+
"unittest": "tap --no-only --reporter=terse && tsc -p tsconfig.json --noEmit"
|
|
54
54
|
},
|
|
55
55
|
"tap": {
|
|
56
56
|
"check-coverage": false,
|
|
57
|
-
"coverage-report": [
|
|
58
|
-
"json-summary",
|
|
59
|
-
"text"
|
|
60
|
-
],
|
|
61
57
|
"node-arg": [
|
|
62
58
|
"--no-warnings",
|
|
63
59
|
"--experimental-loader",
|
|
@@ -79,10 +75,10 @@
|
|
|
79
75
|
}
|
|
80
76
|
},
|
|
81
77
|
"dependencies": {
|
|
82
|
-
"@babel/runtime": "^7.16.
|
|
83
|
-
"arrayiffy-if-string": "^4.0.
|
|
78
|
+
"@babel/runtime": "^7.16.3",
|
|
79
|
+
"arrayiffy-if-string": "^4.0.6",
|
|
84
80
|
"lodash.isplainobject": "^4.0.6",
|
|
85
|
-
"string-character-is-astral-surrogate": "^2.0.
|
|
81
|
+
"string-character-is-astral-surrogate": "^2.0.6"
|
|
86
82
|
},
|
|
87
83
|
"devDependencies": {
|
|
88
84
|
"@babel/cli": "^7.16.0",
|
|
@@ -93,8 +89,8 @@
|
|
|
93
89
|
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0",
|
|
94
90
|
"@babel/plugin-proposal-object-rest-spread": "^7.16.0",
|
|
95
91
|
"@babel/plugin-proposal-optional-chaining": "^7.16.0",
|
|
96
|
-
"@babel/plugin-transform-runtime": "^7.16.
|
|
97
|
-
"@babel/preset-env": "^7.16.
|
|
92
|
+
"@babel/plugin-transform-runtime": "^7.16.4",
|
|
93
|
+
"@babel/preset-env": "^7.16.4",
|
|
98
94
|
"@babel/preset-typescript": "^7.16.0",
|
|
99
95
|
"@babel/register": "^7.16.0",
|
|
100
96
|
"@istanbuljs/esm-loader-hook": "^0.1.2",
|
|
@@ -104,25 +100,25 @@
|
|
|
104
100
|
"@rollup/plugin-strip": "^2.1.0",
|
|
105
101
|
"@rollup/plugin-typescript": "^8.3.0",
|
|
106
102
|
"@types/lodash.isplainobject": "^4.0.6",
|
|
107
|
-
"@types/node": "^16.11.
|
|
103
|
+
"@types/node": "^16.11.9",
|
|
108
104
|
"@types/tap": "^15.0.5",
|
|
109
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
110
|
-
"@typescript-eslint/parser": "^5.
|
|
105
|
+
"@typescript-eslint/eslint-plugin": "^5.4.0",
|
|
106
|
+
"@typescript-eslint/parser": "^5.4.0",
|
|
111
107
|
"core-js": "^3.19.1",
|
|
112
108
|
"cross-env": "^7.0.3",
|
|
113
|
-
"eslint": "^8.
|
|
114
|
-
"lect": "^0.18.
|
|
115
|
-
"rollup": "^2.
|
|
109
|
+
"eslint": "^8.3.0",
|
|
110
|
+
"lect": "^0.18.6",
|
|
111
|
+
"rollup": "^2.60.0",
|
|
116
112
|
"rollup-plugin-ascii": "^0.0.3",
|
|
117
113
|
"rollup-plugin-banner": "^0.2.1",
|
|
118
114
|
"rollup-plugin-cleanup": "^3.2.1",
|
|
119
115
|
"rollup-plugin-dts": "^4.0.1",
|
|
120
116
|
"rollup-plugin-terser": "^7.0.2",
|
|
121
|
-
"tap": "^15.
|
|
117
|
+
"tap": "^15.1.2",
|
|
122
118
|
"tslib": "^2.3.1",
|
|
123
|
-
"typescript": "^4.
|
|
119
|
+
"typescript": "^4.5.2"
|
|
124
120
|
},
|
|
125
121
|
"engines": {
|
|
126
|
-
"node": ">=
|
|
122
|
+
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
|
127
123
|
}
|
|
128
124
|
}
|