Skip to content

Commit e06d0ee

Browse files
committed
Add individualThreshold option to stringify()
1 parent 24eaaf4 commit e06d0ee

File tree

4 files changed

+70
-14
lines changed

4 files changed

+70
-14
lines changed

api-reference.md

+17-2
Original file line numberDiff line numberDiff line change
@@ -424,19 +424,32 @@ init([[2, 5], [8, 10]]); // [[2, 5], [8, 9]]
424424
## function: `stringify`
425425

426426
```ts
427-
stringify(data: MultiIntegerRange): string
427+
stringify(
428+
data: MultiIntegerRange,
429+
options: StringifyOptions = {}
430+
): string
428431
```
429432

430433
| Param | Description |
431434
|-|-|
432435
| `data` | The MultiIntegerRange to stringify. |
436+
| `options` | Options for the stringification. |
433437
| Returns | The string representation of the given data. |
434438

435439
Returns the string respresentation of the given MultiIntegerRange.
436440

441+
- `options.individualThreshold` (number): If set, small ranges with a length
442+
smaller than or equal to this will be output as individual integers.
443+
Defaults to `1`, which means only ranges with a length of 1 will be
444+
output as a single integer.
445+
437446
### Example
438447

439448
```ts
449+
stringify([[2, 3], [5, 5], [7, 9]]); // '2-3,5,7-9'
450+
stringify([[2, 3], [5, 5], [7, 9]], { individualThreshold: 0 }); // '2-3,5-5,7-9'
451+
stringify([[2, 3], [5, 5], [7, 9]], { individualThreshold: 2 }); // '2,3,5,7-9'
452+
stringify([[2, 3], [5, 5], [7, 9]], { individualThreshold: 3 }); // '2,3,5,7,8,9'
440453
stringify([[3, 5], [7, Infinity]]); // '3-5,7-'
441454
```
442455

