@nyaomaru/divider 1.8.18 → 1.9.0
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/README.md +14 -2
- package/dist/index.cjs +121 -2
- package/dist/index.d.cts +51 -5
- package/dist/index.d.ts +51 -5
- package/dist/index.js +117 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -158,11 +158,11 @@ const result5 = dividerLoop('abcdefghij', 3, { maxChunks: 2 });
|
|
|
158
158
|
```ts
|
|
159
159
|
import { dividerNumberString } from '@nyaomaru/divider';
|
|
160
160
|
|
|
161
|
-
//
|
|
161
|
+
// Divide numbers and letters from a string
|
|
162
162
|
const result = dividerNumberString('abc123def456');
|
|
163
163
|
// ['abc', '123', 'def', '456']
|
|
164
164
|
|
|
165
|
-
//
|
|
165
|
+
// Divide each string in a string[]
|
|
166
166
|
const result2 = dividerNumberString(['abc123', '45z']);
|
|
167
167
|
// [['abc', '123'], ['45', 'z']]
|
|
168
168
|
|
|
@@ -171,6 +171,18 @@ const result3 = dividerNumberString(['abc123', '45z'], { flatten: true });
|
|
|
171
171
|
// ['abc', '123', '45', 'z']
|
|
172
172
|
```
|
|
173
173
|
|
|
174
|
+
### 📌 Presets
|
|
175
|
+
|
|
176
|
+
Some common use cases are wrapped as presets for convenience.
|
|
177
|
+
|
|
178
|
+
| Preset name | Description |
|
|
179
|
+
| -------------- | --------------------------------------------------------- |
|
|
180
|
+
| `emailDivider` | Divide email into [local-part, domain] (by '@') |
|
|
181
|
+
| `csvDivider` | Divide comma-separated strings, with quoted field support |
|
|
182
|
+
| `pathDivider` | Divide file paths by / or \| |
|
|
183
|
+
|
|
184
|
+
[Presets detail](src/presets/README.md)
|
|
185
|
+
|
|
174
186
|
## 🎯 General Options
|
|
175
187
|
|
|
176
188
|
| Option | Type | Default | Description |
|
package/dist/index.cjs
CHANGED
|
@@ -20,11 +20,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
csvDivider: () => csvDivider,
|
|
23
24
|
divider: () => divider,
|
|
24
25
|
dividerFirst: () => dividerFirst,
|
|
25
26
|
dividerLast: () => dividerLast,
|
|
26
27
|
dividerLoop: () => dividerLoop,
|
|
27
|
-
dividerNumberString: () => dividerNumberString
|
|
28
|
+
dividerNumberString: () => dividerNumberString,
|
|
29
|
+
emailDivider: () => emailDivider,
|
|
30
|
+
pathDivider: () => pathDivider
|
|
28
31
|
});
|
|
29
32
|
module.exports = __toCommonJS(index_exports);
|
|
30
33
|
|
|
@@ -46,6 +49,12 @@ var PERFORMANCE_CONSTANTS = {
|
|
|
46
49
|
DEFAULT_MAX_CHUNKS: 0
|
|
47
50
|
};
|
|
48
51
|
var CACHE_KEY_SEPARATOR = "\0";
|
|
52
|
+
var WHITE_SPACE = " ";
|
|
53
|
+
var TAB = " ";
|
|
54
|
+
var PATH_SEPARATORS = {
|
|
55
|
+
SLASH: "/",
|
|
56
|
+
ALT: "|"
|
|
57
|
+
};
|
|
49
58
|
|
|
50
59
|
// src/utils/is.ts
|
|
51
60
|
function isString(arg) {
|
|
@@ -362,11 +371,121 @@ function dividerNumberString(input, options) {
|
|
|
362
371
|
const result = isString(input) ? divideNumberString(input) : input.map(divideNumberString);
|
|
363
372
|
return applyDividerOptions(result, options ?? {});
|
|
364
373
|
}
|
|
374
|
+
|
|
375
|
+
// src/utils/quoted.ts
|
|
376
|
+
function dividePreserve(input, separator) {
|
|
377
|
+
if (input === "") return [""];
|
|
378
|
+
const divided = divider(input, separator);
|
|
379
|
+
return divided.join(separator) === input ? divided : input.split(separator);
|
|
380
|
+
}
|
|
381
|
+
function countUnescaped(text, quote) {
|
|
382
|
+
const pair = quote + quote;
|
|
383
|
+
let count = 0;
|
|
384
|
+
for (const chunk of dividePreserve(text, pair)) {
|
|
385
|
+
count += dividePreserve(chunk, quote).length - 1;
|
|
386
|
+
}
|
|
387
|
+
return count;
|
|
388
|
+
}
|
|
389
|
+
function stripOuterQuotes(text, quoteChar, { lenient = true } = {}) {
|
|
390
|
+
const escapedPair = quoteChar + quoteChar;
|
|
391
|
+
const isWhitespace = (char) => char === WHITE_SPACE || char === TAB;
|
|
392
|
+
const restoreEscapedQuotes = (fieldText) => fieldText.split(escapedPair).join(quoteChar);
|
|
393
|
+
let left = 0;
|
|
394
|
+
let right = text.length - 1;
|
|
395
|
+
while (left <= right && isWhitespace(text[left])) left++;
|
|
396
|
+
while (right >= left && isWhitespace(text[right])) right--;
|
|
397
|
+
if (left > right) return restoreEscapedQuotes(text);
|
|
398
|
+
const startsWithQuote = text[left] === quoteChar;
|
|
399
|
+
if (!startsWithQuote) return restoreEscapedQuotes(text);
|
|
400
|
+
const endsWithQuote = text[right] === quoteChar;
|
|
401
|
+
if (endsWithQuote && right > left) {
|
|
402
|
+
const withoutPair = text.slice(0, left) + text.slice(left + 1, right) + text.slice(right + 1);
|
|
403
|
+
return restoreEscapedQuotes(withoutPair);
|
|
404
|
+
}
|
|
405
|
+
if (!lenient) return restoreEscapedQuotes(text);
|
|
406
|
+
let result = text.slice(0, left) + text.slice(left + 1);
|
|
407
|
+
let lastNonSpaceIndexAfterTrim = result.length - 1;
|
|
408
|
+
while (lastNonSpaceIndexAfterTrim >= 0 && isWhitespace(result[lastNonSpaceIndexAfterTrim])) {
|
|
409
|
+
lastNonSpaceIndexAfterTrim--;
|
|
410
|
+
}
|
|
411
|
+
if (lastNonSpaceIndexAfterTrim >= 0 && result[lastNonSpaceIndexAfterTrim] === quoteChar) {
|
|
412
|
+
result = result.slice(0, lastNonSpaceIndexAfterTrim) + result.slice(lastNonSpaceIndexAfterTrim + 1);
|
|
413
|
+
}
|
|
414
|
+
return restoreEscapedQuotes(result);
|
|
415
|
+
}
|
|
416
|
+
function quotedDivide(line, {
|
|
417
|
+
delimiter = ",",
|
|
418
|
+
quote = '"',
|
|
419
|
+
trim = false,
|
|
420
|
+
lenient = true
|
|
421
|
+
} = {}) {
|
|
422
|
+
if (line === "") return [""];
|
|
423
|
+
const pieces = dividePreserve(line, delimiter);
|
|
424
|
+
const fields = [];
|
|
425
|
+
let currentFieldBuffer = "";
|
|
426
|
+
let insideQuotes = false;
|
|
427
|
+
const flush = () => {
|
|
428
|
+
let fieldValue = stripOuterQuotes(currentFieldBuffer, quote, { lenient });
|
|
429
|
+
if (trim) fieldValue = fieldValue.trim();
|
|
430
|
+
fields.push(fieldValue);
|
|
431
|
+
currentFieldBuffer = "";
|
|
432
|
+
};
|
|
433
|
+
for (const piece of pieces) {
|
|
434
|
+
currentFieldBuffer = currentFieldBuffer === "" ? piece : currentFieldBuffer + delimiter + piece;
|
|
435
|
+
insideQuotes = countUnescaped(currentFieldBuffer, quote) % 2 === 1;
|
|
436
|
+
if (!insideQuotes) flush();
|
|
437
|
+
}
|
|
438
|
+
if (currentFieldBuffer !== "") flush();
|
|
439
|
+
return fields;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// src/presets/csv-divider.ts
|
|
443
|
+
function csvDivider(line, options = {}) {
|
|
444
|
+
const { delimiter = ",", quoteChar = '"', trim = false } = options;
|
|
445
|
+
return quotedDivide(line, {
|
|
446
|
+
delimiter,
|
|
447
|
+
quote: quoteChar,
|
|
448
|
+
trim,
|
|
449
|
+
lenient: true
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// src/presets/email-divider.ts
|
|
454
|
+
var MAX_EMAIL_PARTS = 2;
|
|
455
|
+
function emailDivider(input, options = {}) {
|
|
456
|
+
const { splitTLD, ...dividerOptions } = options;
|
|
457
|
+
const result = divider(input, "@", dividerOptions);
|
|
458
|
+
if (result.length > MAX_EMAIL_PARTS) {
|
|
459
|
+
console.warn(
|
|
460
|
+
`[divider/emailDivider] Too many "@" symbols in "${input}". Expected at most one.`
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
if (splitTLD && result.length === MAX_EMAIL_PARTS) {
|
|
464
|
+
const [local, domain] = result;
|
|
465
|
+
const domainParts = divider(domain, ".", dividerOptions);
|
|
466
|
+
return [local, ...domainParts];
|
|
467
|
+
}
|
|
468
|
+
return result;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/presets/path-divider.ts
|
|
472
|
+
function pathDivider(input, options = {}) {
|
|
473
|
+
const { trim = false, collapse = true } = options;
|
|
474
|
+
if (input === "") return [""];
|
|
475
|
+
const segments = collapse ? divider(input, PATH_SEPARATORS.SLASH, PATH_SEPARATORS.ALT) : dividePreserve(input, PATH_SEPARATORS.ALT).flatMap(
|
|
476
|
+
(part) => dividePreserve(part, PATH_SEPARATORS.SLASH)
|
|
477
|
+
);
|
|
478
|
+
const maybeTrimmed = trim ? segments.map((segment) => segment.trim()) : segments;
|
|
479
|
+
return collapse ? maybeTrimmed.filter((segment) => segment !== "") : maybeTrimmed;
|
|
480
|
+
}
|
|
365
481
|
// Annotate the CommonJS export names for ESM import in node:
|
|
366
482
|
0 && (module.exports = {
|
|
483
|
+
csvDivider,
|
|
367
484
|
divider,
|
|
368
485
|
dividerFirst,
|
|
369
486
|
dividerLast,
|
|
370
487
|
dividerLoop,
|
|
371
|
-
dividerNumberString
|
|
488
|
+
dividerNumberString,
|
|
489
|
+
emailDivider,
|
|
490
|
+
pathDivider
|
|
372
491
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -21,20 +21,20 @@ type DividerInput = StringInput | StringArrayInput;
|
|
|
21
21
|
type DividerStringResult = string[];
|
|
22
22
|
type DividerArrayResult = string[][];
|
|
23
23
|
type DividerResult<T extends DividerInput> = T extends StringInput ? DividerStringResult : DividerArrayResult;
|
|
24
|
-
|
|
24
|
+
type DividerOptions = {
|
|
25
25
|
/** If true, flattens nested arrays into a single array */
|
|
26
26
|
flatten?: boolean;
|
|
27
27
|
/** If true, trims whitespace from each divided segment */
|
|
28
28
|
trim?: boolean;
|
|
29
29
|
/** Controls how empty or whitespace segments are handled */
|
|
30
30
|
exclude?: DividerExcludeMode;
|
|
31
|
-
}
|
|
32
|
-
|
|
31
|
+
};
|
|
32
|
+
type DividerLoopOptions = DividerOptions & {
|
|
33
33
|
/** Starting position for the division (0-based) */
|
|
34
34
|
startOffset?: number;
|
|
35
35
|
/** Maximum number of chunks to produce */
|
|
36
36
|
maxChunks?: number;
|
|
37
|
-
}
|
|
37
|
+
};
|
|
38
38
|
type NumericSeparator = number;
|
|
39
39
|
type StringSeparator = string;
|
|
40
40
|
type DividerSeparator = NumericSeparator | StringSeparator;
|
|
@@ -115,4 +115,50 @@ declare function dividerLoop<T extends string | string[]>(input: T, size: number
|
|
|
115
115
|
*/
|
|
116
116
|
declare function dividerNumberString<T extends string | string[]>(input: T, options?: DividerOptions): DividerResult<T>;
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
type EmailDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
119
|
+
/** Split top-level domain from the rest of the email address. */
|
|
120
|
+
splitTLD?: boolean;
|
|
121
|
+
};
|
|
122
|
+
type CsvDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
123
|
+
/** Character used for quoting values. */
|
|
124
|
+
quoteChar?: string;
|
|
125
|
+
/** Character used to separate CSV fields. */
|
|
126
|
+
delimiter?: string;
|
|
127
|
+
};
|
|
128
|
+
type PathDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
129
|
+
/** Collapse empty segments produced by leading/trailing or repeated separators. */
|
|
130
|
+
collapse?: boolean;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Divides a CSV line into an array of fields, handling quoted values appropriately.
|
|
135
|
+
*
|
|
136
|
+
* @param line - The CSV line string to be divided into fields
|
|
137
|
+
* @param options - Configuration options for CSV parsing
|
|
138
|
+
* @param options.delimiter - The character used to separate fields (default: ',')
|
|
139
|
+
* @param options.quoteChar - The character used to quote fields containing delimiters or newlines (default: '"')
|
|
140
|
+
* @param options.trim - Whether to trim whitespace from field values (default: false)
|
|
141
|
+
* @returns A DividerStringResult containing the parsed CSV fields
|
|
142
|
+
*/
|
|
143
|
+
declare function csvDivider(line: string, options?: CsvDividerOptions): DividerStringResult;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Divides an email address string at the "@" symbol into its local and domain parts.
|
|
147
|
+
*
|
|
148
|
+
* @param input - The email address string to divide
|
|
149
|
+
* @param options - Optional configuration for the divider operation
|
|
150
|
+
* @returns A DividerStringResult containing the divided parts of the email address
|
|
151
|
+
*/
|
|
152
|
+
declare function emailDivider(input: string, options?: EmailDividerOptions): DividerStringResult;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Divides a path string into segments using path separators.
|
|
156
|
+
* @param input - The path string to divide
|
|
157
|
+
* @param options - Configuration options for path division
|
|
158
|
+
* @param options.trim - Whether to trim whitespace from segments
|
|
159
|
+
* @param options.collapse - Whether to collapse consecutive separators and filter empty segments
|
|
160
|
+
* @returns Array of path segments
|
|
161
|
+
*/
|
|
162
|
+
declare function pathDivider(input: string, options?: PathDividerOptions): DividerStringResult;
|
|
163
|
+
|
|
164
|
+
export { type DividerArgs, type DividerArrayResult, type DividerExcludeMode, type DividerInput, type DividerLoopOptions, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,20 +21,20 @@ type DividerInput = StringInput | StringArrayInput;
|
|
|
21
21
|
type DividerStringResult = string[];
|
|
22
22
|
type DividerArrayResult = string[][];
|
|
23
23
|
type DividerResult<T extends DividerInput> = T extends StringInput ? DividerStringResult : DividerArrayResult;
|
|
24
|
-
|
|
24
|
+
type DividerOptions = {
|
|
25
25
|
/** If true, flattens nested arrays into a single array */
|
|
26
26
|
flatten?: boolean;
|
|
27
27
|
/** If true, trims whitespace from each divided segment */
|
|
28
28
|
trim?: boolean;
|
|
29
29
|
/** Controls how empty or whitespace segments are handled */
|
|
30
30
|
exclude?: DividerExcludeMode;
|
|
31
|
-
}
|
|
32
|
-
|
|
31
|
+
};
|
|
32
|
+
type DividerLoopOptions = DividerOptions & {
|
|
33
33
|
/** Starting position for the division (0-based) */
|
|
34
34
|
startOffset?: number;
|
|
35
35
|
/** Maximum number of chunks to produce */
|
|
36
36
|
maxChunks?: number;
|
|
37
|
-
}
|
|
37
|
+
};
|
|
38
38
|
type NumericSeparator = number;
|
|
39
39
|
type StringSeparator = string;
|
|
40
40
|
type DividerSeparator = NumericSeparator | StringSeparator;
|
|
@@ -115,4 +115,50 @@ declare function dividerLoop<T extends string | string[]>(input: T, size: number
|
|
|
115
115
|
*/
|
|
116
116
|
declare function dividerNumberString<T extends string | string[]>(input: T, options?: DividerOptions): DividerResult<T>;
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
type EmailDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
119
|
+
/** Split top-level domain from the rest of the email address. */
|
|
120
|
+
splitTLD?: boolean;
|
|
121
|
+
};
|
|
122
|
+
type CsvDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
123
|
+
/** Character used for quoting values. */
|
|
124
|
+
quoteChar?: string;
|
|
125
|
+
/** Character used to separate CSV fields. */
|
|
126
|
+
delimiter?: string;
|
|
127
|
+
};
|
|
128
|
+
type PathDividerOptions = Pick<DividerOptions, 'trim'> & {
|
|
129
|
+
/** Collapse empty segments produced by leading/trailing or repeated separators. */
|
|
130
|
+
collapse?: boolean;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Divides a CSV line into an array of fields, handling quoted values appropriately.
|
|
135
|
+
*
|
|
136
|
+
* @param line - The CSV line string to be divided into fields
|
|
137
|
+
* @param options - Configuration options for CSV parsing
|
|
138
|
+
* @param options.delimiter - The character used to separate fields (default: ',')
|
|
139
|
+
* @param options.quoteChar - The character used to quote fields containing delimiters or newlines (default: '"')
|
|
140
|
+
* @param options.trim - Whether to trim whitespace from field values (default: false)
|
|
141
|
+
* @returns A DividerStringResult containing the parsed CSV fields
|
|
142
|
+
*/
|
|
143
|
+
declare function csvDivider(line: string, options?: CsvDividerOptions): DividerStringResult;
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Divides an email address string at the "@" symbol into its local and domain parts.
|
|
147
|
+
*
|
|
148
|
+
* @param input - The email address string to divide
|
|
149
|
+
* @param options - Optional configuration for the divider operation
|
|
150
|
+
* @returns A DividerStringResult containing the divided parts of the email address
|
|
151
|
+
*/
|
|
152
|
+
declare function emailDivider(input: string, options?: EmailDividerOptions): DividerStringResult;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Divides a path string into segments using path separators.
|
|
156
|
+
* @param input - The path string to divide
|
|
157
|
+
* @param options - Configuration options for path division
|
|
158
|
+
* @param options.trim - Whether to trim whitespace from segments
|
|
159
|
+
* @param options.collapse - Whether to collapse consecutive separators and filter empty segments
|
|
160
|
+
* @returns Array of path segments
|
|
161
|
+
*/
|
|
162
|
+
declare function pathDivider(input: string, options?: PathDividerOptions): DividerStringResult;
|
|
163
|
+
|
|
164
|
+
export { type DividerArgs, type DividerArrayResult, type DividerExcludeMode, type DividerInput, type DividerLoopOptions, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider };
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,12 @@ var PERFORMANCE_CONSTANTS = {
|
|
|
16
16
|
DEFAULT_MAX_CHUNKS: 0
|
|
17
17
|
};
|
|
18
18
|
var CACHE_KEY_SEPARATOR = "\0";
|
|
19
|
+
var WHITE_SPACE = " ";
|
|
20
|
+
var TAB = " ";
|
|
21
|
+
var PATH_SEPARATORS = {
|
|
22
|
+
SLASH: "/",
|
|
23
|
+
ALT: "|"
|
|
24
|
+
};
|
|
19
25
|
|
|
20
26
|
// src/utils/is.ts
|
|
21
27
|
function isString(arg) {
|
|
@@ -332,10 +338,120 @@ function dividerNumberString(input, options) {
|
|
|
332
338
|
const result = isString(input) ? divideNumberString(input) : input.map(divideNumberString);
|
|
333
339
|
return applyDividerOptions(result, options ?? {});
|
|
334
340
|
}
|
|
341
|
+
|
|
342
|
+
// src/utils/quoted.ts
|
|
343
|
+
function dividePreserve(input, separator) {
|
|
344
|
+
if (input === "") return [""];
|
|
345
|
+
const divided = divider(input, separator);
|
|
346
|
+
return divided.join(separator) === input ? divided : input.split(separator);
|
|
347
|
+
}
|
|
348
|
+
function countUnescaped(text, quote) {
|
|
349
|
+
const pair = quote + quote;
|
|
350
|
+
let count = 0;
|
|
351
|
+
for (const chunk of dividePreserve(text, pair)) {
|
|
352
|
+
count += dividePreserve(chunk, quote).length - 1;
|
|
353
|
+
}
|
|
354
|
+
return count;
|
|
355
|
+
}
|
|
356
|
+
function stripOuterQuotes(text, quoteChar, { lenient = true } = {}) {
|
|
357
|
+
const escapedPair = quoteChar + quoteChar;
|
|
358
|
+
const isWhitespace = (char) => char === WHITE_SPACE || char === TAB;
|
|
359
|
+
const restoreEscapedQuotes = (fieldText) => fieldText.split(escapedPair).join(quoteChar);
|
|
360
|
+
let left = 0;
|
|
361
|
+
let right = text.length - 1;
|
|
362
|
+
while (left <= right && isWhitespace(text[left])) left++;
|
|
363
|
+
while (right >= left && isWhitespace(text[right])) right--;
|
|
364
|
+
if (left > right) return restoreEscapedQuotes(text);
|
|
365
|
+
const startsWithQuote = text[left] === quoteChar;
|
|
366
|
+
if (!startsWithQuote) return restoreEscapedQuotes(text);
|
|
367
|
+
const endsWithQuote = text[right] === quoteChar;
|
|
368
|
+
if (endsWithQuote && right > left) {
|
|
369
|
+
const withoutPair = text.slice(0, left) + text.slice(left + 1, right) + text.slice(right + 1);
|
|
370
|
+
return restoreEscapedQuotes(withoutPair);
|
|
371
|
+
}
|
|
372
|
+
if (!lenient) return restoreEscapedQuotes(text);
|
|
373
|
+
let result = text.slice(0, left) + text.slice(left + 1);
|
|
374
|
+
let lastNonSpaceIndexAfterTrim = result.length - 1;
|
|
375
|
+
while (lastNonSpaceIndexAfterTrim >= 0 && isWhitespace(result[lastNonSpaceIndexAfterTrim])) {
|
|
376
|
+
lastNonSpaceIndexAfterTrim--;
|
|
377
|
+
}
|
|
378
|
+
if (lastNonSpaceIndexAfterTrim >= 0 && result[lastNonSpaceIndexAfterTrim] === quoteChar) {
|
|
379
|
+
result = result.slice(0, lastNonSpaceIndexAfterTrim) + result.slice(lastNonSpaceIndexAfterTrim + 1);
|
|
380
|
+
}
|
|
381
|
+
return restoreEscapedQuotes(result);
|
|
382
|
+
}
|
|
383
|
+
function quotedDivide(line, {
|
|
384
|
+
delimiter = ",",
|
|
385
|
+
quote = '"',
|
|
386
|
+
trim = false,
|
|
387
|
+
lenient = true
|
|
388
|
+
} = {}) {
|
|
389
|
+
if (line === "") return [""];
|
|
390
|
+
const pieces = dividePreserve(line, delimiter);
|
|
391
|
+
const fields = [];
|
|
392
|
+
let currentFieldBuffer = "";
|
|
393
|
+
let insideQuotes = false;
|
|
394
|
+
const flush = () => {
|
|
395
|
+
let fieldValue = stripOuterQuotes(currentFieldBuffer, quote, { lenient });
|
|
396
|
+
if (trim) fieldValue = fieldValue.trim();
|
|
397
|
+
fields.push(fieldValue);
|
|
398
|
+
currentFieldBuffer = "";
|
|
399
|
+
};
|
|
400
|
+
for (const piece of pieces) {
|
|
401
|
+
currentFieldBuffer = currentFieldBuffer === "" ? piece : currentFieldBuffer + delimiter + piece;
|
|
402
|
+
insideQuotes = countUnescaped(currentFieldBuffer, quote) % 2 === 1;
|
|
403
|
+
if (!insideQuotes) flush();
|
|
404
|
+
}
|
|
405
|
+
if (currentFieldBuffer !== "") flush();
|
|
406
|
+
return fields;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// src/presets/csv-divider.ts
|
|
410
|
+
function csvDivider(line, options = {}) {
|
|
411
|
+
const { delimiter = ",", quoteChar = '"', trim = false } = options;
|
|
412
|
+
return quotedDivide(line, {
|
|
413
|
+
delimiter,
|
|
414
|
+
quote: quoteChar,
|
|
415
|
+
trim,
|
|
416
|
+
lenient: true
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/presets/email-divider.ts
|
|
421
|
+
var MAX_EMAIL_PARTS = 2;
|
|
422
|
+
function emailDivider(input, options = {}) {
|
|
423
|
+
const { splitTLD, ...dividerOptions } = options;
|
|
424
|
+
const result = divider(input, "@", dividerOptions);
|
|
425
|
+
if (result.length > MAX_EMAIL_PARTS) {
|
|
426
|
+
console.warn(
|
|
427
|
+
`[divider/emailDivider] Too many "@" symbols in "${input}". Expected at most one.`
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
if (splitTLD && result.length === MAX_EMAIL_PARTS) {
|
|
431
|
+
const [local, domain] = result;
|
|
432
|
+
const domainParts = divider(domain, ".", dividerOptions);
|
|
433
|
+
return [local, ...domainParts];
|
|
434
|
+
}
|
|
435
|
+
return result;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// src/presets/path-divider.ts
|
|
439
|
+
function pathDivider(input, options = {}) {
|
|
440
|
+
const { trim = false, collapse = true } = options;
|
|
441
|
+
if (input === "") return [""];
|
|
442
|
+
const segments = collapse ? divider(input, PATH_SEPARATORS.SLASH, PATH_SEPARATORS.ALT) : dividePreserve(input, PATH_SEPARATORS.ALT).flatMap(
|
|
443
|
+
(part) => dividePreserve(part, PATH_SEPARATORS.SLASH)
|
|
444
|
+
);
|
|
445
|
+
const maybeTrimmed = trim ? segments.map((segment) => segment.trim()) : segments;
|
|
446
|
+
return collapse ? maybeTrimmed.filter((segment) => segment !== "") : maybeTrimmed;
|
|
447
|
+
}
|
|
335
448
|
export {
|
|
449
|
+
csvDivider,
|
|
336
450
|
divider,
|
|
337
451
|
dividerFirst,
|
|
338
452
|
dividerLast,
|
|
339
453
|
dividerLoop,
|
|
340
|
-
dividerNumberString
|
|
454
|
+
dividerNumberString,
|
|
455
|
+
emailDivider,
|
|
456
|
+
pathDivider
|
|
341
457
|
};
|