@nyaomaru/divider 1.9.11 → 1.9.13

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  # Divider
2
2
 
3
3
  <p align="center">
4
- <img src="https://raw.githubusercontent.com/nyaomaru/divider/main/logo.svg" width="200px" align="center" alt="Divider logo" />
4
+ <img src="https://raw.githubusercontent.com/nyaomaru/divider/main/divider_image.png" width="600px" align="center" alt="Divider logo" />
5
5
  </p>
6
6
 
7
7
  <p align="center">
package/dist/index.cjs CHANGED
@@ -234,7 +234,7 @@ function divideString(input, numSeparators, strSeparators, options) {
234
234
  const sortedNumSeparators = sortAscending(numSeparators);
235
235
  const parts = sliceByIndexes(input, sortedNumSeparators);
236
236
  const segments = regex ? parts.flatMap((part) => part.split(regex)) : parts;
237
- return shouldPreserveEmpty ? segments : segments.filter((segment) => segment !== "");
237
+ return shouldPreserveEmpty ? segments : segments.filter((segment) => !isEmptyString(segment));
238
238
  }
239
239
 
240
240
  // src/utils/array.ts
@@ -268,7 +268,7 @@ function extractOptions(args) {
268
268
  }
269
269
  function trimSegments(segments, preserveEmpty) {
270
270
  const trimmed = segments.map((segment) => segment.trim());
271
- return preserveEmpty ? trimmed : trimmed.filter((segment) => segment !== "");
271
+ return preserveEmpty ? trimmed : trimmed.filter((segment) => !isEmptyString(segment));
272
272
  }
273
273
  function trimNestedSegments(rows, preserveEmpty) {
274
274
  return rows.map((row) => trimSegments(row, preserveEmpty));
@@ -327,7 +327,10 @@ function divider(input, ...args) {
327
327
  preserveEmpty: options.preserveEmpty
328
328
  });
329
329
  const result = isString(input) ? applyDivision(input) : input.map(applyDivision);
330
- return applyDividerOptions(result, options);
330
+ return applyDividerOptions(
331
+ result,
332
+ options
333
+ );
331
334
  }
332
335
 
333
336
  // src/core/divider-first.ts
@@ -378,15 +381,15 @@ function dividerLoop(input, size, options) {
378
381
  console.warn("dividerLoop: chunk size must be a positive number");
379
382
  return [];
380
383
  }
381
- const finalOptions = options ?? {};
384
+ const resolvedOptions = options ?? {};
382
385
  const {
383
386
  startOffset = PERFORMANCE_CONSTANTS.DEFAULT_START_OFFSET,
384
387
  maxChunks = PERFORMANCE_CONSTANTS.DEFAULT_MAX_CHUNKS
385
- } = finalOptions;
388
+ } = resolvedOptions;
386
389
  const result = isString(input) ? createChunksFromString(input, size, startOffset, maxChunks) : input.map(
387
390
  (str) => createChunksFromString(str, size, startOffset, maxChunks)
388
391
  );
389
- return applyDividerOptions(result, finalOptions);
392
+ return applyDividerOptions(result, resolvedOptions);
390
393
  }
391
394
 
392
395
  // src/utils/divide.ts
