@nyaomaru/divider 2.0.7 → 2.0.9
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 +69 -57
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +69 -57
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -108,6 +108,9 @@ function isNestedStringArray(value) {
|
|
|
108
108
|
const firstRow = value[0];
|
|
109
109
|
return Array.isArray(firstRow) && firstRow.every((item) => isString(item));
|
|
110
110
|
}
|
|
111
|
+
function isSpaceOrTab(value) {
|
|
112
|
+
return value === WHITE_SPACE || value === TAB;
|
|
113
|
+
}
|
|
111
114
|
function isWhitespaceOnly(value) {
|
|
112
115
|
return value.trim() === "";
|
|
113
116
|
}
|
|
@@ -443,11 +446,7 @@ function dividerNumberString(input, options) {
|
|
|
443
446
|
return transformDividerInput(input, divideNumberString, options);
|
|
444
447
|
}
|
|
445
448
|
|
|
446
|
-
// src/utils/
|
|
447
|
-
function dividePreserve(input, separator) {
|
|
448
|
-
if (isEmptyString(input)) return [""];
|
|
449
|
-
return divider(input, separator, { preserveEmpty: true });
|
|
450
|
-
}
|
|
449
|
+
// src/utils/count-unescaped.ts
|
|
451
450
|
var countUnescapedSingleChar = (text, quote) => {
|
|
452
451
|
let count = 0;
|
|
453
452
|
for (let index = 0; index < text.length; index++) {
|
|
@@ -484,67 +483,56 @@ function countUnescaped(text, quote) {
|
|
|
484
483
|
if (quote.length === 1) return countUnescapedSingleChar(text, quote);
|
|
485
484
|
return countUnescapedMultiChar(text, quote);
|
|
486
485
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
return restoreEscapedQuotes(stripped);
|
|
493
|
-
}
|
|
494
|
-
function quotedDivide(line, {
|
|
495
|
-
delimiter = ",",
|
|
496
|
-
quote = '"',
|
|
497
|
-
trim = false,
|
|
498
|
-
lenient = true
|
|
499
|
-
} = {}) {
|
|
500
|
-
if (isEmptyString(line)) return [""];
|
|
501
|
-
return buildQuotedFields(line, delimiter, quote, trim, lenient);
|
|
486
|
+
|
|
487
|
+
// src/utils/divide-preserve.ts
|
|
488
|
+
function dividePreserve(input, separator) {
|
|
489
|
+
if (isEmptyString(input)) return [""];
|
|
490
|
+
return divider(input, separator, { preserveEmpty: true });
|
|
502
491
|
}
|
|
503
|
-
|
|
492
|
+
|
|
493
|
+
// src/utils/strip-outer-quotes.ts
|
|
494
|
+
var findNonSpaceBounds = (text) => {
|
|
504
495
|
let left = 0;
|
|
505
496
|
let right = text.length - 1;
|
|
506
|
-
while (left <= right &&
|
|
507
|
-
while (right >= left &&
|
|
497
|
+
while (left <= right && isSpaceOrTab(text[left])) left++;
|
|
498
|
+
while (right >= left && isSpaceOrTab(text[right])) right--;
|
|
508
499
|
return { left, right };
|
|
509
500
|
};
|
|
510
|
-
var stripMatchedOuterQuotes = (text, left,
|
|
511
|
-
var
|
|
512
|
-
var stripTrailingQuote = (text,
|
|
501
|
+
var stripMatchedOuterQuotes = (text, left, rightQuoteStart, quote) => text.slice(0, left) + text.slice(left + quote.length, rightQuoteStart) + text.slice(rightQuoteStart + quote.length);
|
|
502
|
+
var removeQuoteAt = (text, start, quote) => text.slice(0, start) + text.slice(start + quote.length);
|
|
503
|
+
var stripTrailingQuote = (text, quote) => {
|
|
504
|
+
const quoteLength = quote.length;
|
|
513
505
|
let lastNonSpaceIndex = text.length - 1;
|
|
514
|
-
while (lastNonSpaceIndex >= 0 &&
|
|
506
|
+
while (lastNonSpaceIndex >= 0 && isSpaceOrTab(text[lastNonSpaceIndex])) {
|
|
515
507
|
lastNonSpaceIndex--;
|
|
516
508
|
}
|
|
517
|
-
|
|
509
|
+
const trailingQuoteStart = lastNonSpaceIndex - quoteLength + 1;
|
|
510
|
+
if (trailingQuoteStart < 0 || !text.startsWith(quote, trailingQuoteStart)) {
|
|
518
511
|
return text;
|
|
519
512
|
}
|
|
520
|
-
return
|
|
513
|
+
return removeQuoteAt(text, trailingQuoteStart, quote);
|
|
521
514
|
};
|
|
522
|
-
var stripOuterQuotesRaw = (text,
|
|
523
|
-
|
|
515
|
+
var stripOuterQuotesRaw = (text, quote, lenient) => {
|
|
516
|
+
if (quote.length === 0) return text;
|
|
517
|
+
const { left, right } = findNonSpaceBounds(text);
|
|
524
518
|
if (left > right) return text;
|
|
525
|
-
if (text
|
|
526
|
-
|
|
527
|
-
|
|
519
|
+
if (!text.startsWith(quote, left)) return text;
|
|
520
|
+
const rightQuoteStart = right - quote.length + 1;
|
|
521
|
+
if (rightQuoteStart >= left + quote.length && text.startsWith(quote, rightQuoteStart)) {
|
|
522
|
+
return stripMatchedOuterQuotes(text, left, rightQuoteStart, quote);
|
|
528
523
|
}
|
|
529
524
|
if (!lenient) return text;
|
|
530
|
-
const withoutLeading =
|
|
531
|
-
return stripTrailingQuote(withoutLeading,
|
|
532
|
-
};
|
|
533
|
-
var buildQuotedFields = (line, delimiter, quote, trim, lenient) => {
|
|
534
|
-
const pieces = dividePreserve(line, delimiter);
|
|
535
|
-
const state = {
|
|
536
|
-
fields: [],
|
|
537
|
-
current: "",
|
|
538
|
-
insideQuotes: false
|
|
539
|
-
};
|
|
540
|
-
for (const piece of pieces) {
|
|
541
|
-
appendPiece(state, piece, delimiter, quote, trim, lenient);
|
|
542
|
-
}
|
|
543
|
-
if (!isEmptyString(state.current)) {
|
|
544
|
-
flushField(state, quote, trim, lenient);
|
|
545
|
-
}
|
|
546
|
-
return state.fields;
|
|
525
|
+
const withoutLeading = removeQuoteAt(text, left, quote);
|
|
526
|
+
return stripTrailingQuote(withoutLeading, quote);
|
|
547
527
|
};
|
|
528
|
+
function stripOuterQuotes(text, quoteChar, { lenient = true } = {}) {
|
|
529
|
+
const stripped = stripOuterQuotesRaw(text, quoteChar, lenient);
|
|
530
|
+
if (quoteChar.length === 0) return stripped;
|
|
531
|
+
const escapedPair = quoteChar + quoteChar;
|
|
532
|
+
return stripped.split(escapedPair).join(quoteChar);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// src/utils/quoted-parser.ts
|
|
548
536
|
var advanceQuoteState = (insideQuotes, segment, quote) => {
|
|
549
537
|
let nextInsideQuotes = insideQuotes;
|
|
550
538
|
for (const char of segment) {
|
|
@@ -552,6 +540,13 @@ var advanceQuoteState = (insideQuotes, segment, quote) => {
|
|
|
552
540
|
}
|
|
553
541
|
return nextInsideQuotes;
|
|
554
542
|
};
|
|
543
|
+
var flushField = (state, quote, trim, lenient) => {
|
|
544
|
+
let fieldValue = stripOuterQuotes(state.current, quote, { lenient });
|
|
545
|
+
if (trim) fieldValue = fieldValue.trim();
|
|
546
|
+
state.fields.push(fieldValue);
|
|
547
|
+
state.current = "";
|
|
548
|
+
state.insideQuotes = false;
|
|
549
|
+
};
|
|
555
550
|
var appendPiece = (state, piece, delimiter, quote, trim, lenient) => {
|
|
556
551
|
const segment = isEmptyString(state.current) ? piece : delimiter + piece;
|
|
557
552
|
state.current += segment;
|
|
@@ -560,13 +555,30 @@ var appendPiece = (state, piece, delimiter, quote, trim, lenient) => {
|
|
|
560
555
|
flushField(state, quote, trim, lenient);
|
|
561
556
|
}
|
|
562
557
|
};
|
|
563
|
-
var
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
558
|
+
var buildQuotedFields = (line, delimiter, quote, trim, lenient) => {
|
|
559
|
+
const pieces = dividePreserve(line, delimiter);
|
|
560
|
+
const state = {
|
|
561
|
+
fields: [],
|
|
562
|
+
current: "",
|
|
563
|
+
insideQuotes: false
|
|
564
|
+
};
|
|
565
|
+
for (const piece of pieces) {
|
|
566
|
+
appendPiece(state, piece, delimiter, quote, trim, lenient);
|
|
567
|
+
}
|
|
568
|
+
if (!isEmptyString(state.current)) {
|
|
569
|
+
flushField(state, quote, trim, lenient);
|
|
570
|
+
}
|
|
571
|
+
return state.fields;
|
|
569
572
|
};
|
|
573
|
+
function quotedDivide(line, {
|
|
574
|
+
delimiter = ",",
|
|
575
|
+
quote = '"',
|
|
576
|
+
trim = false,
|
|
577
|
+
lenient = true
|
|
578
|
+
} = {}) {
|
|
579
|
+
if (isEmptyString(line)) return [""];
|
|
580
|
+
return buildQuotedFields(line, delimiter, quote, trim, lenient);
|
|
581
|
+
}
|
|
570
582
|
|
|
571
583
|
// src/presets/csv-divider.ts
|
|
572
584
|
function csvDivider(line, options = {}) {
|
package/dist/index.d.cts
CHANGED
|
@@ -223,9 +223,9 @@ type EmailDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
|
223
223
|
readonly splitTLD?: boolean;
|
|
224
224
|
};
|
|
225
225
|
type CsvDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
226
|
-
/**
|
|
226
|
+
/** Quote string used for quoting values. */
|
|
227
227
|
readonly quoteChar?: string;
|
|
228
|
-
/**
|
|
228
|
+
/** Delimiter string used to separate CSV fields. */
|
|
229
229
|
readonly delimiter?: string;
|
|
230
230
|
};
|
|
231
231
|
type PathDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
@@ -243,8 +243,8 @@ type QueryDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
|
243
243
|
*
|
|
244
244
|
* @param line - The CSV line string to be divided into fields
|
|
245
245
|
* @param options - Configuration options for CSV parsing
|
|
246
|
-
* @param options.delimiter - The
|
|
247
|
-
* @param options.quoteChar - The
|
|
246
|
+
* @param options.delimiter - The delimiter string used to separate fields (default: ',')
|
|
247
|
+
* @param options.quoteChar - The quote string used to wrap fields containing delimiters or newlines (default: '"')
|
|
248
248
|
* @param options.trim - Whether to trim whitespace from field values (default: false)
|
|
249
249
|
* @returns A DividerStringResult containing the parsed CSV fields
|
|
250
250
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -223,9 +223,9 @@ type EmailDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
|
223
223
|
readonly splitTLD?: boolean;
|
|
224
224
|
};
|
|
225
225
|
type CsvDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
226
|
-
/**
|
|
226
|
+
/** Quote string used for quoting values. */
|
|
227
227
|
readonly quoteChar?: string;
|
|
228
|
-
/**
|
|
228
|
+
/** Delimiter string used to separate CSV fields. */
|
|
229
229
|
readonly delimiter?: string;
|
|
230
230
|
};
|
|
231
231
|
type PathDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
@@ -243,8 +243,8 @@ type QueryDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
|
243
243
|
*
|
|
244
244
|
* @param line - The CSV line string to be divided into fields
|
|
245
245
|
* @param options - Configuration options for CSV parsing
|
|
246
|
-
* @param options.delimiter - The
|
|
247
|
-
* @param options.quoteChar - The
|
|
246
|
+
* @param options.delimiter - The delimiter string used to separate fields (default: ',')
|
|
247
|
+
* @param options.quoteChar - The quote string used to wrap fields containing delimiters or newlines (default: '"')
|
|
248
248
|
* @param options.trim - Whether to trim whitespace from field values (default: false)
|
|
249
249
|
* @returns A DividerStringResult containing the parsed CSV fields
|
|
250
250
|
*/
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,9 @@ function isNestedStringArray(value) {
|
|
|
74
74
|
const firstRow = value[0];
|
|
75
75
|
return Array.isArray(firstRow) && firstRow.every((item) => isString(item));
|
|
76
76
|
}
|
|
77
|
+
function isSpaceOrTab(value) {
|
|
78
|
+
return value === WHITE_SPACE || value === TAB;
|
|
79
|
+
}
|
|
77
80
|
function isWhitespaceOnly(value) {
|
|
78
81
|
return value.trim() === "";
|
|
79
82
|
}
|
|
@@ -409,11 +412,7 @@ function dividerNumberString(input, options) {
|
|
|
409
412
|
return transformDividerInput(input, divideNumberString, options);
|
|
410
413
|
}
|
|
411
414
|
|
|
412
|
-
// src/utils/
|
|
413
|
-
function dividePreserve(input, separator) {
|
|
414
|
-
if (isEmptyString(input)) return [""];
|
|
415
|
-
return divider(input, separator, { preserveEmpty: true });
|
|
416
|
-
}
|
|
415
|
+
// src/utils/count-unescaped.ts
|
|
417
416
|
var countUnescapedSingleChar = (text, quote) => {
|
|
418
417
|
let count = 0;
|
|
419
418
|
for (let index = 0; index < text.length; index++) {
|
|
@@ -450,67 +449,56 @@ function countUnescaped(text, quote) {
|
|
|
450
449
|
if (quote.length === 1) return countUnescapedSingleChar(text, quote);
|
|
451
450
|
return countUnescapedMultiChar(text, quote);
|
|
452
451
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
return restoreEscapedQuotes(stripped);
|
|
459
|
-
}
|
|
460
|
-
function quotedDivide(line, {
|
|
461
|
-
delimiter = ",",
|
|
462
|
-
quote = '"',
|
|
463
|
-
trim = false,
|
|
464
|
-
lenient = true
|
|
465
|
-
} = {}) {
|
|
466
|
-
if (isEmptyString(line)) return [""];
|
|
467
|
-
return buildQuotedFields(line, delimiter, quote, trim, lenient);
|
|
452
|
+
|
|
453
|
+
// src/utils/divide-preserve.ts
|
|
454
|
+
function dividePreserve(input, separator) {
|
|
455
|
+
if (isEmptyString(input)) return [""];
|
|
456
|
+
return divider(input, separator, { preserveEmpty: true });
|
|
468
457
|
}
|
|
469
|
-
|
|
458
|
+
|
|
459
|
+
// src/utils/strip-outer-quotes.ts
|
|
460
|
+
var findNonSpaceBounds = (text) => {
|
|
470
461
|
let left = 0;
|
|
471
462
|
let right = text.length - 1;
|
|
472
|
-
while (left <= right &&
|
|
473
|
-
while (right >= left &&
|
|
463
|
+
while (left <= right && isSpaceOrTab(text[left])) left++;
|
|
464
|
+
while (right >= left && isSpaceOrTab(text[right])) right--;
|
|
474
465
|
return { left, right };
|
|
475
466
|
};
|
|
476
|
-
var stripMatchedOuterQuotes = (text, left,
|
|
477
|
-
var
|
|
478
|
-
var stripTrailingQuote = (text,
|
|
467
|
+
var stripMatchedOuterQuotes = (text, left, rightQuoteStart, quote) => text.slice(0, left) + text.slice(left + quote.length, rightQuoteStart) + text.slice(rightQuoteStart + quote.length);
|
|
468
|
+
var removeQuoteAt = (text, start, quote) => text.slice(0, start) + text.slice(start + quote.length);
|
|
469
|
+
var stripTrailingQuote = (text, quote) => {
|
|
470
|
+
const quoteLength = quote.length;
|
|
479
471
|
let lastNonSpaceIndex = text.length - 1;
|
|
480
|
-
while (lastNonSpaceIndex >= 0 &&
|
|
472
|
+
while (lastNonSpaceIndex >= 0 && isSpaceOrTab(text[lastNonSpaceIndex])) {
|
|
481
473
|
lastNonSpaceIndex--;
|
|
482
474
|
}
|
|
483
|
-
|
|
475
|
+
const trailingQuoteStart = lastNonSpaceIndex - quoteLength + 1;
|
|
476
|
+
if (trailingQuoteStart < 0 || !text.startsWith(quote, trailingQuoteStart)) {
|
|
484
477
|
return text;
|
|
485
478
|
}
|
|
486
|
-
return
|
|
479
|
+
return removeQuoteAt(text, trailingQuoteStart, quote);
|
|
487
480
|
};
|
|
488
|
-
var stripOuterQuotesRaw = (text,
|
|
489
|
-
|
|
481
|
+
var stripOuterQuotesRaw = (text, quote, lenient) => {
|
|
482
|
+
if (quote.length === 0) return text;
|
|
483
|
+
const { left, right } = findNonSpaceBounds(text);
|
|
490
484
|
if (left > right) return text;
|
|
491
|
-
if (text
|
|
492
|
-
|
|
493
|
-
|
|
485
|
+
if (!text.startsWith(quote, left)) return text;
|
|
486
|
+
const rightQuoteStart = right - quote.length + 1;
|
|
487
|
+
if (rightQuoteStart >= left + quote.length && text.startsWith(quote, rightQuoteStart)) {
|
|
488
|
+
return stripMatchedOuterQuotes(text, left, rightQuoteStart, quote);
|
|
494
489
|
}
|
|
495
490
|
if (!lenient) return text;
|
|
496
|
-
const withoutLeading =
|
|
497
|
-
return stripTrailingQuote(withoutLeading,
|
|
498
|
-
};
|
|
499
|
-
var buildQuotedFields = (line, delimiter, quote, trim, lenient) => {
|
|
500
|
-
const pieces = dividePreserve(line, delimiter);
|
|
501
|
-
const state = {
|
|
502
|
-
fields: [],
|
|
503
|
-
current: "",
|
|
504
|
-
insideQuotes: false
|
|
505
|
-
};
|
|
506
|
-
for (const piece of pieces) {
|
|
507
|
-
appendPiece(state, piece, delimiter, quote, trim, lenient);
|
|
508
|
-
}
|
|
509
|
-
if (!isEmptyString(state.current)) {
|
|
510
|
-
flushField(state, quote, trim, lenient);
|
|
511
|
-
}
|
|
512
|
-
return state.fields;
|
|
491
|
+
const withoutLeading = removeQuoteAt(text, left, quote);
|
|
492
|
+
return stripTrailingQuote(withoutLeading, quote);
|
|
513
493
|
};
|
|
494
|
+
function stripOuterQuotes(text, quoteChar, { lenient = true } = {}) {
|
|
495
|
+
const stripped = stripOuterQuotesRaw(text, quoteChar, lenient);
|
|
496
|
+
if (quoteChar.length === 0) return stripped;
|
|
497
|
+
const escapedPair = quoteChar + quoteChar;
|
|
498
|
+
return stripped.split(escapedPair).join(quoteChar);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/utils/quoted-parser.ts
|
|
514
502
|
var advanceQuoteState = (insideQuotes, segment, quote) => {
|
|
515
503
|
let nextInsideQuotes = insideQuotes;
|
|
516
504
|
for (const char of segment) {
|
|
@@ -518,6 +506,13 @@ var advanceQuoteState = (insideQuotes, segment, quote) => {
|
|
|
518
506
|
}
|
|
519
507
|
return nextInsideQuotes;
|
|
520
508
|
};
|
|
509
|
+
var flushField = (state, quote, trim, lenient) => {
|
|
510
|
+
let fieldValue = stripOuterQuotes(state.current, quote, { lenient });
|
|
511
|
+
if (trim) fieldValue = fieldValue.trim();
|
|
512
|
+
state.fields.push(fieldValue);
|
|
513
|
+
state.current = "";
|
|
514
|
+
state.insideQuotes = false;
|
|
515
|
+
};
|
|
521
516
|
var appendPiece = (state, piece, delimiter, quote, trim, lenient) => {
|
|
522
517
|
const segment = isEmptyString(state.current) ? piece : delimiter + piece;
|
|
523
518
|
state.current += segment;
|
|
@@ -526,13 +521,30 @@ var appendPiece = (state, piece, delimiter, quote, trim, lenient) => {
|
|
|
526
521
|
flushField(state, quote, trim, lenient);
|
|
527
522
|
}
|
|
528
523
|
};
|
|
529
|
-
var
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
524
|
+
var buildQuotedFields = (line, delimiter, quote, trim, lenient) => {
|
|
525
|
+
const pieces = dividePreserve(line, delimiter);
|
|
526
|
+
const state = {
|
|
527
|
+
fields: [],
|
|
528
|
+
current: "",
|
|
529
|
+
insideQuotes: false
|
|
530
|
+
};
|
|
531
|
+
for (const piece of pieces) {
|
|
532
|
+
appendPiece(state, piece, delimiter, quote, trim, lenient);
|
|
533
|
+
}
|
|
534
|
+
if (!isEmptyString(state.current)) {
|
|
535
|
+
flushField(state, quote, trim, lenient);
|
|
536
|
+
}
|
|
537
|
+
return state.fields;
|
|
535
538
|
};
|
|
539
|
+
function quotedDivide(line, {
|
|
540
|
+
delimiter = ",",
|
|
541
|
+
quote = '"',
|
|
542
|
+
trim = false,
|
|
543
|
+
lenient = true
|
|
544
|
+
} = {}) {
|
|
545
|
+
if (isEmptyString(line)) return [""];
|
|
546
|
+
return buildQuotedFields(line, delimiter, quote, trim, lenient);
|
|
547
|
+
}
|
|
536
548
|
|
|
537
549
|
// src/presets/csv-divider.ts
|
|
538
550
|
function csvDivider(line, options = {}) {
|