@nyaomaru/divider 1.9.20 → 1.9.22
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/dist/index.cjs +100 -70
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +100 -70
- package/package.json +4 -1
package/dist/index.cjs
CHANGED
|
@@ -103,11 +103,10 @@ function isValidInput(value) {
|
|
|
103
103
|
function isStringOrNumber(value) {
|
|
104
104
|
return isString(value) || isNumber(value);
|
|
105
105
|
}
|
|
106
|
-
function isStringArray(value) {
|
|
107
|
-
return Array.isArray(value) && value.every(isString);
|
|
108
|
-
}
|
|
109
106
|
function isNestedStringArray(value) {
|
|
110
|
-
|
|
107
|
+
if (!Array.isArray(value) || value.length === 0) return false;
|
|
108
|
+
const firstRow = value[0];
|
|
109
|
+
return Array.isArray(firstRow) && firstRow.every((item) => isString(item));
|
|
111
110
|
}
|
|
112
111
|
function isWhitespaceOnly(value) {
|
|
113
112
|
return value.trim() === "";
|
|
@@ -233,12 +232,10 @@ function sortAscending(numbers) {
|
|
|
233
232
|
|
|
234
233
|
// src/utils/parser.ts
|
|
235
234
|
function divideString(input, numSeparators, strSeparators, options) {
|
|
236
|
-
if (
|
|
235
|
+
if (hasNoSeparators(numSeparators, strSeparators)) {
|
|
237
236
|
return [input];
|
|
238
237
|
}
|
|
239
|
-
|
|
240
|
-
throw new Error("Invalid numeric separators");
|
|
241
|
-
}
|
|
238
|
+
assertValidNumSeparators(numSeparators);
|
|
242
239
|
const regex = getRegex(strSeparators);
|
|
243
240
|
const shouldPreserveEmpty = options?.preserveEmpty === true;
|
|
244
241
|
const sortedNumSeparators = sortAscending(numSeparators);
|
|
@@ -246,6 +243,12 @@ function divideString(input, numSeparators, strSeparators, options) {
|
|
|
246
243
|
const segments = regex ? parts.flatMap((part) => part.split(regex)) : parts;
|
|
247
244
|
return shouldPreserveEmpty ? segments : segments.filter((segment) => !isEmptyString(segment));
|
|
248
245
|
}
|
|
246
|
+
var hasNoSeparators = (numSeparators, strSeparators) => isEmptyArray(numSeparators) && isEmptyArray(strSeparators);
|
|
247
|
+
var assertValidNumSeparators = (numSeparators) => {
|
|
248
|
+
if (!Array.isArray(numSeparators) || !numSeparators.every(isNumber)) {
|
|
249
|
+
throw new Error("Invalid numeric separators");
|
|
250
|
+
}
|
|
251
|
+
};
|
|
249
252
|
|
|
250
253
|
// src/utils/array.ts
|
|
251
254
|
function ensureStringArray(input) {
|
|
@@ -284,29 +287,32 @@ function trimNestedSegments(rows, preserveEmpty) {
|
|
|
284
287
|
return rows.map((row) => trimSegments(row, preserveEmpty));
|
|
285
288
|
}
|
|
286
289
|
function applyDividerOptions(result, options) {
|
|
287
|
-
let output = result;
|
|
288
290
|
const shouldPreserveEmpty = options.preserveEmpty === true;
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
output = output.flat();
|
|
294
|
-
}
|
|
295
|
-
if (!isNoneMode(options.exclude)) {
|
|
296
|
-
const exclude = options.exclude ?? DIVIDER_EXCLUDE_MODES.NONE;
|
|
297
|
-
let shouldKeep = () => true;
|
|
298
|
-
if (exclude in excludePredicateMap) {
|
|
299
|
-
shouldKeep = excludePredicateMap[exclude];
|
|
300
|
-
}
|
|
301
|
-
const filterNested = (arr) => {
|
|
302
|
-
const filteredRows = arr.map((row) => row.filter(shouldKeep));
|
|
303
|
-
return shouldPreserveEmpty ? filteredRows : filteredRows.filter((row) => row.length > 0);
|
|
304
|
-
};
|
|
305
|
-
const filterFlat = (arr) => arr.filter(shouldKeep);
|
|
306
|
-
output = isNestedStringArray(output) ? filterNested(output) : filterFlat(output);
|
|
307
|
-
}
|
|
291
|
+
let output = result;
|
|
292
|
+
output = applyTrimOption(output, options, shouldPreserveEmpty);
|
|
293
|
+
output = applyFlattenOption(output, options);
|
|
294
|
+
output = applyExcludeOption(output, options, shouldPreserveEmpty);
|
|
308
295
|
return output;
|
|
309
296
|
}
|
|
297
|
+
var applyTrimOption = (output, options, shouldPreserveEmpty) => {
|
|
298
|
+
if (!options.trim) return output;
|
|
299
|
+
return isNestedStringArray(output) ? trimNestedSegments(output, shouldPreserveEmpty) : trimSegments(output, shouldPreserveEmpty);
|
|
300
|
+
};
|
|
301
|
+
var applyFlattenOption = (output, options) => options.flatten ? output.flat() : output;
|
|
302
|
+
var applyExcludeOption = (output, options, shouldPreserveEmpty) => {
|
|
303
|
+
if (options.exclude == null || isNoneMode(options.exclude)) return output;
|
|
304
|
+
const exclude = options.exclude;
|
|
305
|
+
let shouldKeep = () => true;
|
|
306
|
+
if (exclude in excludePredicateMap) {
|
|
307
|
+
shouldKeep = excludePredicateMap[exclude];
|
|
308
|
+
}
|
|
309
|
+
const filterNested = (arr) => {
|
|
310
|
+
const filteredRows = arr.map((row) => row.filter(shouldKeep));
|
|
311
|
+
return shouldPreserveEmpty ? filteredRows : filteredRows.filter((row) => row.length > 0);
|
|
312
|
+
};
|
|
313
|
+
const filterFlat = (arr) => arr.filter(shouldKeep);
|
|
314
|
+
return isNestedStringArray(output) ? filterNested(output) : filterFlat(output);
|
|
315
|
+
};
|
|
310
316
|
|
|
311
317
|
// src/utils/separator.ts
|
|
312
318
|
function classifySeparators(args) {
|
|
@@ -431,28 +437,8 @@ function stripOuterQuotes(text, quoteChar, { lenient = true } = {}) {
|
|
|
431
437
|
const escapedPair = quoteChar + quoteChar;
|
|
432
438
|
const isWhitespace = (char) => char === WHITE_SPACE || char === TAB;
|
|
433
439
|
const restoreEscapedQuotes = (fieldText) => fieldText.split(escapedPair).join(quoteChar);
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
while (left <= right && isWhitespace(text[left])) left++;
|
|
437
|
-
while (right >= left && isWhitespace(text[right])) right--;
|
|
438
|
-
if (left > right) return restoreEscapedQuotes(text);
|
|
439
|
-
const startsWithQuote = text[left] === quoteChar;
|
|
440
|
-
if (!startsWithQuote) return restoreEscapedQuotes(text);
|
|
441
|
-
const endsWithQuote = text[right] === quoteChar;
|
|
442
|
-
if (endsWithQuote && right > left) {
|
|
443
|
-
const withoutPair = text.slice(0, left) + text.slice(left + 1, right) + text.slice(right + 1);
|
|
444
|
-
return restoreEscapedQuotes(withoutPair);
|
|
445
|
-
}
|
|
446
|
-
if (!lenient) return restoreEscapedQuotes(text);
|
|
447
|
-
let result = text.slice(0, left) + text.slice(left + 1);
|
|
448
|
-
let lastNonSpaceIndexAfterTrim = result.length - 1;
|
|
449
|
-
while (lastNonSpaceIndexAfterTrim >= 0 && isWhitespace(result[lastNonSpaceIndexAfterTrim])) {
|
|
450
|
-
lastNonSpaceIndexAfterTrim--;
|
|
451
|
-
}
|
|
452
|
-
if (lastNonSpaceIndexAfterTrim >= 0 && result[lastNonSpaceIndexAfterTrim] === quoteChar) {
|
|
453
|
-
result = result.slice(0, lastNonSpaceIndexAfterTrim) + result.slice(lastNonSpaceIndexAfterTrim + 1);
|
|
454
|
-
}
|
|
455
|
-
return restoreEscapedQuotes(result);
|
|
440
|
+
const stripped = stripOuterQuotesRaw(text, quoteChar, lenient, isWhitespace);
|
|
441
|
+
return restoreEscapedQuotes(stripped);
|
|
456
442
|
}
|
|
457
443
|
function quotedDivide(line, {
|
|
458
444
|
delimiter = ",",
|
|
@@ -461,24 +447,65 @@ function quotedDivide(line, {
|
|
|
461
447
|
lenient = true
|
|
462
448
|
} = {}) {
|
|
463
449
|
if (isEmptyString(line)) return [""];
|
|
450
|
+
return buildQuotedFields(line, delimiter, quote, trim, lenient);
|
|
451
|
+
}
|
|
452
|
+
var findNonSpaceBounds = (text, isWhitespace) => {
|
|
453
|
+
let left = 0;
|
|
454
|
+
let right = text.length - 1;
|
|
455
|
+
while (left <= right && isWhitespace(text[left])) left++;
|
|
456
|
+
while (right >= left && isWhitespace(text[right])) right--;
|
|
457
|
+
return { left, right };
|
|
458
|
+
};
|
|
459
|
+
var stripMatchedOuterQuotes = (text, left, right) => text.slice(0, left) + text.slice(left + 1, right) + text.slice(right + 1);
|
|
460
|
+
var removeCharAt = (text, index) => text.slice(0, index) + text.slice(index + 1);
|
|
461
|
+
var stripTrailingQuote = (text, quoteChar, isWhitespace) => {
|
|
462
|
+
let lastNonSpaceIndex = text.length - 1;
|
|
463
|
+
while (lastNonSpaceIndex >= 0 && isWhitespace(text[lastNonSpaceIndex])) {
|
|
464
|
+
lastNonSpaceIndex--;
|
|
465
|
+
}
|
|
466
|
+
if (lastNonSpaceIndex < 0 || text[lastNonSpaceIndex] !== quoteChar) {
|
|
467
|
+
return text;
|
|
468
|
+
}
|
|
469
|
+
return removeCharAt(text, lastNonSpaceIndex);
|
|
470
|
+
};
|
|
471
|
+
var stripOuterQuotesRaw = (text, quoteChar, lenient, isWhitespace) => {
|
|
472
|
+
const { left, right } = findNonSpaceBounds(text, isWhitespace);
|
|
473
|
+
if (left > right) return text;
|
|
474
|
+
if (text[left] !== quoteChar) return text;
|
|
475
|
+
if (text[right] === quoteChar && right > left) {
|
|
476
|
+
return stripMatchedOuterQuotes(text, left, right);
|
|
477
|
+
}
|
|
478
|
+
if (!lenient) return text;
|
|
479
|
+
const withoutLeading = removeCharAt(text, left);
|
|
480
|
+
return stripTrailingQuote(withoutLeading, quoteChar, isWhitespace);
|
|
481
|
+
};
|
|
482
|
+
var buildQuotedFields = (line, delimiter, quote, trim, lenient) => {
|
|
464
483
|
const pieces = dividePreserve(line, delimiter);
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
const flush = () => {
|
|
469
|
-
let fieldValue = stripOuterQuotes(currentFieldBuffer, quote, { lenient });
|
|
470
|
-
if (trim) fieldValue = fieldValue.trim();
|
|
471
|
-
fields.push(fieldValue);
|
|
472
|
-
currentFieldBuffer = "";
|
|
484
|
+
const state = {
|
|
485
|
+
fields: [],
|
|
486
|
+
current: ""
|
|
473
487
|
};
|
|
474
488
|
for (const piece of pieces) {
|
|
475
|
-
|
|
476
|
-
insideQuotes = countUnescaped(currentFieldBuffer, quote) % 2 === 1;
|
|
477
|
-
if (!insideQuotes) flush();
|
|
489
|
+
appendPiece(state, piece, delimiter, quote, trim, lenient);
|
|
478
490
|
}
|
|
479
|
-
if (!isEmptyString(
|
|
480
|
-
|
|
481
|
-
}
|
|
491
|
+
if (!isEmptyString(state.current)) {
|
|
492
|
+
flushField(state, quote, trim, lenient);
|
|
493
|
+
}
|
|
494
|
+
return state.fields;
|
|
495
|
+
};
|
|
496
|
+
var appendPiece = (state, piece, delimiter, quote, trim, lenient) => {
|
|
497
|
+
state.current = isEmptyString(state.current) ? piece : state.current + delimiter + piece;
|
|
498
|
+
const insideQuotes = countUnescaped(state.current, quote) % 2 === 1;
|
|
499
|
+
if (!insideQuotes) {
|
|
500
|
+
flushField(state, quote, trim, lenient);
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
var flushField = (state, quote, trim, lenient) => {
|
|
504
|
+
let fieldValue = stripOuterQuotes(state.current, quote, { lenient });
|
|
505
|
+
if (trim) fieldValue = fieldValue.trim();
|
|
506
|
+
state.fields.push(fieldValue);
|
|
507
|
+
state.current = "";
|
|
508
|
+
};
|
|
482
509
|
|
|
483
510
|
// src/presets/csv-divider.ts
|
|
484
511
|
function csvDivider(line, options = {}) {
|
|
@@ -513,12 +540,15 @@ function emailDivider(input, options = {}) {
|
|
|
513
540
|
function pathDivider(input, options = {}) {
|
|
514
541
|
const { trim = false, collapse = true } = options;
|
|
515
542
|
if (isEmptyString(input)) return [""];
|
|
516
|
-
const segments =
|
|
517
|
-
|
|
518
|
-
);
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
543
|
+
const segments = buildPathSegments(input, collapse);
|
|
544
|
+
const maybeTrimmed = trimSegments2(segments, trim);
|
|
545
|
+
return applyCollapseRules(maybeTrimmed, collapse);
|
|
546
|
+
}
|
|
547
|
+
var buildPathSegments = (input, collapse) => collapse ? divider(input, PATH_SEPARATORS.SLASH, PATH_SEPARATORS.ALT) : dividePreserve(input, PATH_SEPARATORS.ALT).flatMap(
|
|
548
|
+
(part) => dividePreserve(part, PATH_SEPARATORS.SLASH)
|
|
549
|
+
);
|
|
550
|
+
var trimSegments2 = (segments, trim) => trim ? segments.map((segment) => segment.trim()) : segments;
|
|
551
|
+
var applyCollapseRules = (segments, collapse) => collapse ? segments.filter((segment) => !isEmptyString(segment)) : segments;
|
|
522
552
|
|
|
523
553
|
// src/presets/query-divider.ts
|
|
524
554
|
function tryExtractQuery(input) {
|
package/dist/index.d.cts
CHANGED
|
@@ -56,7 +56,7 @@ type HasFlattenOption<TOptions extends DividerInferredOptions> = TOptions extend
|
|
|
56
56
|
readonly flatten?: infer Flag;
|
|
57
57
|
} ? Flag extends true ? true : false : false;
|
|
58
58
|
type DividerResult<T extends DividerInput, TOptions extends DividerInferredOptions = DividerEmptyOptions> = T extends StringInput ? DividerStringResult : HasFlattenOption<TOptions> extends true ? DividerStringResult : DividerArrayResult;
|
|
59
|
-
type ExtractedDividerOptions<TArgs extends DividerArgs> = TArgs extends readonly [...infer
|
|
59
|
+
type ExtractedDividerOptions<TArgs extends DividerArgs> = TArgs extends readonly [...infer Rest, infer Last] ? Rest extends DividerArg[] ? Last extends DividerOptions ? Last : DividerEmptyOptions : DividerEmptyOptions : DividerEmptyOptions;
|
|
60
60
|
type DividerLoopOptions = DividerOptions & {
|
|
61
61
|
/** Starting position for the division (0-based) */
|
|
62
62
|
startOffset?: number;
|
package/dist/index.d.ts
CHANGED
|
@@ -56,7 +56,7 @@ type HasFlattenOption<TOptions extends DividerInferredOptions> = TOptions extend
|
|
|
56
56
|
readonly flatten?: infer Flag;
|
|
57
57
|
} ? Flag extends true ? true : false : false;
|
|
58
58
|
type DividerResult<T extends DividerInput, TOptions extends DividerInferredOptions = DividerEmptyOptions> = T extends StringInput ? DividerStringResult : HasFlattenOption<TOptions> extends true ? DividerStringResult : DividerArrayResult;
|
|
59
|
-
type ExtractedDividerOptions<TArgs extends DividerArgs> = TArgs extends readonly [...infer
|
|
59
|
+
type ExtractedDividerOptions<TArgs extends DividerArgs> = TArgs extends readonly [...infer Rest, infer Last] ? Rest extends DividerArg[] ? Last extends DividerOptions ? Last : DividerEmptyOptions : DividerEmptyOptions : DividerEmptyOptions;
|
|
60
60
|
type DividerLoopOptions = DividerOptions & {
|
|
61
61
|
/** Starting position for the division (0-based) */
|
|
62
62
|
startOffset?: number;
|
package/dist/index.js
CHANGED
|
@@ -69,11 +69,10 @@ function isValidInput(value) {
|
|
|
69
69
|
function isStringOrNumber(value) {
|
|
70
70
|
return isString(value) || isNumber(value);
|
|
71
71
|
}
|
|
72
|
-
function isStringArray(value) {
|
|
73
|
-
return Array.isArray(value) && value.every(isString);
|
|
74
|
-
}
|
|
75
72
|
function isNestedStringArray(value) {
|
|
76
|
-
|
|
73
|
+
if (!Array.isArray(value) || value.length === 0) return false;
|
|
74
|
+
const firstRow = value[0];
|
|
75
|
+
return Array.isArray(firstRow) && firstRow.every((item) => isString(item));
|
|
77
76
|
}
|
|
78
77
|
function isWhitespaceOnly(value) {
|
|
79
78
|
return value.trim() === "";
|
|
@@ -199,12 +198,10 @@ function sortAscending(numbers) {
|
|
|
199
198
|
|
|
200
199
|
// src/utils/parser.ts
|
|
201
200
|
function divideString(input, numSeparators, strSeparators, options) {
|
|
202
|
-
if (
|
|
201
|
+
if (hasNoSeparators(numSeparators, strSeparators)) {
|
|
203
202
|
return [input];
|
|
204
203
|
}
|
|
205
|
-
|
|
206
|
-
throw new Error("Invalid numeric separators");
|
|
207
|
-
}
|
|
204
|
+
assertValidNumSeparators(numSeparators);
|
|
208
205
|
const regex = getRegex(strSeparators);
|
|
209
206
|
const shouldPreserveEmpty = options?.preserveEmpty === true;
|
|
210
207
|
const sortedNumSeparators = sortAscending(numSeparators);
|
|
@@ -212,6 +209,12 @@ function divideString(input, numSeparators, strSeparators, options) {
|
|
|
212
209
|
const segments = regex ? parts.flatMap((part) => part.split(regex)) : parts;
|
|
213
210
|
return shouldPreserveEmpty ? segments : segments.filter((segment) => !isEmptyString(segment));
|
|
214
211
|
}
|
|
212
|
+
var hasNoSeparators = (numSeparators, strSeparators) => isEmptyArray(numSeparators) && isEmptyArray(strSeparators);
|
|
213
|
+
var assertValidNumSeparators = (numSeparators) => {
|
|
214
|
+
if (!Array.isArray(numSeparators) || !numSeparators.every(isNumber)) {
|
|
215
|
+
throw new Error("Invalid numeric separators");
|
|
216
|
+
}
|
|
217
|
+
};
|
|
215
218
|
|
|
216
219
|
// src/utils/array.ts
|
|
217
220
|
function ensureStringArray(input) {
|
|
@@ -250,29 +253,32 @@ function trimNestedSegments(rows, preserveEmpty) {
|
|
|
250
253
|
return rows.map((row) => trimSegments(row, preserveEmpty));
|
|
251
254
|
}
|
|
252
255
|
function applyDividerOptions(result, options) {
|
|
253
|
-
let output = result;
|
|
254
256
|
const shouldPreserveEmpty = options.preserveEmpty === true;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
output = output.flat();
|
|
260
|
-
}
|
|
261
|
-
if (!isNoneMode(options.exclude)) {
|
|
262
|
-
const exclude = options.exclude ?? DIVIDER_EXCLUDE_MODES.NONE;
|
|
263
|
-
let shouldKeep = () => true;
|
|
264
|
-
if (exclude in excludePredicateMap) {
|
|
265
|
-
shouldKeep = excludePredicateMap[exclude];
|
|
266
|
-
}
|
|
267
|
-
const filterNested = (arr) => {
|
|
268
|
-
const filteredRows = arr.map((row) => row.filter(shouldKeep));
|
|
269
|
-
return shouldPreserveEmpty ? filteredRows : filteredRows.filter((row) => row.length > 0);
|
|
270
|
-
};
|
|
271
|
-
const filterFlat = (arr) => arr.filter(shouldKeep);
|
|
272
|
-
output = isNestedStringArray(output) ? filterNested(output) : filterFlat(output);
|
|
273
|
-
}
|
|
257
|
+
let output = result;
|
|
258
|
+
output = applyTrimOption(output, options, shouldPreserveEmpty);
|
|
259
|
+
output = applyFlattenOption(output, options);
|
|
260
|
+
output = applyExcludeOption(output, options, shouldPreserveEmpty);
|
|
274
261
|
return output;
|
|
275
262
|
}
|
|
263
|
+
var applyTrimOption = (output, options, shouldPreserveEmpty) => {
|
|
264
|
+
if (!options.trim) return output;
|
|
265
|
+
return isNestedStringArray(output) ? trimNestedSegments(output, shouldPreserveEmpty) : trimSegments(output, shouldPreserveEmpty);
|
|
266
|
+
};
|
|
267
|
+
var applyFlattenOption = (output, options) => options.flatten ? output.flat() : output;
|
|
268
|
+
var applyExcludeOption = (output, options, shouldPreserveEmpty) => {
|
|
269
|
+
if (options.exclude == null || isNoneMode(options.exclude)) return output;
|
|
270
|
+
const exclude = options.exclude;
|
|
271
|
+
let shouldKeep = () => true;
|
|
272
|
+
if (exclude in excludePredicateMap) {
|
|
273
|
+
shouldKeep = excludePredicateMap[exclude];
|
|
274
|
+
}
|
|
275
|
+
const filterNested = (arr) => {
|
|
276
|
+
const filteredRows = arr.map((row) => row.filter(shouldKeep));
|
|
277
|
+
return shouldPreserveEmpty ? filteredRows : filteredRows.filter((row) => row.length > 0);
|
|
278
|
+
};
|
|
279
|
+
const filterFlat = (arr) => arr.filter(shouldKeep);
|
|
280
|
+
return isNestedStringArray(output) ? filterNested(output) : filterFlat(output);
|
|
281
|
+
};
|
|
276
282
|
|
|
277
283
|
// src/utils/separator.ts
|
|
278
284
|
function classifySeparators(args) {
|
|
@@ -397,28 +403,8 @@ function stripOuterQuotes(text, quoteChar, { lenient = true } = {}) {
|
|
|
397
403
|
const escapedPair = quoteChar + quoteChar;
|
|
398
404
|
const isWhitespace = (char) => char === WHITE_SPACE || char === TAB;
|
|
399
405
|
const restoreEscapedQuotes = (fieldText) => fieldText.split(escapedPair).join(quoteChar);
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
while (left <= right && isWhitespace(text[left])) left++;
|
|
403
|
-
while (right >= left && isWhitespace(text[right])) right--;
|
|
404
|
-
if (left > right) return restoreEscapedQuotes(text);
|
|
405
|
-
const startsWithQuote = text[left] === quoteChar;
|
|
406
|
-
if (!startsWithQuote) return restoreEscapedQuotes(text);
|
|
407
|
-
const endsWithQuote = text[right] === quoteChar;
|
|
408
|
-
if (endsWithQuote && right > left) {
|
|
409
|
-
const withoutPair = text.slice(0, left) + text.slice(left + 1, right) + text.slice(right + 1);
|
|
410
|
-
return restoreEscapedQuotes(withoutPair);
|
|
411
|
-
}
|
|
412
|
-
if (!lenient) return restoreEscapedQuotes(text);
|
|
413
|
-
let result = text.slice(0, left) + text.slice(left + 1);
|
|
414
|
-
let lastNonSpaceIndexAfterTrim = result.length - 1;
|
|
415
|
-
while (lastNonSpaceIndexAfterTrim >= 0 && isWhitespace(result[lastNonSpaceIndexAfterTrim])) {
|
|
416
|
-
lastNonSpaceIndexAfterTrim--;
|
|
417
|
-
}
|
|
418
|
-
if (lastNonSpaceIndexAfterTrim >= 0 && result[lastNonSpaceIndexAfterTrim] === quoteChar) {
|
|
419
|
-
result = result.slice(0, lastNonSpaceIndexAfterTrim) + result.slice(lastNonSpaceIndexAfterTrim + 1);
|
|
420
|
-
}
|
|
421
|
-
return restoreEscapedQuotes(result);
|
|
406
|
+
const stripped = stripOuterQuotesRaw(text, quoteChar, lenient, isWhitespace);
|
|
407
|
+
return restoreEscapedQuotes(stripped);
|
|
422
408
|
}
|
|
423
409
|
function quotedDivide(line, {
|
|
424
410
|
delimiter = ",",
|
|
@@ -427,24 +413,65 @@ function quotedDivide(line, {
|
|
|
427
413
|
lenient = true
|
|
428
414
|
} = {}) {
|
|
429
415
|
if (isEmptyString(line)) return [""];
|
|
416
|
+
return buildQuotedFields(line, delimiter, quote, trim, lenient);
|
|
417
|
+
}
|
|
418
|
+
var findNonSpaceBounds = (text, isWhitespace) => {
|
|
419
|
+
let left = 0;
|
|
420
|
+
let right = text.length - 1;
|
|
421
|
+
while (left <= right && isWhitespace(text[left])) left++;
|
|
422
|
+
while (right >= left && isWhitespace(text[right])) right--;
|
|
423
|
+
return { left, right };
|
|
424
|
+
};
|
|
425
|
+
var stripMatchedOuterQuotes = (text, left, right) => text.slice(0, left) + text.slice(left + 1, right) + text.slice(right + 1);
|
|
426
|
+
var removeCharAt = (text, index) => text.slice(0, index) + text.slice(index + 1);
|
|
427
|
+
var stripTrailingQuote = (text, quoteChar, isWhitespace) => {
|
|
428
|
+
let lastNonSpaceIndex = text.length - 1;
|
|
429
|
+
while (lastNonSpaceIndex >= 0 && isWhitespace(text[lastNonSpaceIndex])) {
|
|
430
|
+
lastNonSpaceIndex--;
|
|
431
|
+
}
|
|
432
|
+
if (lastNonSpaceIndex < 0 || text[lastNonSpaceIndex] !== quoteChar) {
|
|
433
|
+
return text;
|
|
434
|
+
}
|
|
435
|
+
return removeCharAt(text, lastNonSpaceIndex);
|
|
436
|
+
};
|
|
437
|
+
var stripOuterQuotesRaw = (text, quoteChar, lenient, isWhitespace) => {
|
|
438
|
+
const { left, right } = findNonSpaceBounds(text, isWhitespace);
|
|
439
|
+
if (left > right) return text;
|
|
440
|
+
if (text[left] !== quoteChar) return text;
|
|
441
|
+
if (text[right] === quoteChar && right > left) {
|
|
442
|
+
return stripMatchedOuterQuotes(text, left, right);
|
|
443
|
+
}
|
|
444
|
+
if (!lenient) return text;
|
|
445
|
+
const withoutLeading = removeCharAt(text, left);
|
|
446
|
+
return stripTrailingQuote(withoutLeading, quoteChar, isWhitespace);
|
|
447
|
+
};
|
|
448
|
+
var buildQuotedFields = (line, delimiter, quote, trim, lenient) => {
|
|
430
449
|
const pieces = dividePreserve(line, delimiter);
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
const flush = () => {
|
|
435
|
-
let fieldValue = stripOuterQuotes(currentFieldBuffer, quote, { lenient });
|
|
436
|
-
if (trim) fieldValue = fieldValue.trim();
|
|
437
|
-
fields.push(fieldValue);
|
|
438
|
-
currentFieldBuffer = "";
|
|
450
|
+
const state = {
|
|
451
|
+
fields: [],
|
|
452
|
+
current: ""
|
|
439
453
|
};
|
|
440
454
|
for (const piece of pieces) {
|
|
441
|
-
|
|
442
|
-
insideQuotes = countUnescaped(currentFieldBuffer, quote) % 2 === 1;
|
|
443
|
-
if (!insideQuotes) flush();
|
|
455
|
+
appendPiece(state, piece, delimiter, quote, trim, lenient);
|
|
444
456
|
}
|
|
445
|
-
if (!isEmptyString(
|
|
446
|
-
|
|
447
|
-
}
|
|
457
|
+
if (!isEmptyString(state.current)) {
|
|
458
|
+
flushField(state, quote, trim, lenient);
|
|
459
|
+
}
|
|
460
|
+
return state.fields;
|
|
461
|
+
};
|
|
462
|
+
var appendPiece = (state, piece, delimiter, quote, trim, lenient) => {
|
|
463
|
+
state.current = isEmptyString(state.current) ? piece : state.current + delimiter + piece;
|
|
464
|
+
const insideQuotes = countUnescaped(state.current, quote) % 2 === 1;
|
|
465
|
+
if (!insideQuotes) {
|
|
466
|
+
flushField(state, quote, trim, lenient);
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
var flushField = (state, quote, trim, lenient) => {
|
|
470
|
+
let fieldValue = stripOuterQuotes(state.current, quote, { lenient });
|
|
471
|
+
if (trim) fieldValue = fieldValue.trim();
|
|
472
|
+
state.fields.push(fieldValue);
|
|
473
|
+
state.current = "";
|
|
474
|
+
};
|
|
448
475
|
|
|
449
476
|
// src/presets/csv-divider.ts
|
|
450
477
|
function csvDivider(line, options = {}) {
|
|
@@ -479,12 +506,15 @@ function emailDivider(input, options = {}) {
|
|
|
479
506
|
function pathDivider(input, options = {}) {
|
|
480
507
|
const { trim = false, collapse = true } = options;
|
|
481
508
|
if (isEmptyString(input)) return [""];
|
|
482
|
-
const segments =
|
|
483
|
-
|
|
484
|
-
);
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
509
|
+
const segments = buildPathSegments(input, collapse);
|
|
510
|
+
const maybeTrimmed = trimSegments2(segments, trim);
|
|
511
|
+
return applyCollapseRules(maybeTrimmed, collapse);
|
|
512
|
+
}
|
|
513
|
+
var buildPathSegments = (input, collapse) => collapse ? divider(input, PATH_SEPARATORS.SLASH, PATH_SEPARATORS.ALT) : dividePreserve(input, PATH_SEPARATORS.ALT).flatMap(
|
|
514
|
+
(part) => dividePreserve(part, PATH_SEPARATORS.SLASH)
|
|
515
|
+
);
|
|
516
|
+
var trimSegments2 = (segments, trim) => trim ? segments.map((segment) => segment.trim()) : segments;
|
|
517
|
+
var applyCollapseRules = (segments, collapse) => collapse ? segments.filter((segment) => !isEmptyString(segment)) : segments;
|
|
488
518
|
|
|
489
519
|
// src/presets/query-divider.ts
|
|
490
520
|
function tryExtractQuery(input) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nyaomaru/divider",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.9.
|
|
4
|
+
"version": "1.9.22",
|
|
5
5
|
"description": "To divide string or string[] with a given separator",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -38,11 +38,14 @@
|
|
|
38
38
|
"@eslint/js": "^9.26.0",
|
|
39
39
|
"@types/jest": "^30.0.0",
|
|
40
40
|
"@types/node": "^22.15.12",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
42
|
+
"@typescript-eslint/parser": "^8.32.1",
|
|
41
43
|
"bun-types": "^1.2.21",
|
|
42
44
|
"eslint": "^9.39.1",
|
|
43
45
|
"eslint-config-prettier": "^10.1.8",
|
|
44
46
|
"eslint-plugin-prettier": "^5.5.4",
|
|
45
47
|
"jest": "^30.2.0",
|
|
48
|
+
"lefthook": "^2.0.13",
|
|
46
49
|
"prettier": "^3.5.3",
|
|
47
50
|
"ts-jest": "^29.4.5",
|
|
48
51
|
"ts-node": "^10.9.2",
|