@@ -397,7 +400,8 @@ function divideNumberString(str) {
397
400
  // src/core/divider-number-string.ts
398
401
  function dividerNumberString(input, options) {
399
402
  const result = isString(input) ? divideNumberString(input) : input.map(divideNumberString);
400
- return applyDividerOptions(result, options ?? {});
403
+ const resolvedOptions = options ?? {};
404
+ return applyDividerOptions(result, resolvedOptions);
401
405
  }
402
406
 
403
407
  // src/utils/quoted.ts
@@ -459,11 +463,11 @@ function quotedDivide(line, {
459
463
  currentFieldBuffer = "";
460
464
  };
461
465
  for (const piece of pieces) {
462
- currentFieldBuffer = currentFieldBuffer === "" ? piece : currentFieldBuffer + delimiter + piece;
466
+ currentFieldBuffer = isEmptyString(currentFieldBuffer) ? piece : currentFieldBuffer + delimiter + piece;
463
467
  insideQuotes = countUnescaped(currentFieldBuffer, quote) % 2 === 1;
464
468
  if (!insideQuotes) flush();
465
469
  }
466
- if (currentFieldBuffer !== "") flush();
470
+ if (!isEmptyString(currentFieldBuffer)) flush();
467
471
  return fields;
468
472
  }
469
473
 
@@ -499,12 +503,12 @@ function emailDivider(input, options = {}) {
499
503
  // src/presets/path-divider.ts
500
504
  function pathDivider(input, options = {}) {
501
505
  const { trim = false, collapse = true } = options;
502
- if (input === "") return [""];
506
+ if (isEmptyString(input)) return [""];
503
507
  const segments = collapse ? divider(input, PATH_SEPARATORS.SLASH, PATH_SEPARATORS.ALT) : dividePreserve(input, PATH_SEPARATORS.ALT).flatMap(
504
508
  (part) => dividePreserve(part, PATH_SEPARATORS.SLASH)
505
509
  );
506
510
  const maybeTrimmed = trim ? segments.map((segment) => segment.trim()) : segments;
507
- return collapse ? maybeTrimmed.filter((segment) => segment !== "") : maybeTrimmed;
511
+ return collapse ? maybeTrimmed.filter((segment) => !isEmptyString(segment)) : maybeTrimmed;
508
512
  }
509
513
  // Annotate the CommonJS export names for ESM import in node:
510
514
  0 && (module.exports = {
package/dist/index.d.cts CHANGED
@@ -20,7 +20,6 @@ type StringArrayInput = readonly string[];
20
20
  type DividerInput = StringInput | StringArrayInput;
21
21
  type DividerStringResult = string[];
22
22
  type DividerArrayResult = string[][];
23
- type DividerResult<T extends DividerInput> = T extends StringInput ? DividerStringResult : DividerArrayResult;
24
23
  type DividerOptions = {
25
24
  /** If true, flattens nested arrays into a single array */
26
25
  flatten?: boolean;
@@ -31,17 +30,43 @@ type DividerOptions = {
31
30
  /** Controls how empty or whitespace segments are handled */
32
31
  exclude?: DividerExcludeMode;
33
32
  };
33
+ /**
34
+ * Represents the absence of user-specified divider options while retaining
35
+ * property knowledge for conditional typing.
36
+ */
37
+ type DividerEmptyOptions = {
38
+ /** Explicitly omits flatten while preserving literal inference */
39
+ readonly flatten?: never;
40
+ /** Explicitly omits trim while preserving literal inference */
41
+ readonly trim?: never;
42
+ /** Explicitly omits preserveEmpty while preserving literal inference */
43
+ readonly preserveEmpty?: never;
44
+ /** Explicitly omits exclude while preserving literal inference */
45
+ readonly exclude?: never;
46
+ };
47
+ type DividerInferredOptions = DividerOptions | DividerEmptyOptions;
48
+ type HasFlattenOption<TOptions extends DividerInferredOptions> = TOptions extends {
49
+ readonly flatten?: infer Flag;
50
+ } ? Flag extends true ? true : false : false;
51
+ type DividerResult<T extends DividerInput, TOptions extends DividerInferredOptions = DividerEmptyOptions> = T extends StringInput ? DividerStringResult : HasFlattenOption<TOptions> extends true ? DividerStringResult : DividerArrayResult;
52
+ type ExtractedDividerOptions<TArgs extends readonly (string | number | DividerOptions)[]> = TArgs extends readonly [...infer _Rest, infer Last] ? Last extends DividerOptions ? Last : DividerEmptyOptions : DividerEmptyOptions;
34
53
  type DividerLoopOptions = DividerOptions & {
35
54
  /** Starting position for the division (0-based) */
36
55
  startOffset?: number;
37
56
  /** Maximum number of chunks to produce */
38
57
  maxChunks?: number;
39
58
  };
59
+ type DividerLoopEmptyOptions = DividerEmptyOptions & {
60
+ /** Placeholder to signal startOffset is intentionally absent */
61
+ readonly startOffset?: never;
62
+ /** Placeholder to signal maxChunks is intentionally absent */
63
+ readonly maxChunks?: never;
64
+ };
65
+ type DividerLoopOptionsLike = DividerLoopOptions | DividerLoopEmptyOptions;
40
66
  type NumericSeparator = number;
41
67
  type StringSeparator = string;
42
68
  type DividerSeparator = NumericSeparator | StringSeparator;
43
69
  type DividerSeparators = DividerSeparator[];
44
- type DividerArgs = DividerSeparators | [...DividerSeparators, DividerOptions];
45
70
 
46
71
  /**
47
72
  * Main divider function that splits input based on numeric positions or string delimiters.
@@ -55,7 +80,7 @@ type DividerArgs = DividerSeparators | [...DividerSeparators, DividerOptions];
55
80
  * @param args - Array of separators (numbers/strings) and optional options object
56
81
  * @returns Divided string segments based on input type and options
57
82
  */
58
- declare function divider<T extends DividerInput>(input: T, ...args: DividerArgs): DividerResult<T>;
83
+ declare function divider<T extends DividerInput, const TArgs extends readonly (DividerSeparator | DividerOptions)[]>(input: T, ...args: TArgs): DividerResult<T, ExtractedDividerOptions<TArgs>>;
59
84
 
60
85
  /**
61
86
  * Extracts the first segment after dividing the input using specified separators.
@@ -100,7 +125,7 @@ declare function dividerLast(input: DividerInput, ...args: DividerSeparators): s
100
125
  * dividerLoop("abcdef", 2) // returns ["ab", "cd", "ef"]
101
126
  * dividerLoop("abcdef", 2, { maxChunks: 2 }) // returns ["ab", "cdef"]
102
127
  */
103
- declare function dividerLoop<T extends DividerInput>(input: T, size: number, options?: DividerLoopOptions): DividerResult<T>;
128
+ declare function dividerLoop<T extends DividerInput, O extends DividerLoopOptionsLike = DividerLoopEmptyOptions>(input: T, size: number, options?: O): DividerResult<T, O>;
104
129
 
105
130
  /**
106
131
  * Divides a string or array of strings by separating numbers from non-numbers.
@@ -115,7 +140,7 @@ declare function dividerLoop<T extends DividerInput>(input: T, size: number, opt
115
140
  * dividerNumberString("abc123def") // returns ["abc", "123", "def"]
116
141
  * dividerNumberString("test42") // returns ["test", "42"]
117
142
  */
118
- declare function dividerNumberString<T extends DividerInput>(input: T, options?: DividerOptions): DividerResult<T>;
143
+ declare function dividerNumberString<T extends DividerInput, O extends DividerInferredOptions = DividerEmptyOptions>(input: T, options?: O): DividerResult<T, O>;
119
144
 
120
145
  type EmailDividerOptions = Pick<DividerOptions, 'trim'> & {
121
146
  /** Split top-level domain from the rest of the email address. */
@@ -163,4 +188,4 @@ declare function emailDivider(input: string, options?: EmailDividerOptions): Div
163
188
  */
164
189
  declare function pathDivider(input: string, options?: PathDividerOptions): DividerStringResult;
165
190
 
166
- 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 };
191
+ export { type DividerArrayResult, type DividerEmptyOptions, type DividerExcludeMode, type DividerInferredOptions, type DividerInput, type DividerLoopEmptyOptions, type DividerLoopOptions, type DividerLoopOptionsLike, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type ExtractedDividerOptions, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider };
package/dist/index.d.ts CHANGED
@@ -20,7 +20,6 @@ type StringArrayInput = readonly string[];
20
20
  type DividerInput = StringInput | StringArrayInput;
21
21
  type DividerStringResult = string[];
22
22
  type DividerArrayResult = string[][];
23
- type DividerResult<T extends DividerInput> = T extends StringInput ? DividerStringResult : DividerArrayResult;
24
23
  type DividerOptions = {
25
24
  /** If true, flattens nested arrays into a single array */
26
25
  flatten?: boolean;
@@ -31,17 +30,43 @@ type DividerOptions = {
31
30
  /** Controls how empty or whitespace segments are handled */
32
31
  exclude?: DividerExcludeMode;
33
32
  };
33
+ /**
34
+ * Represents the absence of user-specified divider options while retaining
35
+ * property knowledge for conditional typing.
36
+ */
37
+ type DividerEmptyOptions = {
38
+ /** Explicitly omits flatten while preserving literal inference */
39
+ readonly flatten?: never;
40
+ /** Explicitly omits trim while preserving literal inference */
41
+ readonly trim?: never;
42
+ /** Explicitly omits preserveEmpty while preserving literal inference */
43
+ readonly preserveEmpty?: never;
44
+ /** Explicitly omits exclude while preserving literal inference */
45
+ readonly exclude?: never;
46
+ };
47
+ type DividerInferredOptions = DividerOptions | DividerEmptyOptions;
48
+ type HasFlattenOption<TOptions extends DividerInferredOptions> = TOptions extends {
49
+ readonly flatten?: infer Flag;
50
+ } ? Flag extends true ? true : false : false;
51
+ type DividerResult<T extends DividerInput, TOptions extends DividerInferredOptions = DividerEmptyOptions> = T extends StringInput ? DividerStringResult : HasFlattenOption<TOptions> extends true ? DividerStringResult : DividerArrayResult;
52
+ type ExtractedDividerOptions<TArgs extends readonly (string | number | DividerOptions)[]> = TArgs extends readonly [...infer _Rest, infer Last] ? Last extends DividerOptions ? Last : DividerEmptyOptions : DividerEmptyOptions;
34
53
  type DividerLoopOptions = DividerOptions & {
35
54
  /** Starting position for the division (0-based) */
36
55
  startOffset?: number;
37
56
  /** Maximum number of chunks to produce */
38
57
  maxChunks?: number;
39
58
  };
59
+ type DividerLoopEmptyOptions = DividerEmptyOptions & {
60
+ /** Placeholder to signal startOffset is intentionally absent */
61
+ readonly startOffset?: never;
62
+ /** Placeholder to signal maxChunks is intentionally absent */
63
+ readonly maxChunks?: never;
64
+ };
65
+ type DividerLoopOptionsLike = DividerLoopOptions | DividerLoopEmptyOptions;
40
66
  type NumericSeparator = number;
41
67
  type StringSeparator = string;
42
68
  type DividerSeparator = NumericSeparator | StringSeparator;
43
69
  type DividerSeparators = DividerSeparator[];
44
- type DividerArgs = DividerSeparators | [...DividerSeparators, DividerOptions];
45
70
 
46
71
  /**
47
72
  * Main divider function that splits input based on numeric positions or string delimiters.
@@ -55,7 +80,7 @@ type DividerArgs = DividerSeparators | [...DividerSeparators, DividerOptions];
55
80
  * @param args - Array of separators (numbers/strings) and optional options object
56
81
  * @returns Divided string segments based on input type and options
57
82
  */
58
- declare function divider<T extends DividerInput>(input: T, ...args: DividerArgs): DividerResult<T>;
83
+ declare function divider<T extends DividerInput, const TArgs extends readonly (DividerSeparator | DividerOptions)[]>(input: T, ...args: TArgs): DividerResult<T, ExtractedDividerOptions<TArgs>>;
59
84
 
60
85
  /**
61
86
  * Extracts the first segment after dividing the input using specified separators.
@@ -100,7 +125,7 @@ declare function dividerLast(input: DividerInput, ...args: DividerSeparators): s
100
125
  * dividerLoop("abcdef", 2) // returns ["ab", "cd", "ef"]
101
126
  * dividerLoop("abcdef", 2, { maxChunks: 2 }) // returns ["ab", "cdef"]
102
127
  */
103
- declare function dividerLoop<T extends DividerInput>(input: T, size: number, options?: DividerLoopOptions): DividerResult<T>;
128
+ declare function dividerLoop<T extends DividerInput, O extends DividerLoopOptionsLike = DividerLoopEmptyOptions>(input: T, size: number, options?: O): DividerResult<T, O>;
104
129
 
105
130
  /**
106
131
  * Divides a string or array of strings by separating numbers from non-numbers.
@@ -115,7 +140,7 @@ declare function dividerLoop<T extends DividerInput>(input: T, size: number, opt
115
140
  * dividerNumberString("abc123def") // returns ["abc", "123", "def"]
116
141
  * dividerNumberString("test42") // returns ["test", "42"]
117
142
  */
118
- declare function dividerNumberString<T extends DividerInput>(input: T, options?: DividerOptions): DividerResult<T>;
143
+ declare function dividerNumberString<T extends DividerInput, O extends DividerInferredOptions = DividerEmptyOptions>(input: T, options?: O): DividerResult<T, O>;
119
144
 
120
145
  type EmailDividerOptions = Pick<DividerOptions, 'trim'> & {
121
146
  /** Split top-level domain from the rest of the email address. */
@@ -163,4 +188,4 @@ declare function emailDivider(input: string, options?: EmailDividerOptions): Div
163
188
  */
164
189
  declare function pathDivider(input: string, options?: PathDividerOptions): DividerStringResult;
165
190
 
166
- 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 };
191
+ export { type DividerArrayResult, type DividerEmptyOptions, type DividerExcludeMode, type DividerInferredOptions, type DividerInput, type DividerLoopEmptyOptions, type DividerLoopOptions, type DividerLoopOptionsLike, type DividerOptions, type DividerResult, type DividerSeparator, type DividerSeparators, type DividerStringResult, type ExtractedDividerOptions, type NumericSeparator, type StringArrayInput, type StringInput, type StringSeparator, csvDivider, divider, dividerFirst, dividerLast, dividerLoop, dividerNumberString, emailDivider, pathDivider };
package/dist/index.js CHANGED
@@ -201,7 +201,7 @@ function divideString(input, numSeparators, strSeparators, options) {
201
201
  const sortedNumSeparators = sortAscending(numSeparators);
202
202
  const parts = sliceByIndexes(input, sortedNumSeparators);
203
203
  const segments = regex ? parts.flatMap((part) => part.split(regex)) : parts;
204
- return shouldPreserveEmpty ? segments : segments.filter((segment) => segment !== "");
204
+ return shouldPreserveEmpty ? segments : segments.filter((segment) => !isEmptyString(segment));
205
205
  }
206
206
 
207
207
  // src/utils/array.ts
@@ -235,7 +235,7 @@ function extractOptions(args) {
235
235
  }
236
236
  function trimSegments(segments, preserveEmpty) {
237
237
  const trimmed = segments.map((segment) => segment.trim());
238
- return preserveEmpty ? trimmed : trimmed.filter((segment) => segment !== "");
238
+ return preserveEmpty ? trimmed : trimmed.filter((segment) => !isEmptyString(segment));
239
239
  }
240
240
  function trimNestedSegments(rows, preserveEmpty) {
241
241
  return rows.map((row) => trimSegments(row, preserveEmpty));
@@ -294,7 +294,10 @@ function divider(input, ...args) {
294
294
  preserveEmpty: options.preserveEmpty
295
295
  });
296
296
  const result = isString(input) ? applyDivision(input) : input.map(applyDivision);
297
- return applyDividerOptions(result, options);
297
+ return applyDividerOptions(
298
+ result,
299
+ options
300
+ );
298
301
  }
299
302
 
300
303
  // src/core/divider-first.ts
@@ -345,15 +348,15 @@ function dividerLoop(input, size, options) {
345
348
  console.warn("dividerLoop: chunk size must be a positive number");
346
349
  return [];
347
350
  }
348
- const finalOptions = options ?? {};
351
+ const resolvedOptions = options ?? {};
349
352
  const {
350
353
  startOffset = PERFORMANCE_CONSTANTS.DEFAULT_START_OFFSET,
351
354
  maxChunks = PERFORMANCE_CONSTANTS.DEFAULT_MAX_CHUNKS
352
- } = finalOptions;
355
+ } = resolvedOptions;
353
356
  const result = isString(input) ? createChunksFromString(input, size, startOffset, maxChunks) : input.map(
354
357
  (str) => createChunksFromString(str, size, startOffset, maxChunks)
355
358
  );
356
- return applyDividerOptions(result, finalOptions);
359
+ return applyDividerOptions(result, resolvedOptions);
357
360
  }
358
361
 
359
362
  // src/utils/divide.ts
@@ -364,7 +367,8 @@ function divideNumberString(str) {
364
367
  // src/core/divider-number-string.ts
365
368
  function dividerNumberString(input, options) {
366
369
  const result = isString(input) ? divideNumberString(input) : input.map(divideNumberString);
367
- return applyDividerOptions(result, options ?? {});
370
+ const resolvedOptions = options ?? {};
371
+ return applyDividerOptions(result, resolvedOptions);
368
372
  }
369
373
 
370
374
  // src/utils/quoted.ts
@@ -426,11 +430,11 @@ function quotedDivide(line, {
426
430
  currentFieldBuffer = "";
427
431
  };
428
432
  for (const piece of pieces) {
429
- currentFieldBuffer = currentFieldBuffer === "" ? piece : currentFieldBuffer + delimiter + piece;
433
+ currentFieldBuffer = isEmptyString(currentFieldBuffer) ? piece : currentFieldBuffer + delimiter + piece;
430
434
  insideQuotes = countUnescaped(currentFieldBuffer, quote) % 2 === 1;
431
435
  if (!insideQuotes) flush();
432
436
  }
433
- if (currentFieldBuffer !== "") flush();
437
+ if (!isEmptyString(currentFieldBuffer)) flush();
434
438
  return fields;
435
439
  }
436
440
 
@@ -466,12 +470,12 @@ function emailDivider(input, options = {}) {
466
470
  // src/presets/path-divider.ts
467
471
  function pathDivider(input, options = {}) {
468
472
  const { trim = false, collapse = true } = options;
469
- if (input === "") return [""];
473
+ if (isEmptyString(input)) return [""];
470
474
  const segments = collapse ? divider(input, PATH_SEPARATORS.SLASH, PATH_SEPARATORS.ALT) : dividePreserve(input, PATH_SEPARATORS.ALT).flatMap(
471
475
  (part) => dividePreserve(part, PATH_SEPARATORS.SLASH)
472
476
  );
473
477
  const maybeTrimmed = trim ? segments.map((segment) => segment.trim()) : segments;
474
- return collapse ? maybeTrimmed.filter((segment) => segment !== "") : maybeTrimmed;
478
+ return collapse ? maybeTrimmed.filter((segment) => !isEmptyString(segment)) : maybeTrimmed;
475
479
  }
476
480
  export {
477
481
  csvDivider,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nyaomaru/divider",
3
3
  "type": "module",
4
- "version": "1.9.11",
4
+ "version": "1.9.13",
5
5
  "description": "To divide string or string[] with a given separator",
6
6
  "main": "./dist/index.cjs",
7
7
  "module": "./dist/index.js",