range-pie 1.0.1 → 2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 SkorpionG2000
3
+ Copyright (c) 2025 SkorpionG2000
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,11 +1,15 @@
1
1
  # range-pie
2
2
 
3
- A 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.
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
5
  ## Table of Contents
6
6
 
7
7
  - [Installation](#installation)
8
8
  - [Basic Usage](#basic-usage)
9
+
10
+ - [JavaScript](#javascript)
11
+ - [TypeScript](#typescript)
12
+
9
13
  - [API Reference](#api-reference)
10
14
 
11
15
  - [Constructor Options](#constructor-options)
@@ -36,6 +40,9 @@ A JavaScript library that brings Python's range functionality to JavaScript, enh
36
40
 
37
41
  - [Methods chaining](#methods-chaining)
38
42
  - [Using as Array-like Object](#using-as-array-like-object)
43
+ - [Example Files](#example-files)
44
+ - [Running the Examples](#running-the-examples)
45
+ - [Available Examples](#available-examples)
39
46
 
40
47
  ## Installation
41
48
 
@@ -45,7 +52,10 @@ npm install range-pie
45
52
 
46
53
  ## Basic Usage
47
54
 
55
+ ### JavaScript
56
+
48
57
  ```javascript
58
+ // CommonJS
49
59
  const { PyRange } = require('range-pie');
50
60
 
51
61
  // Create a range from 0 to 5
@@ -61,6 +71,25 @@ const range3 = new PyRange(0, 10, 2);
61
71
  console.log([...range3]); // [0, 2, 4, 6, 8]
62
72
  ```
63
73
 
74
+ ### TypeScript
75
+
76
+ ```typescript
77
+ // ES Modules
78
+ import { PyRange } from 'range-pie';
79
+
80
+ // Create a range from 0 to 5
81
+ const range = new PyRange(5);
82
+ console.log([...range]); // [0, 1, 2, 3, 4]
83
+
84
+ // Type-safe operations
85
+ const doubledValues: number[] = range.map(x => x * 2);
86
+ console.log(doubledValues); // [0, 2, 4, 6, 8]
87
+
88
+ // Type inference works with generics
89
+ const stringValues: string[] = range.map(x => `Value: ${x}`);
90
+ console.log(stringValues); // ['Value: 0', 'Value: 1', 'Value: 2', 'Value: 3', 'Value: 4']
91
+ ```
92
+
64
93
  ## API Reference
65
94
 
66
95
  ### Constructor Options
@@ -304,6 +333,29 @@ console.log(proxy[0]); // 0
304
333
  console.log(proxy[3]); // 3
305
334
  ```
306
335
 
336
+ ### TypeScript Support
337
+
338
+ This package is written in TypeScript and provides full type definitions for all methods and properties. TypeScript users get the following benefits:
339
+
340
+ - Type checking for all method parameters and return values
341
+ - Autocompletion in IDEs
342
+ - Generic type support for methods like `map()` and `reduce()`
343
+ - Better documentation through type annotations
344
+
345
+ ```typescript
346
+ // Type inference with generics
347
+ const range = new PyRange(5);
348
+
349
+ // TypeScript knows this is a number[]
350
+ const numbers = range.map(x => x * 2);
351
+
352
+ // TypeScript knows this is a string[]
353
+ const strings = range.map(x => `Number: ${x}`);
354
+
355
+ // TypeScript knows this is a boolean[]
356
+ const booleans = range.map(x => x % 2 === 0);
357
+ ```
358
+
307
359
  ## Examples
308
360
 
309
361
  ### Methods chaining
@@ -323,3 +375,43 @@ const range = new PyRange(5).asProxy();
323
375
  const firstThree = [range[0], range[1], range[2]];
324
376
  console.log(firstThree); // [0, 1, 2]
325
377
  ```
378
+
379
+ ### Example Files
380
+
381
+ This package includes several example files to help you get started. You can find them in the `examples` directory after installing the package.
382
+
383
+ #### Running the Examples
384
+
385
+ If you've cloned the repository, you can run the examples using npm scripts:
386
+
387
+ ```bash
388
+ # Run basic usage examples
389
+ npm run example:basic
390
+
391
+ # Run array methods examples
392
+ npm run example:array
393
+
394
+ # Run advanced usage examples
395
+ npm run example:advanced
396
+
397
+ # Run TypeScript examples (requires ts-node)
398
+ npm run example:ts
399
+ ```
400
+
401
+ Or you can run them directly with Node.js:
402
+
403
+ ```bash
404
+ node node_modules/range-pie/examples/basic-usage.js
405
+ node node_modules/range-pie/examples/array-methods.js
406
+ node node_modules/range-pie/examples/advanced-usage.js
407
+
408
+ # For TypeScript examples
409
+ ts-node node_modules/range-pie/examples/typescript-usage.ts
410
+ ```
411
+
412
+ #### Available Examples
413
+
414
+ - **basic-usage.js**: Shows fundamental PyRange operations
415
+ - **array-methods.js**: Demonstrates all array-like methods
416
+ - **advanced-usage.js**: Covers advanced features like method chaining and proxy usage
417
+ - **typescript-usage.ts**: Shows TypeScript-specific features and type safety
@@ -0,0 +1,3 @@
1
+ import PyRange, { PyRange as PyRangeClass } from "./py-range";
2
+ export { PyRangeClass as PyRange };
3
+ export default PyRange;
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.PyRange = void 0;
37
+ const py_range_1 = __importStar(require("./py-range"));
38
+ Object.defineProperty(exports, "PyRange", { enumerable: true, get: function () { return py_range_1.PyRange; } });
39
+ exports.default = py_range_1.default;
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uDAA8D;AAGrC,wFAHI,kBAAY,OAGT;AAChC,kBAAe,kBAAO,CAAC"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * A class that simulates Python's range function, combined with several useful JavaScript array methods.
3
+ */
4
+ declare class PyRange implements Iterable<number> {
5
+ private _start;
6
+ private _stop;
7
+ private _step;
8
+ private _length;
9
+ /**
10
+ * Creates a new PyRange instance.
11
+ * @param {...number} args - The arguments of the range. The possible forms are
12
+ * - `PyRange(stop)`
13
+ * - `PyRange(start, stop)`
14
+ * - `PyRange(start, stop, step)`
15
+ * @throws {TypeError} If any of the arguments is not a number.
16
+ * @throws {TypeError} If any of the arguments is not an integer.
17
+ * @throws {Error} If the step is zero.
18
+ * @throws {Error} If the arguments count is not between 1 and 3.
19
+ * @property {number} start - The start of the range, inclusive.
20
+ * @property {number} stop - The stop of the range, exclusive.
21
+ * @property {number} step - The step of the range.
22
+ * @property {number} length - The length of the range.
23
+ */
24
+ constructor(...args: number[]);
25
+ /**
26
+ * Gets the length of this range.
27
+ *
28
+ * @returns {number} the length of this range
29
+ * @readonly
30
+ */
31
+ get length(): number;
32
+ /**
33
+ * Gets the starting value of the range.
34
+ *
35
+ * @returns {number} The starting value of the range.
36
+ * @readonly
37
+ */
38
+ get start(): number;
39
+ /**
40
+ * Gets the ending value of the range.
41
+ *
42
+ * @returns {number} The ending value of the range.
43
+ * @readonly
44
+ */
45
+ get stop(): number;
46
+ /**
47
+ * Gets the step value of the range.
48
+ *
49
+ * @returns {number} The step value of the range.
50
+ * @readonly
51
+ */
52
+ get step(): number;
53
+ /**
54
+ * Gets the value at the specified index in this range.
55
+ * @param {number} index - The index of the value to retrieve
56
+ * @returns {number} The value at the specified index
57
+ * @throws {RangeError} If the index is out of range
58
+ */
59
+ at(index: number): number;
60
+ /**
61
+ * Converts the range to a string.
62
+ * @returns {string} A string of the form `Range(start, stop, step)`.
63
+ */
64
+ toString(): string;
65
+ /**
66
+ * Converts the range to an array.
67
+ * @returns {number[]} An array of numbers with the same elements as this range.
68
+ */
69
+ toArray(): number[];
70
+ /**
71
+ * Validates that the callback is a function.
72
+ * @param {Function} cb - The callback to validate.
73
+ * @throws {TypeError} If the callback is not a function.
74
+ */
75
+ private static validateCb;
76
+ /**
77
+ * Creates a new array with the results of applying the given callback
78
+ * function to every element in this range.
79
+ * @param {function(number, number, PyRange): T} callback - The callback
80
+ * function to apply to every element.
81
+ * @returns {T[]} A new array of the same length as this range.
82
+ * @template T
83
+ */
84
+ map<T>(callback: (value: number, index: number, range: PyRange) => T): T[];
85
+ /**
86
+ * Creates a new array with all elements that pass the test implemented by
87
+ * the provided function.
88
+ * @param {function(number, number, PyRange): boolean} callback - The
89
+ * predicate function to apply to every element
90
+ * @returns {number[]} A new array of elements that pass the test
91
+ */
92
+ filter(callback: (value: number, index: number, range: PyRange) => boolean): number[];
93
+ /**
94
+ * Reduces the range to a single value.
95
+ * @param {function(T, number, number, PyRange): T} callback - The callback
96
+ * function to apply to every element. The callback should take four
97
+ * arguments: the accumulator, the current value, the index of the current
98
+ * value, and the range object.
99
+ * @param {T} [initialValue] - The initial value of the accumulator.
100
+ * @returns {T} The final value of the accumulator.
101
+ * @template T
102
+ */
103
+ reduce<T>(callback: (accumulator: T, value: number, index: number, range: PyRange) => T, initialValue?: T): T;
104
+ /**
105
+ * Determines whether at least one element of the range satisfies the
106
+ * provided test.
107
+ * @param {function(number, number, PyRange): boolean} callback - The
108
+ * predicate function to apply to every element
109
+ * @returns {boolean} True if at least one element of the range passes the
110
+ * test, false otherwise.
111
+ */
112
+ some(callback: (value: number, index: number, range: PyRange) => boolean): boolean;
113
+ /**
114
+ * Determines whether all elements of the range satisfy the provided test.
115
+ * @param {function(number, number, PyRange): boolean} callback - The
116
+ * predicate function to apply to every element
117
+ * @returns {boolean} True if all elements of the range pass the test,
118
+ * false otherwise.
119
+ */
120
+ every(callback: (value: number, index: number, range: PyRange) => boolean): boolean;
121
+ /**
122
+ * Finds the first element in this range that satisfies the provided test.
123
+ * @param {function(number, number, PyRange): boolean} callback - The
124
+ * predicate function to apply to every element
125
+ * @returns {number|undefined} The first element that passes the test,
126
+ * or undefined if no element passes the test.
127
+ */
128
+ find(callback: (value: number, index: number, range: PyRange) => boolean): number | undefined;
129
+ /**
130
+ * Finds the index of the first element in this range that satisfies the provided test.
131
+ * @param {function(number, number, PyRange): boolean} callback - The predicate function to apply to each element.
132
+ * @returns {number} The index of the first element that passes the test, or -1 if no element passes the test.
133
+ */
134
+ findIndex(callback: (value: number, index: number, range: PyRange) => boolean): number;
135
+ /**
136
+ * Finds the index of the last element in this range that satisfies the provided test.
137
+ * @param {function(number, number, PyRange): boolean} callback - The predicate function to apply to each element.
138
+ * @returns {number} The index of the last element that passes the test, or -1 if no element passes the test.
139
+ */
140
+ findLastIndex(callback: (value: number, index: number, range: PyRange) => boolean): number;
141
+ /**
142
+ * Executes a provided function once for each element in this range.
143
+ * @param {function(number, number, PyRange): void} callback - The
144
+ * function to execute for each element.
145
+ */
146
+ forEach(callback: (value: number, index: number, range: PyRange) => void): void;
147
+ /**
148
+ * Determines whether the given value is present in this range.
149
+ * @param {any} value - The value to search for.
150
+ * @returns {boolean} True if the value is present, false otherwise.
151
+ */
152
+ includes(value: any): boolean;
153
+ /**
154
+ * Returns the index of the first occurrence of the specified value, or -1 if it is not present.
155
+ * @param {any} value - The value to search for.
156
+ * @returns {number} The index of the value, or -1 if it is not present.
157
+ */
158
+ indexOf(value: any): number;
159
+ /**
160
+ * Returns the index of the last occurrence of the specified value, or -1 if it is not present.
161
+ * @param {any} value - The value to search for.
162
+ * @returns {number} The index of the last occurrence of the value, or -1 if it is not present.
163
+ */
164
+ lastIndexOf(value: any): number;
165
+ /**
166
+ * Reverses the order of the elements in this range, returning a new PyRange object.
167
+ * @returns {PyRange} A new PyRange object with the elements in reverse order.
168
+ */
169
+ reverse(): PyRange;
170
+ /**
171
+ * Implements the iterable protocol for this range.
172
+ * @returns {Iterator<number>} An iterator for this range.
173
+ */
174
+ [Symbol.iterator](): Iterator<number>;
175
+ /**
176
+ * Returns a Proxy for this range, allowing indexed access.
177
+ * This proxy enables accessing range elements via array-like indexing.
178
+ * If the property is a number, it will return the element at that index.
179
+ *
180
+ * @returns {any} A proxy for the PyRange instance.
181
+ */
182
+ asProxy(): any;
183
+ }
184
+ export { PyRange };
185
+ export default PyRange;
@@ -0,0 +1,361 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PyRange = void 0;
4
+ /**
5
+ * A class that simulates Python's range function, combined with several useful JavaScript array methods.
6
+ */
7
+ class PyRange {
8
+ /**
9
+ * Creates a new PyRange instance.
10
+ * @param {...number} args - The arguments of the range. The possible forms are
11
+ * - `PyRange(stop)`
12
+ * - `PyRange(start, stop)`
13
+ * - `PyRange(start, stop, step)`
14
+ * @throws {TypeError} If any of the arguments is not a number.
15
+ * @throws {TypeError} If any of the arguments is not an integer.
16
+ * @throws {Error} If the step is zero.
17
+ * @throws {Error} If the arguments count is not between 1 and 3.
18
+ * @property {number} start - The start of the range, inclusive.
19
+ * @property {number} stop - The stop of the range, exclusive.
20
+ * @property {number} step - The step of the range.
21
+ * @property {number} length - The length of the range.
22
+ */
23
+ constructor(...args) {
24
+ if (!args.every((arg) => typeof arg === "number")) {
25
+ throw new TypeError("All arguments must be numbers");
26
+ }
27
+ if (!args.every(Number.isInteger)) {
28
+ throw new TypeError("All arguments must be integers");
29
+ }
30
+ const [start, stop, step] = args.length === 1
31
+ ? [0, args[0], 1]
32
+ : args.length === 2
33
+ ? [args[0], args[1], 1]
34
+ : args.length === 3
35
+ ? [args[0], args[1], args[2]]
36
+ : (() => {
37
+ throw new Error("Invalid arguments count: must between 1 and 3");
38
+ })();
39
+ if (step === 0) {
40
+ throw new Error("Step cannot be zero");
41
+ }
42
+ this._start = start;
43
+ this._stop = stop;
44
+ this._step = stop < start && args.length !== 3 ? -step : step;
45
+ const diff = this._step > 0 ? stop - start : start - stop;
46
+ this._length = Math.max(Math.ceil(diff / Math.abs(this._step)), 0);
47
+ }
48
+ /**
49
+ * Gets the length of this range.
50
+ *
51
+ * @returns {number} the length of this range
52
+ * @readonly
53
+ */
54
+ get length() {
55
+ return this._length;
56
+ }
57
+ /**
58
+ * Gets the starting value of the range.
59
+ *
60
+ * @returns {number} The starting value of the range.
61
+ * @readonly
62
+ */
63
+ get start() {
64
+ return this._start;
65
+ }
66
+ /**
67
+ * Gets the ending value of the range.
68
+ *
69
+ * @returns {number} The ending value of the range.
70
+ * @readonly
71
+ */
72
+ get stop() {
73
+ return this._stop;
74
+ }
75
+ /**
76
+ * Gets the step value of the range.
77
+ *
78
+ * @returns {number} The step value of the range.
79
+ * @readonly
80
+ */
81
+ get step() {
82
+ return this._step;
83
+ }
84
+ /**
85
+ * Gets the value at the specified index in this range.
86
+ * @param {number} index - The index of the value to retrieve
87
+ * @returns {number} The value at the specified index
88
+ * @throws {RangeError} If the index is out of range
89
+ */
90
+ at(index) {
91
+ if (index < 0 || index >= this._length) {
92
+ throw new RangeError("Index out of range");
93
+ }
94
+ return this._start + index * this._step;
95
+ }
96
+ /**
97
+ * Converts the range to a string.
98
+ * @returns {string} A string of the form `Range(start, stop, step)`.
99
+ */
100
+ toString() {
101
+ return `PyRange(${this._start}, ${this._stop}, ${this._step})`;
102
+ }
103
+ /**
104
+ * Converts the range to an array.
105
+ * @returns {number[]} An array of numbers with the same elements as this range.
106
+ */
107
+ toArray() {
108
+ return [...this];
109
+ }
110
+ /**
111
+ * Validates that the callback is a function.
112
+ * @param {Function} cb - The callback to validate.
113
+ * @throws {TypeError} If the callback is not a function.
114
+ */
115
+ static validateCb(cb) {
116
+ if (typeof cb !== "function") {
117
+ throw new TypeError("Callback must be a function");
118
+ }
119
+ }
120
+ /**
121
+ * Creates a new array with the results of applying the given callback
122
+ * function to every element in this range.
123
+ * @param {function(number, number, PyRange): T} callback - The callback
124
+ * function to apply to every element.
125
+ * @returns {T[]} A new array of the same length as this range.
126
+ * @template T
127
+ */
128
+ map(callback) {
129
+ PyRange.validateCb(callback);
130
+ const result = new Array(this._length);
131
+ for (let i = 0; i < this._length; i++) {
132
+ result[i] = callback(this.at(i), i, this);
133
+ }
134
+ return result;
135
+ }
136
+ /**
137
+ * Creates a new array with all elements that pass the test implemented by
138
+ * the provided function.
139
+ * @param {function(number, number, PyRange): boolean} callback - The
140
+ * predicate function to apply to every element
141
+ * @returns {number[]} A new array of elements that pass the test
142
+ */
143
+ filter(callback) {
144
+ PyRange.validateCb(callback);
145
+ const result = [];
146
+ for (let i = 0; i < this._length; i++) {
147
+ const value = this.at(i);
148
+ if (callback(value, i, this)) {
149
+ result.push(value);
150
+ }
151
+ }
152
+ return result;
153
+ }
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) {
165
+ PyRange.validateCb(callback);
166
+ if (this._length === 0 && initialValue === undefined) {
167
+ throw new TypeError("Reduce of empty range with no initial value");
168
+ }
169
+ let accumulator;
170
+ let startIndex;
171
+ if (initialValue !== undefined) {
172
+ accumulator = initialValue;
173
+ startIndex = 0;
174
+ }
175
+ else {
176
+ accumulator = this.at(0);
177
+ startIndex = 1;
178
+ }
179
+ for (let i = startIndex; i < this._length; i++) {
180
+ accumulator = callback(accumulator, this.at(i), i, this);
181
+ }
182
+ return accumulator;
183
+ }
184
+ /**
185
+ * Determines whether at least one element of the range satisfies the
186
+ * provided test.
187
+ * @param {function(number, number, PyRange): boolean} callback - The
188
+ * predicate function to apply to every element
189
+ * @returns {boolean} True if at least one element of the range passes the
190
+ * test, false otherwise.
191
+ */
192
+ some(callback) {
193
+ PyRange.validateCb(callback);
194
+ for (let i = 0; i < this._length; i++) {
195
+ if (callback(this.at(i), i, this)) {
196
+ return true;
197
+ }
198
+ }
199
+ return false;
200
+ }
201
+ /**
202
+ * Determines whether all elements of the range satisfy the provided test.
203
+ * @param {function(number, number, PyRange): boolean} callback - The
204
+ * predicate function to apply to every element
205
+ * @returns {boolean} True if all elements of the range pass the test,
206
+ * false otherwise.
207
+ */
208
+ every(callback) {
209
+ PyRange.validateCb(callback);
210
+ for (let i = 0; i < this._length; i++) {
211
+ if (!callback(this.at(i), i, this)) {
212
+ return false;
213
+ }
214
+ }
215
+ return true;
216
+ }
217
+ /**
218
+ * Finds the first element in this range that satisfies the provided test.
219
+ * @param {function(number, number, PyRange): boolean} callback - The
220
+ * predicate function to apply to every element
221
+ * @returns {number|undefined} The first element that passes the test,
222
+ * or undefined if no element passes the test.
223
+ */
224
+ find(callback) {
225
+ PyRange.validateCb(callback);
226
+ for (let i = 0; i < this._length; i++) {
227
+ if (callback(this.at(i), i, this)) {
228
+ return this.at(i);
229
+ }
230
+ }
231
+ return undefined;
232
+ }
233
+ /**
234
+ * Finds the index of the first element in this range that satisfies the provided test.
235
+ * @param {function(number, number, PyRange): boolean} callback - The predicate function to apply to each element.
236
+ * @returns {number} The index of the first element that passes the test, or -1 if no element passes the test.
237
+ */
238
+ findIndex(callback) {
239
+ PyRange.validateCb(callback);
240
+ for (let i = 0; i < this._length; i++) {
241
+ if (callback(this.at(i), i, this)) {
242
+ return i;
243
+ }
244
+ }
245
+ return -1;
246
+ }
247
+ /**
248
+ * Finds the index of the last element in this range that satisfies the provided test.
249
+ * @param {function(number, number, PyRange): boolean} callback - The predicate function to apply to each element.
250
+ * @returns {number} The index of the last element that passes the test, or -1 if no element passes the test.
251
+ */
252
+ findLastIndex(callback) {
253
+ PyRange.validateCb(callback);
254
+ for (let i = this._length - 1; i >= 0; i--) {
255
+ if (callback(this.at(i), i, this)) {
256
+ return i;
257
+ }
258
+ }
259
+ return -1;
260
+ }
261
+ /**
262
+ * Executes a provided function once for each element in this range.
263
+ * @param {function(number, number, PyRange): void} callback - The
264
+ * function to execute for each element.
265
+ */
266
+ forEach(callback) {
267
+ PyRange.validateCb(callback);
268
+ for (let i = 0; i < this._length; i++) {
269
+ callback(this.at(i), i, this);
270
+ }
271
+ }
272
+ /**
273
+ * Determines whether the given value is present in this range.
274
+ * @param {any} value - The value to search for.
275
+ * @returns {boolean} True if the value is present, false otherwise.
276
+ */
277
+ includes(value) {
278
+ return this.some((item) => item === value);
279
+ }
280
+ /**
281
+ * Returns the index of the first occurrence of the specified value, or -1 if it is not present.
282
+ * @param {any} value - The value to search for.
283
+ * @returns {number} The index of the value, or -1 if it is not present.
284
+ */
285
+ indexOf(value) {
286
+ for (let i = 0; i < this._length; i++) {
287
+ if (this.at(i) === value) {
288
+ return i;
289
+ }
290
+ }
291
+ return -1;
292
+ }
293
+ /**
294
+ * Returns the index of the last occurrence of the specified value, or -1 if it is not present.
295
+ * @param {any} value - The value to search for.
296
+ * @returns {number} The index of the last occurrence of the value, or -1 if it is not present.
297
+ */
298
+ lastIndexOf(value) {
299
+ for (let i = this._length - 1; i >= 0; i--) {
300
+ if (this.at(i) === value) {
301
+ return i;
302
+ }
303
+ }
304
+ return -1;
305
+ }
306
+ /**
307
+ * Reverses the order of the elements in this range, returning a new PyRange object.
308
+ * @returns {PyRange} A new PyRange object with the elements in reverse order.
309
+ */
310
+ reverse() {
311
+ const result = new PyRange(this._stop, this._start, -this._step);
312
+ // Force the length to be the same as the original range
313
+ result._length = this._length;
314
+ return result;
315
+ }
316
+ /**
317
+ * Implements the iterable protocol for this range.
318
+ * @returns {Iterator<number>} An iterator for this range.
319
+ */
320
+ [Symbol.iterator]() {
321
+ let index = 0;
322
+ let current = this._start;
323
+ const { _step: step, _length: length } = this;
324
+ return {
325
+ next: () => {
326
+ if (index >= length) {
327
+ return { done: true, value: undefined };
328
+ }
329
+ else {
330
+ const value = current;
331
+ current += step;
332
+ index++;
333
+ return { value, done: false };
334
+ }
335
+ },
336
+ };
337
+ }
338
+ /**
339
+ * Returns a Proxy for this range, allowing indexed access.
340
+ * This proxy enables accessing range elements via array-like indexing.
341
+ * If the property is a number, it will return the element at that index.
342
+ *
343
+ * @returns {any} A proxy for the PyRange instance.
344
+ */
345
+ asProxy() {
346
+ return new Proxy(this, {
347
+ get(target, prop) {
348
+ if (typeof prop === "symbol") {
349
+ return target[prop];
350
+ }
351
+ if (!isNaN(Number(prop))) {
352
+ return target.at(parseInt(String(prop), 10));
353
+ }
354
+ return target[prop];
355
+ },
356
+ });
357
+ }
358
+ }
359
+ exports.PyRange = PyRange;
360
+ exports.default = PyRange;
361
+ //# sourceMappingURL=py-range.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"py-range.js","sourceRoot":"","sources":["../src/py-range.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,16 +1,30 @@
1
1
  {
2
2
  "name": "range-pie",
3
- "version": "1.0.1",
4
- "description": "A JavaScript class that simulate Python's range function, combined with several useful JavaScript array methods.",
5
- "main": "src/index.js",
3
+ "version": "2.0.0",
4
+ "description": "A TypeScript class that simulates Python's range function, combined with several useful JavaScript array methods.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
6
7
  "exports": {
7
8
  ".": {
8
- "import": "./src/index.js",
9
- "require": "./src/index.js"
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
10
12
  }
11
13
  },
14
+ "files": [
15
+ "dist"
16
+ ],
12
17
  "scripts": {
13
- "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
18
+ "build": "tsc",
19
+ "prepublishOnly": "npm run build",
20
+ "test": "jest",
21
+ "clean": "rimraf dist",
22
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\" \"examples/**/*.ts\"",
23
+ "check-format": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" \"examples/**/*.ts\"",
24
+ "example:basic": "node examples/basic-usage.js",
25
+ "example:array": "node examples/array-methods.js",
26
+ "example:advanced": "node examples/advanced-usage.js",
27
+ "example:ts": "ts-node examples/typescript-usage.ts"
14
28
  },
15
29
  "keywords": [
16
30
  "range",
@@ -20,11 +34,22 @@
20
34
  "JavaScript Array",
21
35
  "Array",
22
36
  "py-range",
23
- "PyRange"
37
+ "PyRange",
38
+ "TypeScript"
24
39
  ],
25
40
  "author": "SkorpionG2000",
26
41
  "license": "MIT",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/SkorpionG/range-pie.git"
45
+ },
27
46
  "devDependencies": {
28
- "jest": "^29.7.0"
47
+ "@types/jest": "^29.5.0",
48
+ "jest": "^29.7.0",
49
+ "prettier": "^3.5.3",
50
+ "rimraf": "^5.0.0",
51
+ "ts-jest": "^29.1.0",
52
+ "ts-node": "^10.9.1",
53
+ "typescript": "^5.0.4"
29
54
  }
30
55
  }
package/src/index.js DELETED
@@ -1,5 +0,0 @@
1
- "use strict";
2
- const PyRange = require("./py-range.js");
3
-
4
- module.exports = PyRange;
5
- module.exports.PyRange = PyRange;
package/src/py-range.js DELETED
@@ -1,376 +0,0 @@
1
- "use strict";
2
-
3
- class PyRange {
4
- /**
5
- * A class that simulate Python's range function, combined with several useful JavaScript array methods.
6
- * @param {...number} args - The arguments of the range. The possible forms are
7
- * - `PyRange(stop)`
8
- * - `PyRange(start, stop)`
9
- * - `PyRange(start, stop, step)`
10
- * @throws {TypeError} If any of the arguments is not a number.
11
- * @throws {TypeError} If any of the arguments is not an integer.
12
- * @throws {Error} If the step is zero.
13
- * @throws {Error} If the arguments count is not between 1 and 3.
14
- * @property {number} start - The start of the range, inclusive.
15
- * @property {number} stop - The stop of the range, exclusive.
16
- * @property {number} step - The step of the range.
17
- * @property {number} length - The length of the range.
18
- */
19
- constructor(...args) {
20
- if (!args.every((arg) => typeof arg === "number")) {
21
- throw new TypeError("All arguments must be numbers");
22
- }
23
-
24
- if (!args.every(Number.isInteger)) {
25
- throw new TypeError("All arguments must be integers");
26
- }
27
-
28
- const [start, stop, step] =
29
- args.length === 1
30
- ? [0, args[0], 1]
31
- : args.length === 2
32
- ? [args[0], args[1], 1]
33
- : args.length === 3
34
- ? [args[0], args[1], args[2]]
35
- : (() => {
36
- throw new Error("Invalid arguments count: must between 1 and 3");
37
- })();
38
-
39
- if (step === 0) {
40
- throw new Error("Step cannot be zero");
41
- }
42
-
43
- this._start = start;
44
- this._stop = stop;
45
- this._step = stop < start && args.length !== 3 ? -step : step;
46
-
47
- const diff = this._step > 0 ? stop - start : start - stop;
48
- this._length = Math.max(Math.ceil(diff / Math.abs(this._step)), 0);
49
- }
50
-
51
- /**
52
- * Gets the length of this range.
53
- *
54
- * @returns {number} the length of this range
55
- * @readonly
56
- */
57
- get length() {
58
- return this._length;
59
- }
60
-
61
- /**
62
- * Gets the starting value of the range.
63
- *
64
- * @returns {number} The starting value of the range.
65
- * @readonly
66
- */
67
- get start() {
68
- return this._start;
69
- }
70
-
71
- /**
72
- * Gets the ending value of the range.
73
- *
74
- * @returns {number} The ending value of the range.
75
- * @readonly
76
- */
77
- get stop() {
78
- return this._stop;
79
- }
80
-
81
- /**
82
- * Gets the step value of the range.
83
- *
84
- * @returns {number} The step value of the range.
85
- * @readonly
86
- */
87
- get step() {
88
- return this._step;
89
- }
90
-
91
- /**
92
- * Gets the value at the specified index in this range.
93
- * @param {number} index - The index of the value to retrieve
94
- * @returns {number} The value at the specified index
95
- * @throws {RangeError} If the index is out of range
96
- */
97
- at(index) {
98
- if (index < 0 || index >= this._length) {
99
- throw new RangeError("Index out of range");
100
- }
101
- return this._start + index * this._step;
102
- }
103
-
104
- /**
105
- * Converts the range to a string.
106
- * @returns {string} A string of the form `Range(start, stop, step)`.
107
- */
108
- toString() {
109
- return `PyRange(${this._start}, ${this._stop}, ${this._step})`;
110
- }
111
-
112
- /**
113
- * Converts the range to an array.
114
- * @returns {number[]} An array of numbers with the same elements as this range.
115
- */
116
- toArray() {
117
- return [...this];
118
- }
119
-
120
- static #validateCb(cb) {
121
- if (typeof cb !== "function") {
122
- throw new TypeError("Callback must be a function");
123
- }
124
- }
125
-
126
- /**
127
- * Creates a new array with the results of applying the given callback
128
- * function to every element in this range.
129
- * @param {function(number, number, PyRange): *} callback - The callback
130
- * function to apply to every element.
131
- * @returns {Array.<*>} A new array of the same length as this range.
132
- */
133
- map(callback) {
134
- PyRange.#validateCb(callback);
135
-
136
- const result = new Array(this._length);
137
-
138
- for (let i = 0; i < this._length; i++) {
139
- result[i] = callback(this.at(i), i, this);
140
- }
141
-
142
- return result;
143
- }
144
-
145
- /**
146
- * Creates a new array with all elements that pass the test implemented by
147
- * the provided function.
148
- * @param {function(number, number, PyRange): boolean} callback - The
149
- * predicate function to apply to every element
150
- * @returns {number[]} A new array of elements that pass the test
151
- */
152
- filter(callback) {
153
- PyRange.#validateCb(callback);
154
-
155
- const result = [];
156
-
157
- for (let i = 0; i < this._length; i++) {
158
- if (callback(this.at(i), i, this)) {
159
- result.push(this.at(i));
160
- }
161
- }
162
-
163
- return result;
164
- }
165
-
166
- /**
167
- * Reduces the range to a single value.
168
- * @param {function(*, number, number, PyRange): *} callback - The callback
169
- * function to apply to every element. The callback should take four
170
- * arguments: the accumulator, the current value, the index of the current
171
- * value, and the range object.
172
- * @param {*} [initialValue] - The initial value of the accumulator.
173
- * @returns {*} The final value of the accumulator.
174
- */
175
- reduce(callback, initialValue) {
176
- PyRange.#validateCb(callback);
177
-
178
- let accumulator = initialValue;
179
-
180
- for (let i = 0; i < this._length; i++) {
181
- accumulator = callback(accumulator, this.at(i), i, this);
182
- }
183
-
184
- return accumulator;
185
- }
186
-
187
- /**
188
- * Determines whether at least one element of the range satisfies the
189
- * provided test.
190
- * @param {function(number, number, PyRange): boolean} callback - The
191
- * predicate function to apply to every element
192
- * @returns {boolean} True if at least one element of the range passes the
193
- * test, false otherwise.
194
- */
195
- some(callback) {
196
- PyRange.#validateCb(callback);
197
-
198
- for (let i = 0; i < this._length; i++) {
199
- if (callback(this.at(i), i, this)) {
200
- return true;
201
- }
202
- }
203
- return false;
204
- }
205
-
206
- /**
207
- * Determines whether all elements of the range satisfy the provided test.
208
- * @param {function(number, number, PyRange): boolean} callback - The
209
- * predicate function to apply to every element
210
- * @returns {boolean} True if all elements of the range pass the test,
211
- * false otherwise.
212
- */
213
- every(callback) {
214
- PyRange.#validateCb(callback);
215
-
216
- for (let i = 0; i < this._length; i++) {
217
- if (!callback(this.at(i), i, this)) {
218
- return false;
219
- }
220
- }
221
- return true;
222
- }
223
-
224
- /**
225
- * Finds the first element in this range that satisfies the provided test.
226
- * @param {function(number, number, PyRange): boolean} callback - The
227
- * predicate function to apply to every element
228
- * @returns {number|undefined} The first element that passes the test,
229
- * or undefined if no element passes the test.
230
- */
231
- find(callback) {
232
- PyRange.#validateCb(callback);
233
-
234
- for (let i = 0; i < this._length; i++) {
235
- if (callback(this.at(i), i, this)) {
236
- return this.at(i);
237
- }
238
- }
239
- return undefined;
240
- }
241
-
242
- /**
243
- * Finds the index of the first element in this range that satisfies the provided test.
244
- * @param {function(number, number, PyRange): boolean} callback - The predicate function to apply to each element.
245
- * @returns {number} The index of the first element that passes the test, or -1 if no element passes the test.
246
- */
247
- findIndex(callback) {
248
- PyRange.#validateCb(callback);
249
-
250
- for (let i = 0; i < this._length; i++) {
251
- if (callback(this.at(i), i, this)) {
252
- return i;
253
- }
254
- }
255
- return -1;
256
- }
257
-
258
- /**
259
- * Finds the index of the last element in this range that satisfies the provided test.
260
- * @param {function(number, number, PyRange): boolean} callback - The predicate function to apply to each element.
261
- * @returns {number} The index of the last element that passes the test, or -1 if no element passes the test.
262
- */
263
- findLastIndex(callback) {
264
- PyRange.#validateCb(callback);
265
-
266
- for (let i = this._length - 1; i >= 0; i--) {
267
- if (callback(this.at(i), i, this)) {
268
- return i;
269
- }
270
- }
271
- return -1;
272
- }
273
-
274
- /**
275
- * Executes a provided function once for each element in this range.
276
- * @param {function(number, number, PyRange): void} callback - The
277
- * function to execute for each element.
278
- */
279
- forEach(callback) {
280
- PyRange.#validateCb(callback);
281
-
282
- for (let i = 0; i < this._length; i++) {
283
- callback(this.at(i), i, this);
284
- }
285
- }
286
-
287
- /**
288
- * Determines whether the given value is present in this range.
289
- * @param {*} value - The value to search for.
290
- * @returns {boolean} True if the value is present, false otherwise.
291
- */
292
- includes(value) {
293
- return this.some((item) => item === value);
294
- }
295
-
296
- /**
297
- * Returns the index of the first occurrence of the specified value, or -1 if it is not present.
298
- * @param {*} value - The value to search for.
299
- * @returns {number} The index of the value, or -1 if it is not present.
300
- */
301
- indexOf(value) {
302
- for (let i = 0; i < this._length; i++) {
303
- if (this.at(i) === value) {
304
- return i;
305
- }
306
- }
307
- return -1;
308
- }
309
-
310
- /**
311
- * Returns the index of the last occurrence of the specified value, or -1 if it is not present.
312
- * @param {*} value - The value to search for.
313
- * @returns {number} The index of the last occurrence of the value, or -1 if it is not present.
314
- */
315
- lastIndexOf(value) {
316
- for (let i = this._length - 1; i >= 0; i--) {
317
- if (this.at(i) === value) {
318
- return i;
319
- }
320
- }
321
- return -1;
322
- }
323
-
324
- /**
325
- * Reverses the order of the elements in this range, returning a new PyRange object.
326
- * @returns {PyRange} A new PyRange object with the elements in reverse order.
327
- */
328
- reverse() {
329
- const result = new PyRange(this._stop, this._start, -this._step);
330
- result._length = this._length;
331
- return result;
332
- }
333
-
334
- [Symbol.iterator]() {
335
- let index = 0;
336
- let current = this._start;
337
- const { _stop: _, _step: step, _length: length } = this;
338
-
339
- return {
340
- next: () => {
341
- if (index >= length) {
342
- return { done: true };
343
- } else {
344
- const value = current;
345
- current += step;
346
- index++;
347
- return { value, done: false };
348
- }
349
- },
350
- };
351
- }
352
-
353
- /**
354
- * Returns a Proxy for this range, allowing indexed access.
355
- * This proxy enables accessing range elements via array-like indexing.
356
- * If the property is a number, it will return the element at that index.
357
- *
358
- * @returns {Proxy} A proxy for the PyRange instance.
359
- */
360
- asProxy() {
361
- return new Proxy(this, {
362
- get(target, prop) {
363
- if (typeof prop === "symbol") {
364
- return target[prop];
365
- }
366
- if (!isNaN(prop)) {
367
- return target.at(parseInt(prop));
368
- }
369
- return target[prop];
370
- },
371
- });
372
- }
373
- }
374
-
375
- module.exports = PyRange;
376
- module.exports.PyRange = PyRange;