range-pie 2.4.0 → 3.0.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/LICENSE +1 -1
- package/README.md +72 -73
- package/dist/py-range.d.ts +38 -13
- package/dist/py-range.js +63 -46
- package/package.json +28 -18
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
A TypeScript/JavaScript library that brings Python's range functionality to JavaScript, enhanced with familiar array methods. This lightweight utility provides a seamless way to work with numeric sequences while maintaining JavaScript's functional programming paradigm. Fully typed for TypeScript users while remaining compatible with JavaScript projects.
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/range-pie)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
5
8
|
## Table of Contents
|
|
6
9
|
|
|
7
10
|
- [Installation](#installation)
|
|
8
11
|
- [Basic Usage](#basic-usage)
|
|
9
|
-
|
|
10
12
|
- [JavaScript](#javascript)
|
|
11
13
|
- [TypeScript](#typescript)
|
|
12
14
|
|
|
13
15
|
- [API Reference](#api-reference)
|
|
14
|
-
|
|
15
16
|
- [Constructor Options](#constructor-options)
|
|
16
17
|
- [Properties](#properties)
|
|
17
18
|
- [at()](#at)
|
|
@@ -37,12 +38,10 @@ A TypeScript/JavaScript library that brings Python's range functionality to Java
|
|
|
37
38
|
- [values()](#values)
|
|
38
39
|
|
|
39
40
|
- [Advanced Usage](#advanced-usage)
|
|
40
|
-
|
|
41
41
|
- [Iteration](#iteration)
|
|
42
42
|
- [Proxy Access](#proxy-access)
|
|
43
43
|
|
|
44
44
|
- [Examples](#examples)
|
|
45
|
-
|
|
46
45
|
- [Methods chaining](#methods-chaining)
|
|
47
46
|
- [Using as Array-like Object](#using-as-array-like-object)
|
|
48
47
|
- [Example Files](#example-files)
|
|
@@ -62,9 +61,9 @@ npm install range-pie
|
|
|
62
61
|
|
|
63
62
|
```javascript
|
|
64
63
|
// CommonJS - Both import styles are supported
|
|
65
|
-
const { PyRange } = require(
|
|
64
|
+
const { PyRange } = require("range-pie"); // Named import style
|
|
66
65
|
// OR
|
|
67
|
-
const PyRange = require(
|
|
66
|
+
const PyRange = require("range-pie"); // Default import style
|
|
68
67
|
|
|
69
68
|
// Create a range from 0 to 5
|
|
70
69
|
const range = new PyRange(5);
|
|
@@ -87,20 +86,20 @@ console.log([...range4]); // [5, 4, 3]
|
|
|
87
86
|
|
|
88
87
|
```typescript
|
|
89
88
|
// ES Modules - Both import styles are supported
|
|
90
|
-
import { PyRange } from
|
|
89
|
+
import { PyRange } from "range-pie"; // Named import style
|
|
91
90
|
// OR
|
|
92
|
-
import PyRange from
|
|
91
|
+
import PyRange from "range-pie"; // Default import style
|
|
93
92
|
|
|
94
93
|
// Create a range from 0 to 5
|
|
95
94
|
const range = new PyRange(5);
|
|
96
95
|
console.log([...range]); // [0, 1, 2, 3, 4]
|
|
97
96
|
|
|
98
97
|
// Type-safe operations
|
|
99
|
-
const doubledValues: number[] = range.map(x => x * 2);
|
|
98
|
+
const doubledValues: number[] = range.map((x) => x * 2);
|
|
100
99
|
console.log(doubledValues); // [0, 2, 4, 6, 8]
|
|
101
100
|
|
|
102
101
|
// Type inference works with generics
|
|
103
|
-
const stringValues: string[] = range.map(x => `Value: ${x}`);
|
|
102
|
+
const stringValues: string[] = range.map((x) => `Value: ${x}`);
|
|
104
103
|
console.log(stringValues); // ['Value: 0', 'Value: 1', 'Value: 2', 'Value: 3', 'Value: 4']
|
|
105
104
|
```
|
|
106
105
|
|
|
@@ -109,9 +108,9 @@ console.log(stringValues); // ['Value: 0', 'Value: 1', 'Value: 2', 'Value: 3', '
|
|
|
109
108
|
### Constructor Options
|
|
110
109
|
|
|
111
110
|
```javascript
|
|
112
|
-
new PyRange(stop)
|
|
113
|
-
new PyRange(start, stop)
|
|
114
|
-
new PyRange(start, stop, step)
|
|
111
|
+
new PyRange(stop); // 0 to stop-1
|
|
112
|
+
new PyRange(start, stop); // start to stop-1
|
|
113
|
+
new PyRange(start, stop, step); // start to stop-1 with step
|
|
115
114
|
```
|
|
116
115
|
|
|
117
116
|
- **PyRange(stop:number)**
|
|
@@ -148,21 +147,22 @@ console.log(PyRange(2, -10, -1));
|
|
|
148
147
|
|
|
149
148
|
```javascript
|
|
150
149
|
const range = new PyRange(1, 10, 2);
|
|
151
|
-
console.log(range.start);
|
|
152
|
-
console.log(range.stop);
|
|
153
|
-
console.log(range.step);
|
|
150
|
+
console.log(range.start); // 1
|
|
151
|
+
console.log(range.stop); // 10
|
|
152
|
+
console.log(range.step); // 2
|
|
154
153
|
console.log(range.length); // 5
|
|
155
154
|
```
|
|
156
155
|
|
|
157
156
|
### at()
|
|
158
157
|
|
|
159
|
-
The 'at' method accepts a number as argument to
|
|
158
|
+
The 'at' method accepts a number as argument to get the value at the specified index in a range. Returns `undefined` if the index is out of range, perfectly matching `Array.prototype.at`. Negative indices count backwards from the end of the range.
|
|
160
159
|
|
|
161
160
|
```javascript
|
|
162
|
-
const range = new PyRange(1, 5);
|
|
163
|
-
console.log(range.at(0));
|
|
164
|
-
console.log(range.at(2));
|
|
165
|
-
console.log(range.at(-1)); //
|
|
161
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
162
|
+
console.log(range.at(0)); // 1
|
|
163
|
+
console.log(range.at(2)); // 3
|
|
164
|
+
console.log(range.at(-1)); // 4 (negative index wraps from the end)
|
|
165
|
+
console.log(range.at(10)); // undefined (out of bounds)
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
### toString()
|
|
@@ -188,8 +188,8 @@ console.log(range.toArray()); // [1, 2, 3]
|
|
|
188
188
|
It works the same as [**`Array.prototype.map`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
|
|
189
189
|
|
|
190
190
|
```javascript
|
|
191
|
-
const range = new PyRange(1, 4);
|
|
192
|
-
console.log(range.map(x => x * 2));
|
|
191
|
+
const range = new PyRange(1, 4); // [1, 2, 3]
|
|
192
|
+
console.log(range.map((x) => x * 2)); // [2, 4, 6]
|
|
193
193
|
```
|
|
194
194
|
|
|
195
195
|
### filter()
|
|
@@ -197,8 +197,8 @@ console.log(range.map(x => x * 2)); // [2, 4, 6]
|
|
|
197
197
|
It works the same as [**`Array.prototype.filter`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)
|
|
198
198
|
|
|
199
199
|
```javascript
|
|
200
|
-
const range = new PyRange(1, 6);
|
|
201
|
-
console.log(range.filter(x => x % 2 === 0));
|
|
200
|
+
const range = new PyRange(1, 6); // [1, 2, 3, 4, 5]
|
|
201
|
+
console.log(range.filter((x) => x % 2 === 0)); // [2, 4]
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
### reduce()
|
|
@@ -206,9 +206,9 @@ console.log(range.filter(x => x % 2 === 0)); // [2, 4]
|
|
|
206
206
|
It works the same as [**`Array.prototype.reduce`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce)
|
|
207
207
|
|
|
208
208
|
```javascript
|
|
209
|
-
const range = new PyRange(1, 4);
|
|
209
|
+
const range = new PyRange(1, 4); // [1, 2, 3]
|
|
210
210
|
const sum = range.reduce((acc, curr) => acc + curr, 0);
|
|
211
|
-
console.log(sum);
|
|
211
|
+
console.log(sum); // 6
|
|
212
212
|
```
|
|
213
213
|
|
|
214
214
|
### some()
|
|
@@ -216,9 +216,9 @@ console.log(sum); // 6
|
|
|
216
216
|
It works the same as [**`Array.prototype.some`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)
|
|
217
217
|
|
|
218
218
|
```javascript
|
|
219
|
-
const range = new PyRange(1, 5);
|
|
220
|
-
console.log(range.some(x => x > 3));
|
|
221
|
-
console.log(range.some(x => x < 0));
|
|
219
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
220
|
+
console.log(range.some((x) => x > 3)); // true
|
|
221
|
+
console.log(range.some((x) => x < 0)); // false
|
|
222
222
|
```
|
|
223
223
|
|
|
224
224
|
### every()
|
|
@@ -226,9 +226,9 @@ console.log(range.some(x => x < 0)); // false
|
|
|
226
226
|
It works the same as [**`Array.prototype.every`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every)
|
|
227
227
|
|
|
228
228
|
```javascript
|
|
229
|
-
const range = new PyRange(1, 5);
|
|
230
|
-
console.log(range.every(x => x > 0));
|
|
231
|
-
console.log(range.every(x => x > 2));
|
|
229
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
230
|
+
console.log(range.every((x) => x > 0)); // true
|
|
231
|
+
console.log(range.every((x) => x > 2)); // false
|
|
232
232
|
```
|
|
233
233
|
|
|
234
234
|
### find()
|
|
@@ -236,9 +236,9 @@ console.log(range.every(x => x > 2)); // false
|
|
|
236
236
|
It works the same as [**`Array.prototype.find`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find)
|
|
237
237
|
|
|
238
238
|
```javascript
|
|
239
|
-
const range = new PyRange(1, 5);
|
|
240
|
-
console.log(range.find(x => x > 2));
|
|
241
|
-
console.log(range.find(x => x > 5));
|
|
239
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
240
|
+
console.log(range.find((x) => x > 2)); // 3
|
|
241
|
+
console.log(range.find((x) => x > 5)); // undefined
|
|
242
242
|
```
|
|
243
243
|
|
|
244
244
|
### findIndex()
|
|
@@ -246,9 +246,9 @@ console.log(range.find(x => x > 5)); // undefined
|
|
|
246
246
|
It works the same as [**`Array.prototype.findIndex`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)
|
|
247
247
|
|
|
248
248
|
```javascript
|
|
249
|
-
const range = new PyRange(1, 5);
|
|
250
|
-
console.log(range.findIndex(x => x > 2));
|
|
251
|
-
console.log(range.findIndex(x => x > 5));
|
|
249
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
250
|
+
console.log(range.findIndex((x) => x > 2)); // 2
|
|
251
|
+
console.log(range.findIndex((x) => x > 5)); // -1
|
|
252
252
|
```
|
|
253
253
|
|
|
254
254
|
### findLastIndex()
|
|
@@ -256,9 +256,9 @@ console.log(range.findIndex(x => x > 5)); // -1
|
|
|
256
256
|
It works the same as [**`Array.prototype.findLastIndex`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex)
|
|
257
257
|
|
|
258
258
|
```javascript
|
|
259
|
-
const range = new PyRange(1, 5);
|
|
260
|
-
console.log(range.findLastIndex(x => x > 2));
|
|
261
|
-
console.log(range.findLastIndex(x => x > 5));
|
|
259
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
260
|
+
console.log(range.findLastIndex((x) => x > 2)); // 3
|
|
261
|
+
console.log(range.findLastIndex((x) => x > 5)); // -1
|
|
262
262
|
```
|
|
263
263
|
|
|
264
264
|
### forEach()
|
|
@@ -266,8 +266,8 @@ console.log(range.findLastIndex(x => x > 5)); // -1
|
|
|
266
266
|
It works the same as [**`Array.prototype.forEach`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
|
|
267
267
|
|
|
268
268
|
```javascript
|
|
269
|
-
const range = new PyRange(1, 4);
|
|
270
|
-
range.forEach(x => console.log(x));
|
|
269
|
+
const range = new PyRange(1, 4); // [1, 2, 3]
|
|
270
|
+
range.forEach((x) => console.log(x));
|
|
271
271
|
// 1
|
|
272
272
|
// 2
|
|
273
273
|
// 3
|
|
@@ -278,9 +278,9 @@ range.forEach(x => console.log(x));
|
|
|
278
278
|
It works the same as [**`Array.prototype.includes`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)
|
|
279
279
|
|
|
280
280
|
```javascript
|
|
281
|
-
const range = new PyRange(1, 5);
|
|
282
|
-
console.log(range.includes(3));
|
|
283
|
-
console.log(range.includes(5));
|
|
281
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
282
|
+
console.log(range.includes(3)); // true
|
|
283
|
+
console.log(range.includes(5)); // false
|
|
284
284
|
```
|
|
285
285
|
|
|
286
286
|
### indexOf()
|
|
@@ -288,9 +288,9 @@ console.log(range.includes(5)); // false
|
|
|
288
288
|
It works the same as [**`Array.prototype.indexOf`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
|
|
289
289
|
|
|
290
290
|
```javascript
|
|
291
|
-
const range = new PyRange(1, 5);
|
|
292
|
-
console.log(range.indexOf(3));
|
|
293
|
-
console.log(range.indexOf(5));
|
|
291
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
292
|
+
console.log(range.indexOf(3)); // 2
|
|
293
|
+
console.log(range.indexOf(5)); // -1
|
|
294
294
|
```
|
|
295
295
|
|
|
296
296
|
### lastIndexOf()
|
|
@@ -298,9 +298,9 @@ console.log(range.indexOf(5)); // -1
|
|
|
298
298
|
It works the same as [**`Array.prototype.lastIndexOf`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf)
|
|
299
299
|
|
|
300
300
|
```javascript
|
|
301
|
-
const range = new PyRange(1, 5, 1);
|
|
302
|
-
console.log(range.lastIndexOf(3));
|
|
303
|
-
console.log(range.lastIndexOf(5));
|
|
301
|
+
const range = new PyRange(1, 5, 1); // [1, 2, 3, 4]
|
|
302
|
+
console.log(range.lastIndexOf(3)); // 2
|
|
303
|
+
console.log(range.lastIndexOf(5)); // -1
|
|
304
304
|
```
|
|
305
305
|
|
|
306
306
|
### pop()
|
|
@@ -310,9 +310,9 @@ this method removes the last value from the range, shortens the range and
|
|
|
310
310
|
returns that value.
|
|
311
311
|
|
|
312
312
|
```javascript
|
|
313
|
-
const range = new PyRange(1, 5);
|
|
314
|
-
console.log(range.pop());
|
|
315
|
-
console.log([...range]);
|
|
313
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
314
|
+
console.log(range.pop()); // 4
|
|
315
|
+
console.log([...range]); // [1, 2, 3]
|
|
316
316
|
```
|
|
317
317
|
|
|
318
318
|
### slice()
|
|
@@ -322,10 +322,10 @@ It returns a new PyRange instance containing elements from the specified indices
|
|
|
322
322
|
The original range is not modified.
|
|
323
323
|
|
|
324
324
|
```javascript
|
|
325
|
-
const range = new PyRange(0, 10);
|
|
325
|
+
const range = new PyRange(0, 10); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
326
326
|
const sliced = range.slice(2, 5);
|
|
327
327
|
console.log([...sliced]); // [2, 3, 4]
|
|
328
|
-
console.log([...range]);
|
|
328
|
+
console.log([...range]); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (unchanged)
|
|
329
329
|
|
|
330
330
|
// Negative indices are supported
|
|
331
331
|
const lastThree = range.slice(-3);
|
|
@@ -337,13 +337,13 @@ console.log([...lastThree]); // [7, 8, 9]
|
|
|
337
337
|
It works the same as [**`Array.prototype.reverse`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)
|
|
338
338
|
|
|
339
339
|
```javascript
|
|
340
|
-
const range = new PyRange(1, 5);
|
|
341
|
-
console.log([...range]);
|
|
340
|
+
const range = new PyRange(1, 5); // [1, 2, 3, 4]
|
|
341
|
+
console.log([...range]); // [1, 2, 3, 4]
|
|
342
342
|
|
|
343
343
|
const reversed = range.reverse(); // [4, 3, 2, 1]
|
|
344
|
-
console.log([...reversed]);
|
|
344
|
+
console.log([...reversed]); // [4, 3, 2, 1]
|
|
345
345
|
|
|
346
|
-
const rangeWithStep = new PyRange(1, 10, 2);
|
|
346
|
+
const rangeWithStep = new PyRange(1, 10, 2); // [1, 3, 5, 7, 9]
|
|
347
347
|
const reversedStep = rangeWithStep.reverse(); // [9, 7, 5, 3, 1]
|
|
348
348
|
console.log([...reversedStep]);
|
|
349
349
|
```
|
|
@@ -354,7 +354,7 @@ It works the same as [**`Array.prototype.entries`**](https://developer.mozilla.o
|
|
|
354
354
|
It returns an iterator of `[index, value]` pairs.
|
|
355
355
|
|
|
356
356
|
```javascript
|
|
357
|
-
const range = new PyRange(1, 4);
|
|
357
|
+
const range = new PyRange(1, 4); // [1, 2, 3]
|
|
358
358
|
for (const [index, value] of range.entries()) {
|
|
359
359
|
console.log(index, value);
|
|
360
360
|
}
|
|
@@ -369,7 +369,7 @@ It works the same as [**`Array.prototype.keys`**](https://developer.mozilla.org/
|
|
|
369
369
|
It returns an iterator of the indices of the range.
|
|
370
370
|
|
|
371
371
|
```javascript
|
|
372
|
-
const range = new PyRange(3);
|
|
372
|
+
const range = new PyRange(3); // [0, 1, 2]
|
|
373
373
|
console.log([...range.keys()]); // [0, 1, 2]
|
|
374
374
|
```
|
|
375
375
|
|
|
@@ -379,7 +379,7 @@ It works the same as [**`Array.prototype.values`**](https://developer.mozilla.or
|
|
|
379
379
|
It returns an iterator of the values in the range.
|
|
380
380
|
|
|
381
381
|
```javascript
|
|
382
|
-
const range = new PyRange(3);
|
|
382
|
+
const range = new PyRange(3); // [0, 1, 2]
|
|
383
383
|
console.log([...range.values()]); // [0, 1, 2]
|
|
384
384
|
```
|
|
385
385
|
|
|
@@ -392,7 +392,7 @@ const range = new PyRange(3);
|
|
|
392
392
|
|
|
393
393
|
// For...of loop
|
|
394
394
|
for (const num of range) {
|
|
395
|
-
|
|
395
|
+
console.log(num); // 0, 1, 2
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
// Spread operator
|
|
@@ -401,7 +401,7 @@ const array = [...range]; // [0, 1, 2]
|
|
|
401
401
|
|
|
402
402
|
### Proxy Access
|
|
403
403
|
|
|
404
|
-
Proxy access allows access to the array elements using bracket notation, just like a regular array.
|
|
404
|
+
Proxy access allows access to the array elements using bracket notation, just like a regular array. Out-of-bounds access returns `undefined`.
|
|
405
405
|
|
|
406
406
|
```javascript
|
|
407
407
|
const range = new PyRange(5);
|
|
@@ -409,6 +409,7 @@ const proxy = range.asProxy();
|
|
|
409
409
|
|
|
410
410
|
console.log(proxy[0]); // 0
|
|
411
411
|
console.log(proxy[3]); // 3
|
|
412
|
+
console.log(proxy[10]); // undefined
|
|
412
413
|
```
|
|
413
414
|
|
|
414
415
|
### TypeScript Support
|
|
@@ -425,13 +426,13 @@ This package is written in TypeScript and provides full type definitions for all
|
|
|
425
426
|
const range = new PyRange(5);
|
|
426
427
|
|
|
427
428
|
// TypeScript knows this is a number[]
|
|
428
|
-
const numbers = range.map(x => x * 2);
|
|
429
|
+
const numbers = range.map((x) => x * 2);
|
|
429
430
|
|
|
430
431
|
// TypeScript knows this is a string[]
|
|
431
|
-
const strings = range.map(x => `Number: ${x}`);
|
|
432
|
+
const strings = range.map((x) => `Number: ${x}`);
|
|
432
433
|
|
|
433
434
|
// TypeScript knows this is a boolean[]
|
|
434
|
-
const booleans = range.map(x => x % 2 === 0);
|
|
435
|
+
const booleans = range.map((x) => x % 2 === 0);
|
|
435
436
|
```
|
|
436
437
|
|
|
437
438
|
## Examples
|
|
@@ -440,9 +441,7 @@ const booleans = range.map(x => x % 2 === 0);
|
|
|
440
441
|
|
|
441
442
|
```javascript
|
|
442
443
|
const range = new PyRange(1, 6);
|
|
443
|
-
const squares = range
|
|
444
|
-
.filter(x => x % 2 === 0)
|
|
445
|
-
.map(x => x * x);
|
|
444
|
+
const squares = range.filter((x) => x % 2 === 0).map((x) => x * x);
|
|
446
445
|
console.log(squares); // [4, 16]
|
|
447
446
|
```
|
|
448
447
|
|
package/dist/py-range.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ declare class PyRange implements Iterable<number> {
|
|
|
6
6
|
private _stop;
|
|
7
7
|
private _step;
|
|
8
8
|
private _length;
|
|
9
|
+
private static toIntegerOrInfinity;
|
|
10
|
+
private static isArrayIndexProperty;
|
|
9
11
|
/**
|
|
10
12
|
* Creates a new PyRange instance.
|
|
11
13
|
* @param {...number} args - The arguments of the range. The possible forms are
|
|
@@ -21,7 +23,9 @@ declare class PyRange implements Iterable<number> {
|
|
|
21
23
|
* @property {number} step - The step of the range.
|
|
22
24
|
* @property {number} length - The length of the range.
|
|
23
25
|
*/
|
|
24
|
-
constructor(
|
|
26
|
+
constructor(stop: number);
|
|
27
|
+
constructor(start: number, stop: number);
|
|
28
|
+
constructor(start: number, stop: number, step: number);
|
|
25
29
|
/**
|
|
26
30
|
* Gets the length of this range.
|
|
27
31
|
*
|
|
@@ -52,11 +56,17 @@ declare class PyRange implements Iterable<number> {
|
|
|
52
56
|
get step(): number;
|
|
53
57
|
/**
|
|
54
58
|
* Gets the value at the specified index in this range.
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
59
|
+
*
|
|
60
|
+
* Negative indices are supported and wrap from the end, matching the
|
|
61
|
+
* behaviour of `Array.prototype.at()`. For example, `at(-1)` returns the
|
|
62
|
+
* last element.
|
|
63
|
+
*
|
|
64
|
+
* @param {number} index - The index of the value to retrieve. Negative
|
|
65
|
+
* indices count from the end of the range.
|
|
66
|
+
* @returns {number|undefined} The value at the specified index, or
|
|
67
|
+
* undefined when the normalised index is out of range.
|
|
58
68
|
*/
|
|
59
|
-
at(index: number): number;
|
|
69
|
+
at(index: number): number | undefined;
|
|
60
70
|
/**
|
|
61
71
|
* Converts the range to a string.
|
|
62
72
|
* @returns {string} A string of the form `Range(start, stop, step)`.
|
|
@@ -71,6 +81,7 @@ declare class PyRange implements Iterable<number> {
|
|
|
71
81
|
* Validates that the callback is a function.
|
|
72
82
|
* @param {Function} cb - The callback to validate.
|
|
73
83
|
* @throws {TypeError} If the callback is not a function.
|
|
84
|
+
* @internal
|
|
74
85
|
*/
|
|
75
86
|
private static validateCb;
|
|
76
87
|
/**
|
|
@@ -92,15 +103,23 @@ declare class PyRange implements Iterable<number> {
|
|
|
92
103
|
filter(callback: (value: number, index: number, range: PyRange) => boolean): number[];
|
|
93
104
|
/**
|
|
94
105
|
* Reduces the range to a single value.
|
|
106
|
+
*
|
|
107
|
+
* Uses rest parameters to reliably distinguish between "no initial value
|
|
108
|
+
* provided" and "explicit `undefined` passed as initial value", matching
|
|
109
|
+
* the behaviour of `Array.prototype.reduce()`.
|
|
110
|
+
*
|
|
95
111
|
* @param {function(T, number, number, PyRange): T} callback - The callback
|
|
96
112
|
* function to apply to every element. The callback should take four
|
|
97
113
|
* arguments: the accumulator, the current value, the index of the current
|
|
98
114
|
* value, and the range object.
|
|
99
115
|
* @param {T} [initialValue] - The initial value of the accumulator.
|
|
100
116
|
* @returns {T} The final value of the accumulator.
|
|
117
|
+
* @throws {TypeError} If the range is empty and no initial value is provided.
|
|
101
118
|
* @template T
|
|
102
119
|
*/
|
|
103
|
-
reduce
|
|
120
|
+
reduce(callback: (accumulator: number, value: number, index: number, range: PyRange) => number): number;
|
|
121
|
+
reduce(callback: (accumulator: number, value: number, index: number, range: PyRange) => number, initialValue: number): number;
|
|
122
|
+
reduce<U>(callback: (accumulator: U, value: number, index: number, range: PyRange) => U, initialValue: U): U;
|
|
104
123
|
/**
|
|
105
124
|
* Determines whether at least one element of the range satisfies the
|
|
106
125
|
* provided test.
|
|
@@ -149,19 +168,19 @@ declare class PyRange implements Iterable<number> {
|
|
|
149
168
|
* @param {any} value - The value to search for.
|
|
150
169
|
* @returns {boolean} True if the value is present, false otherwise.
|
|
151
170
|
*/
|
|
152
|
-
includes(value:
|
|
171
|
+
includes(value: unknown): boolean;
|
|
153
172
|
/**
|
|
154
173
|
* Returns the index of the first occurrence of the specified value, or -1 if it is not present.
|
|
155
174
|
* @param {any} value - The value to search for.
|
|
156
175
|
* @returns {number} The index of the value, or -1 if it is not present.
|
|
157
176
|
*/
|
|
158
|
-
indexOf(value:
|
|
177
|
+
indexOf(value: unknown): number;
|
|
159
178
|
/**
|
|
160
179
|
* Returns the index of the last occurrence of the specified value, or -1 if it is not present.
|
|
161
180
|
* @param {any} value - The value to search for.
|
|
162
181
|
* @returns {number} The index of the last occurrence of the value, or -1 if it is not present.
|
|
163
182
|
*/
|
|
164
|
-
lastIndexOf(value:
|
|
183
|
+
lastIndexOf(value: unknown): number;
|
|
165
184
|
/**
|
|
166
185
|
* Removes the last element from the range and returns it.
|
|
167
186
|
*
|
|
@@ -189,6 +208,10 @@ declare class PyRange implements Iterable<number> {
|
|
|
189
208
|
slice(begin?: number, end?: number): PyRange;
|
|
190
209
|
/**
|
|
191
210
|
* Reverses the order of the elements in this range, returning a new PyRange object.
|
|
211
|
+
*
|
|
212
|
+
* The new range starts at the last actual element of this range and steps
|
|
213
|
+
* in the opposite direction. The original range is not modified.
|
|
214
|
+
*
|
|
192
215
|
* @returns {PyRange} A new PyRange object with the elements in reverse order.
|
|
193
216
|
*/
|
|
194
217
|
reverse(): PyRange;
|
|
@@ -219,17 +242,19 @@ declare class PyRange implements Iterable<number> {
|
|
|
219
242
|
values(): IterableIterator<number>;
|
|
220
243
|
/**
|
|
221
244
|
* Implements the iterable protocol for this range.
|
|
222
|
-
* @returns {
|
|
245
|
+
* @returns {IterableIterator<number>} An iterator for this range.
|
|
223
246
|
*/
|
|
224
|
-
[Symbol.iterator]():
|
|
247
|
+
[Symbol.iterator](): IterableIterator<number>;
|
|
225
248
|
/**
|
|
226
249
|
* Returns a Proxy for this range, allowing indexed access.
|
|
227
250
|
* This proxy enables accessing range elements via array-like indexing.
|
|
228
251
|
* If the property is a number, it will return the element at that index.
|
|
229
252
|
*
|
|
230
|
-
* @returns {
|
|
253
|
+
* @returns {PyRange & { [key: number]: number | undefined }} A proxy for the PyRange instance.
|
|
231
254
|
*/
|
|
232
|
-
asProxy():
|
|
255
|
+
asProxy(): PyRange & {
|
|
256
|
+
[key: number]: number | undefined;
|
|
257
|
+
};
|
|
233
258
|
}
|
|
234
259
|
export { PyRange };
|
|
235
260
|
export default PyRange;
|
package/dist/py-range.js
CHANGED
|
@@ -5,21 +5,22 @@ exports.PyRange = void 0;
|
|
|
5
5
|
* A class that simulates Python's range function, combined with several useful JavaScript array methods.
|
|
6
6
|
*/
|
|
7
7
|
class PyRange {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
8
|
+
_start;
|
|
9
|
+
_stop;
|
|
10
|
+
_step;
|
|
11
|
+
_length;
|
|
12
|
+
static toIntegerOrInfinity(value) {
|
|
13
|
+
const numeric = +value;
|
|
14
|
+
return Number.isNaN(numeric) ? 0 : Math.trunc(numeric);
|
|
15
|
+
}
|
|
16
|
+
static isArrayIndexProperty(prop) {
|
|
17
|
+
const index = Number(prop);
|
|
18
|
+
return (prop !== "" &&
|
|
19
|
+
Number.isInteger(index) &&
|
|
20
|
+
index >= 0 &&
|
|
21
|
+
index < 2 ** 32 - 1 &&
|
|
22
|
+
String(index) === prop);
|
|
23
|
+
}
|
|
23
24
|
constructor(...args) {
|
|
24
25
|
if (!args.every((arg) => typeof arg === "number")) {
|
|
25
26
|
throw new TypeError("All arguments must be numbers");
|
|
@@ -83,15 +84,23 @@ class PyRange {
|
|
|
83
84
|
}
|
|
84
85
|
/**
|
|
85
86
|
* Gets the value at the specified index in this range.
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
87
|
+
*
|
|
88
|
+
* Negative indices are supported and wrap from the end, matching the
|
|
89
|
+
* behaviour of `Array.prototype.at()`. For example, `at(-1)` returns the
|
|
90
|
+
* last element.
|
|
91
|
+
*
|
|
92
|
+
* @param {number} index - The index of the value to retrieve. Negative
|
|
93
|
+
* indices count from the end of the range.
|
|
94
|
+
* @returns {number|undefined} The value at the specified index, or
|
|
95
|
+
* undefined when the normalised index is out of range.
|
|
89
96
|
*/
|
|
90
97
|
at(index) {
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
const relativeIndex = PyRange.toIntegerOrInfinity(index);
|
|
99
|
+
const normalised = relativeIndex < 0 ? this._length + relativeIndex : relativeIndex;
|
|
100
|
+
if (normalised < 0 || normalised >= this._length) {
|
|
101
|
+
return undefined;
|
|
93
102
|
}
|
|
94
|
-
return this._start +
|
|
103
|
+
return this._start + normalised * this._step;
|
|
95
104
|
}
|
|
96
105
|
/**
|
|
97
106
|
* Converts the range to a string.
|
|
@@ -111,6 +120,7 @@ class PyRange {
|
|
|
111
120
|
* Validates that the callback is a function.
|
|
112
121
|
* @param {Function} cb - The callback to validate.
|
|
113
122
|
* @throws {TypeError} If the callback is not a function.
|
|
123
|
+
* @internal
|
|
114
124
|
*/
|
|
115
125
|
static validateCb(cb) {
|
|
116
126
|
if (typeof cb !== "function") {
|
|
@@ -151,25 +161,16 @@ class PyRange {
|
|
|
151
161
|
}
|
|
152
162
|
return result;
|
|
153
163
|
}
|
|
154
|
-
|
|
155
|
-
* Reduces the range to a single value.
|
|
156
|
-
* @param {function(T, number, number, PyRange): T} callback - The callback
|
|
157
|
-
* function to apply to every element. The callback should take four
|
|
158
|
-
* arguments: the accumulator, the current value, the index of the current
|
|
159
|
-
* value, and the range object.
|
|
160
|
-
* @param {T} [initialValue] - The initial value of the accumulator.
|
|
161
|
-
* @returns {T} The final value of the accumulator.
|
|
162
|
-
* @template T
|
|
163
|
-
*/
|
|
164
|
-
reduce(callback, initialValue) {
|
|
164
|
+
reduce(callback, ...args) {
|
|
165
165
|
PyRange.validateCb(callback);
|
|
166
|
-
|
|
166
|
+
const hasInitial = args.length > 0;
|
|
167
|
+
if (this._length === 0 && !hasInitial) {
|
|
167
168
|
throw new TypeError("Reduce of empty range with no initial value");
|
|
168
169
|
}
|
|
169
170
|
let accumulator;
|
|
170
171
|
let startIndex;
|
|
171
|
-
if (
|
|
172
|
-
accumulator =
|
|
172
|
+
if (hasInitial) {
|
|
173
|
+
accumulator = args[0];
|
|
173
174
|
startIndex = 0;
|
|
174
175
|
}
|
|
175
176
|
else {
|
|
@@ -373,13 +374,22 @@ class PyRange {
|
|
|
373
374
|
}
|
|
374
375
|
/**
|
|
375
376
|
* Reverses the order of the elements in this range, returning a new PyRange object.
|
|
377
|
+
*
|
|
378
|
+
* The new range starts at the last actual element of this range and steps
|
|
379
|
+
* in the opposite direction. The original range is not modified.
|
|
380
|
+
*
|
|
376
381
|
* @returns {PyRange} A new PyRange object with the elements in reverse order.
|
|
377
382
|
*/
|
|
378
383
|
reverse() {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
384
|
+
if (this._length === 0) {
|
|
385
|
+
// Return an empty range with the same step direction — nothing to reverse
|
|
386
|
+
return new PyRange(this._start, this._start, this._step);
|
|
387
|
+
}
|
|
388
|
+
// The new start is the last actual element (not _stop which is exclusive)
|
|
389
|
+
const newStart = this.at(this._length - 1);
|
|
390
|
+
// The new stop is one step past the first element in the new direction
|
|
391
|
+
const newStop = this._start - this._step;
|
|
392
|
+
return new PyRange(newStart, newStop, -this._step);
|
|
383
393
|
}
|
|
384
394
|
/**
|
|
385
395
|
* Returns an iterator of `[index, value]` pairs for each element in the range.
|
|
@@ -418,7 +428,7 @@ class PyRange {
|
|
|
418
428
|
}
|
|
419
429
|
/**
|
|
420
430
|
* Implements the iterable protocol for this range.
|
|
421
|
-
* @returns {
|
|
431
|
+
* @returns {IterableIterator<number>} An iterator for this range.
|
|
422
432
|
*/
|
|
423
433
|
[Symbol.iterator]() {
|
|
424
434
|
let index = 0;
|
|
@@ -436,6 +446,9 @@ class PyRange {
|
|
|
436
446
|
return { value, done: false };
|
|
437
447
|
}
|
|
438
448
|
},
|
|
449
|
+
[Symbol.iterator]() {
|
|
450
|
+
return this;
|
|
451
|
+
},
|
|
439
452
|
};
|
|
440
453
|
}
|
|
441
454
|
/**
|
|
@@ -443,18 +456,22 @@ class PyRange {
|
|
|
443
456
|
* This proxy enables accessing range elements via array-like indexing.
|
|
444
457
|
* If the property is a number, it will return the element at that index.
|
|
445
458
|
*
|
|
446
|
-
* @returns {
|
|
459
|
+
* @returns {PyRange & { [key: number]: number | undefined }} A proxy for the PyRange instance.
|
|
447
460
|
*/
|
|
448
461
|
asProxy() {
|
|
449
462
|
return new Proxy(this, {
|
|
450
|
-
get(target, prop) {
|
|
463
|
+
get(target, prop, receiver) {
|
|
451
464
|
if (typeof prop === "symbol") {
|
|
452
|
-
return target
|
|
465
|
+
return Reflect.get(target, prop, receiver);
|
|
453
466
|
}
|
|
454
|
-
if (
|
|
455
|
-
|
|
467
|
+
if (PyRange.isArrayIndexProperty(prop)) {
|
|
468
|
+
const idx = Number(prop);
|
|
469
|
+
// Match Array behaviour: out-of-bounds returns undefined, not throw
|
|
470
|
+
if (idx >= target.length)
|
|
471
|
+
return undefined;
|
|
472
|
+
return target.at(idx);
|
|
456
473
|
}
|
|
457
|
-
return target
|
|
474
|
+
return Reflect.get(target, prop, receiver);
|
|
458
475
|
},
|
|
459
476
|
});
|
|
460
477
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "range-pie",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "A TypeScript class that simulates Python's range function, combined with several useful JavaScript array methods.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -22,22 +22,27 @@
|
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "tsc",
|
|
25
|
+
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|
|
25
26
|
"build:prod": "tsc -p tsconfig.prod.json",
|
|
26
27
|
"build:watch": "tsc --watch",
|
|
28
|
+
"prepare": "husky",
|
|
27
29
|
"prepublishOnly": "npm run build:prod && npm run test",
|
|
28
30
|
"test": "jest",
|
|
31
|
+
"test:watch": "jest --watch",
|
|
32
|
+
"test:coverage": "jest --coverage",
|
|
29
33
|
"lint": "eslint . --ext .ts,.js",
|
|
30
34
|
"lint:fix": "eslint . --ext .ts,.js --fix",
|
|
31
|
-
"test:watch": "jest --watch",
|
|
32
35
|
"clean": "rimraf dist",
|
|
33
|
-
"format": "prettier --write
|
|
34
|
-
"format:check": "prettier --check
|
|
36
|
+
"format": "prettier --write .",
|
|
37
|
+
"format:check": "prettier --check .",
|
|
35
38
|
"example:basic": "node examples/basic-usage.js",
|
|
36
39
|
"example:array": "node examples/array-methods.js",
|
|
37
40
|
"example:advanced": "node examples/advanced-usage.js",
|
|
38
41
|
"example:ts": "ts-node examples/typescript-usage.ts",
|
|
39
42
|
"example:methods": "for file in examples/methods/*.ts; do echo \"\\n=== Running $file ===\"; ts-node \"$file\"; done",
|
|
40
|
-
"knip": "knip"
|
|
43
|
+
"knip": "knip",
|
|
44
|
+
"lint-staged": "lint-staged",
|
|
45
|
+
"precommit": "npm run typecheck && npm run lint-staged"
|
|
41
46
|
},
|
|
42
47
|
"keywords": [
|
|
43
48
|
"range",
|
|
@@ -57,18 +62,23 @@
|
|
|
57
62
|
"url": "git+https://github.com/SkorpionG/range-pie.git"
|
|
58
63
|
},
|
|
59
64
|
"devDependencies": {
|
|
60
|
-
"@eslint/js": "^
|
|
61
|
-
"@types/jest": "^
|
|
62
|
-
"@types/node": "^
|
|
63
|
-
"eslint": "^
|
|
64
|
-
"globals": "^
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
65
|
+
"@eslint/js": "^10.0.1",
|
|
66
|
+
"@types/jest": "^30.0.0",
|
|
67
|
+
"@types/node": "^26.0.1",
|
|
68
|
+
"eslint": "^10.6.0",
|
|
69
|
+
"globals": "^17.7.0",
|
|
70
|
+
"husky": "^9.1.7",
|
|
71
|
+
"jest": "^30.4.2",
|
|
72
|
+
"knip": "^6.23.0",
|
|
73
|
+
"lint-staged": "^17.0.8",
|
|
74
|
+
"prettier": "^3.9.1",
|
|
75
|
+
"rimraf": "^6.1.3",
|
|
76
|
+
"ts-jest": "^29.4.11",
|
|
77
|
+
"ts-node": "^10.9.2",
|
|
78
|
+
"typescript": "^6.0.3",
|
|
79
|
+
"typescript-eslint": "^8.62.0"
|
|
80
|
+
},
|
|
81
|
+
"overrides": {
|
|
82
|
+
"js-yaml": "^4.1.2"
|
|
73
83
|
}
|
|
74
84
|
}
|