@@ -477,11 +490,13 @@ iterate(
477490
| Param | Description |
478491
|-|-|
479492
| `data` | The normalized MultiIntegerRange to iterate over. |
480-
| `options` | Pass `{ descending: true }` to iterate in descending order. |
493+
| `options` | Options for the iteration. |
481494
| Returns | An Iterable object. |
482495

483496
Returns an Iterable with which you can use `for-of` or the spread syntax.
484497

498+
- `options.descending` (boolean): If set to true, the iterator will iterate in descending order.
499+
485500
### Example
486501

487502
```ts

scripts/docgen.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const fs = require('fs/promises');
66
const parseDocComment = docComment => {
77
const lines = docComment
88
.split('\n')
9-
.map(s => s.replace(/^\s*(\/\*\*|\*)?\s*/g, ''));
9+
.map(s => s.replace(/^\s*(\/\*\*|\*)?\s?/g, ''));
1010
const tags = {};
1111
let currentTag = 'summary';
1212
let currentTagContent = '';
@@ -77,6 +77,7 @@ const buildMarkdown = parsed => {
7777
''
7878
];
7979

80+
// TOC
8081
parsed
8182
.filter(item => item.type === 'function')
8283
.forEach(item => {

src/fp.test.ts

+9
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,15 @@ test('stringify', () => {
444444
t('-10');
445445
t('10-');
446446
t('');
447+
448+
const r = mr.parse('2-3,5,7-9');
449+
const t2 = (individualThreshold: number, expected: string) =>
450+
expect(mr.stringify(r, { individualThreshold })).toBe(expected);
451+
t2(0, '2-3,5-5,7-9');
452+
t2(1, '2-3,5,7-9');
453+
t2(2, '2,3,5,7-9');
454+
t2(3, '2,3,5,7,8,9');
455+
t2(4, '2,3,5,7,8,9');
447456
});
448457

449458
test('flatten', () => {

src/fp.ts

+42-11
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ const findOverlap = (
245245
* @param a - The first value.
246246
* @param b - The second value.
247247
* @returns A new MultiIntegerRange containing all integers that belong to
248-
* **either `a` or `b` (or both)**.
248+
* **either `a` or `b` (or both)**.
249249
* @example
250250
* append([[1, 5]], [[3, 8], [10, 15]]); // [[1, 8], [10, 15]]
251251
* append([[5, 9]], [[-Infinity, 2]]); // [[-Infinity, 2], [5, 9]]
@@ -264,7 +264,7 @@ export const append = (a: MIR, b: MIR): MIR => {
264264
* @param a - The value to be subtracted.
265265
* @param b - The value to subtract.
266266
* @returns A new MultiIntegerRange containing all integers that belong to
267-
* **`a` but not `b`**.
267+
* **`a` but not `b`**.
268268
* @example
269269
* subtract([[1, 7]], [[2, 4]]); // [[1, 1], [5, 7]]
270270
* subtract([[-Infinity, Infinity]], [[2, 4]]); // [[-Infinity, 1], [5, Infinity]]
@@ -292,7 +292,7 @@ export const subtract = (a: MIR, b: MIR): MIR => {
292292
* @param a - The first value.
293293
* @param b - The second value.
294294
* @returns A new MultiIntegerRange containing all integers
295-
* that belong to **both `a` and `b`**.
295+
* that belong to **both `a` and `b`**.
296296
* @example
297297
* intersect([[2, 5]], [[4, 9]]); // [[4, 5]]
298298
* intersect([[5, 10]], [[-Infinity, Infinity]]); // [[5, 10]]
@@ -429,7 +429,7 @@ export const max = (data: MIR): number | undefined => {
429429
* @param data - The value.
430430
* @param index - The 0-based index of the integer to return. Can be negative.
431431
* @returns The integer at the specified index.
432-
* Returns `undefined` if the index is out of bounds.
432+
* Returns `undefined` if the index is out of bounds.
433433
* @example
434434
* at([[2, 4], [8, 10]], 4); // 9
435435
* at([[2, 4], [8, 10]], 6); // undefined
@@ -464,7 +464,7 @@ export const at = (data: MIR, index: number): number | undefined => {
464464
* Returns all but the minimum integer.
465465
* @param data - The value.
466466
* @returns A new MultiIntegerRange which is almost the same as `data` but with
467-
* its minimum integer removed.
467+
* its minimum integer removed.
468468
* @example
469469
* tail([[2, 5], [8, 10]]); // [[3, 5], [8, 10]]
470470
*/
@@ -482,7 +482,7 @@ export const tail = (data: MIR): MIR => {
482482
* Returns all but the maximum integer.
483483
* @param data - The value.
484484
* @returns A new MultiIntegerRange which is almost the same as `data` but with
485-
* its maximum integer removed.
485+
* its maximum integer removed.
486486
* @example
487487
* init([[2, 5], [8, 10]]); // [[2, 5], [8, 9]]
488488
*/
@@ -496,14 +496,36 @@ export const init = (data: MIR): MIR => {
496496
return subtract(data, [[m, m]]);
497497
};
498498

499+
/**
500+
* Options for the `stringify()` function.
501+
*/
502+
export interface StringifyOptions {
503+
individualThreshold?: number;
504+
}
505+
499506
/**
500507
* Returns the string respresentation of the given MultiIntegerRange.
508+
*
509+
* - `options.individualThreshold` (number): If set, small ranges with a length
510+
* smaller than or equal to this will be output as individual integers.
511+
* Defaults to `1`, which means only ranges with a length of 1 will be
512+
* output as a single integer.
513+
*
501514
* @param data - The MultiIntegerRange to stringify.
515+
* @param options - Options for the stringification.
502516
* @returns The string representation of the given data.
503517
* @example
518+
* stringify([[2, 3], [5, 5], [7, 9]]); // '2-3,5,7-9'
519+
* stringify([[2, 3], [5, 5], [7, 9]], { individualThreshold: 0 }); // '2-3,5-5,7-9'
520+
* stringify([[2, 3], [5, 5], [7, 9]], { individualThreshold: 2 }); // '2,3,5,7-9'
521+
* stringify([[2, 3], [5, 5], [7, 9]], { individualThreshold: 3 }); // '2,3,5,7,8,9'
504522
* stringify([[3, 5], [7, Infinity]]); // '3-5,7-'
505523
*/
506-
export const stringify = (data: MIR): string => {
524+
export const stringify = (
525+
data: MIR,
526+
options: StringifyOptions = {}
527+
): string => {
528+
const { individualThreshold = 1 } = options;
507529
const wrap = (i: number) => (i >= 0 ? String(i) : `(${i})`);
508530
const ranges: string[] = [];
509531
for (let r of data) {
@@ -515,10 +537,10 @@ export const stringify = (data: MIR): string => {
515537
}
516538
} else if (r[1] === Infinity) {
517539
ranges.push(`${wrap(r[0])}-`);
518-
} else if (r[0] == r[1]) {
519-
ranges.push(wrap(r[0]));
520540
} else {
521-
ranges.push(`${wrap(r[0])}-${wrap(r[1])}`);
541+
if (individualThreshold && r[1] - r[0] + 1 <= individualThreshold) {
542+
for (let i = r[0]; i <= r[1]; i++) ranges.push(wrap(i));
543+
} else ranges.push(`${wrap(r[0])}-${wrap(r[1])}`);
522544
}
523545
}
524546
return ranges.join(',');
@@ -547,14 +569,23 @@ export const flatten = (data: MIR): number[] => {
547569
return result;
548570
};
549571

572+
/**
573+
* Options for the `iterate()` function.
574+
*/
550575
export interface IterateOptions {
576+
/**
577+
* Whether to iterate in descending order.
578+
*/
551579
readonly descending?: boolean;
552580
}
553581

554582
/**
555583
* Returns an Iterable with which you can use `for-of` or the spread syntax.
584+
*
585+
* - `options.descending` (boolean): If set to true, the iterator will iterate in descending order.
586+
*
556587
* @param data - The normalized MultiIntegerRange to iterate over.
557-
* @param options - Pass `{ descending: true }` to iterate in descending order.
588+
* @param options - Options for the iteration.
558589
* @returns An Iterable object.
559590
* @example
560591
* Array.from(iterate([[1, 3], [7, 9]])); // [1, 2, 3, 7, 8, 9]

0 commit comments

Comments
 (0)