diff --git a/README.md b/README.md
index 2907cef..8772526 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Number.range & BigInt.range
+# Iterator.range
**Champions**: Jack Works
@@ -6,7 +6,7 @@
**Stage**: 1
-This proposal describes adding a `Number.range` and a `BigInt.range` to JavaScript.
+This proposal describes adding a `Iterator.range` to the JavaScript.
See the rendered spec at [here](https://tc39.es/proposal-Number.range/).
@@ -16,9 +16,9 @@ See the rendered spec at [here](https://tc39.es/proposal-Number.range/).
## Polyfill
-- A polyfill is available in the [core-js](https://github.com/zloirock/core-js) library. You can find it in the [ECMAScript proposals section](https://github.com/zloirock/core-js/#numberrange).
+- A polyfill is available in the [core-js](https://github.com/zloirock/core-js) library. You can find it in the [ECMAScript proposals section](https://github.com/zloirock/core-js/#numberrange).
-- In the proposal repo is available a [a step-to-step implementation of the proposal](./polyfill.js) [](https://codecov.io/gh/tc39/proposal-Number.range) so you can verify if there is a bug in the specification by the debugger.
+- In the proposal repo is available a [a step-to-step implementation of the proposal](./polyfill.js) [](https://codecov.io/gh/tc39/proposal-Number.range) so you can verify if there is a bug in the specification by the debugger.
## Motivation
@@ -48,14 +48,14 @@ Tons of libraries providing a range: math.js, lodash, underscore.js, ramda, d3,
- - - Decimal step (0, 0.2, 0.4, ...)
- BigInt Support
- - Same as Arithmetic Sequence
-- Infinite Sequence `Number.range(0, Infinity)` -> (0, 1, 2, 3, ...)
+- Infinite Sequence `Iterator.range(0, Infinity)` -> (0, 1, 2, 3, ...)
### Non-goals
- New Syntax
- String Sequence (a, b, c, d, ...)
- Magic
-- - E.g. `if (x in Number.range(0, 10))` (Kotlin have this feature)
+- - E.g. `if (x in Iterator.range(0, 10))` (Kotlin have this feature)
### Discussions
@@ -79,21 +79,21 @@ See [tests](./__tests__/test.js) to learn about more usages.
```js
for (const i of BigInt.range(0n, 43n)) console.log(i) // 0n to 42n
-// With iterator helper proposal
-Number.range(0, Infinity)
+Iterator.range(0, Infinity)
.take(1000)
.filter((x) => !(x % 3))
.toArray()
function* even() {
- for (const i of Number.range(0, Infinity)) if (i % 2 === 0) yield i
+ for (const i of Iterator.range(0, Infinity)) if (i % 2 === 0) yield i
}
-;[...Number.range(1, 100, 2)] // odd number from 1 to 99
+;[...Iterator.range(1, 100, 2)] // odd number from 1 to 99
```
# Presentations
-- 2020 Apr [Notes](https://github.com/tc39/notes/blob/main/meetings/2020-03/april-1.md#numberrange-and-bigintrange-for-stage-1) [Slides](https://docs.google.com/presentation/d/1JD9SrOEtGEviPYJ3LQGKRqDHYeF-EIt7RHB92hKPWzo/)
+- [Apr 2020 Notes](https://github.com/tc39/notes/blob/main/meetings/2020-03/april-1.md#numberrange-and-bigintrange-for-stage-1) / [Slides](https://docs.google.com/presentation/d/1JD9SrOEtGEviPYJ3LQGKRqDHYeF-EIt7RHB92hKPWzo/)
+- [Jul 2020 Notes](https://github.com/tc39/notes/blob/65a82252aa14c273082e7687c6712bb561bc087a/meetings/2020-07/july-22.md#numberrange-for-stage-2) / [Slides](https://docs.google.com/presentation/d/116FDDK2klJoEL8s2Q7UXiDApC681N-Q9SwpC0toAzTU/)
### Signature
diff --git a/__tests__/test.js b/__tests__/test.js
index 31d11d6..1987de9 100644
--- a/__tests__/test.js
+++ b/__tests__/test.js
@@ -1,29 +1,29 @@
///
-require("../polyfill.js")
require("core-js/proposals/iterator-helpers")
+require("../polyfill.js")
-test("Number.range", () => {
- expect(that(Number.range(-1, 5))).toMatchInlineSnapshot(`"-1f, 0f, 1f, 2f, 3f, 4f"`)
- expect(that(Number.range(-5, 1))).toMatchInlineSnapshot(`"-5f, -4f, -3f, -2f, -1f, 0f"`)
- expect(that(Number.range(0, 1, 0.1))).toMatchInlineSnapshot(
+test("Iterator.range", () => {
+ expect(that(Iterator.range(-1, 5))).toMatchInlineSnapshot(`"-1f, 0f, 1f, 2f, 3f, 4f"`)
+ expect(that(Iterator.range(-5, 1))).toMatchInlineSnapshot(`"-5f, -4f, -3f, -2f, -1f, 0f"`)
+ expect(that(Iterator.range(0, 1, 0.1))).toMatchInlineSnapshot(
`"0f, 0.1f, 0.2f, 0.30000000000000004f, 0.4f, 0.5f, 0.6000000000000001f, 0.7000000000000001f, 0.8f, 0.9f"`
)
- expect(that(Number.range(2 ** 53 - 1, 2 ** 53, { inclusive: true }))).toMatchInlineSnapshot(
+ expect(that(Iterator.range(2 ** 53 - 1, 2 ** 53, { inclusive: true }))).toMatchInlineSnapshot(
`"9007199254740991f, 9007199254740992f"`
)
- expect(that(Number.range(0, 0))).toMatchInlineSnapshot(`""`)
- expect(that(Number.range(0, -5, 1))).toMatchInlineSnapshot(`""`)
+ expect(that(Iterator.range(0, 0))).toMatchInlineSnapshot(`""`)
+ expect(that(Iterator.range(0, -5, 1))).toMatchInlineSnapshot(`""`)
})
-test("BigInt.range", () => {
- expect(that(BigInt.range(-1n, 5n))).toMatchInlineSnapshot(`"-1n, 0n, 1n, 2n, 3n, 4n"`)
- expect(that(BigInt.range(-5n, 1n))).toMatchInlineSnapshot(`"-5n, -4n, -3n, -2n, -1n, 0n"`)
+test("Iterator.range", () => {
+ expect(that(Iterator.range(-1n, 5n))).toMatchInlineSnapshot(`"-1n, 0n, 1n, 2n, 3n, 4n"`)
+ expect(that(Iterator.range(-5n, 1n))).toMatchInlineSnapshot(`"-5n, -4n, -3n, -2n, -1n, 0n"`)
})
test("Range to infinity", () => {
{
let q = 0
- for (const i of Number.range(0, Infinity)) {
+ for (const i of Iterator.range(0, Infinity)) {
q += i
if (i >= 100) break
}
@@ -31,7 +31,7 @@ test("Range to infinity", () => {
}
{
let q = 0n
- for (const i of BigInt.range(0n, Infinity, { inclusive: true, step: 2n })) {
+ for (const i of Iterator.range(0n, Infinity, { inclusive: true, step: 2n })) {
q += i
if (i >= 100) break
}
@@ -40,61 +40,33 @@ test("Range to infinity", () => {
})
test("Use with Iterator helpers", () => {
- expect(that(Number.range(0, 10).take(5))).toMatchInlineSnapshot(`"0f, 1f, 2f, 3f, 4f"`)
- expect(that(Number.range(0, 10).map((x) => x * 2))).toMatchInlineSnapshot(
+ expect(that(Iterator.range(0, 10).take(5))).toMatchInlineSnapshot(`"0f, 1f, 2f, 3f, 4f"`)
+ expect(that(Iterator.range(0, 10).map((x) => x * 2))).toMatchInlineSnapshot(
`"0f, 2f, 4f, 6f, 8f, 10f, 12f, 14f, 16f, 18f"`
)
- expect(BigInt.range(0n, 10n).reduce((prev, curr) => prev + curr, 0n)).toMatchInlineSnapshot(`45n`)
+ expect(Iterator.range(0n, 10n).reduce((prev, curr) => prev + curr, 0n)).toMatchInlineSnapshot(`45n`)
})
test("Be an iterator", () => {
- const x = Number.range(0, 10)
+ const x = Iterator.range(0, 10)
const iteratorPrototype = (function* () {})().__proto__.__proto__.__proto__
expect(x.__proto__.__proto__ === iteratorPrototype).toBeTruthy()
})
test("NaN", () => {
- expect(that(Number.range(NaN, 0))).toMatchInlineSnapshot(`""`)
- expect(that(Number.range(0, NaN))).toMatchInlineSnapshot(`""`)
- expect(that(Number.range(NaN, NaN))).toMatchInlineSnapshot(`""`)
-
- expect(that(Number.range(0, 0, { step: NaN }))).toMatchInlineSnapshot(`""`)
- expect(that(Number.range(0, 5, NaN))).toMatchInlineSnapshot(`""`)
-})
+ expect(that(Iterator.range(NaN, 0))).toMatchInlineSnapshot(`""`)
+ expect(that(Iterator.range(0, NaN))).toMatchInlineSnapshot(`""`)
+ expect(that(Iterator.range(NaN, NaN))).toMatchInlineSnapshot(`""`)
-test("{from, to, step} getter", () => {
- {
- const a = Number.range(1, 3)
- expect(a.start).toMatchInlineSnapshot(`1`)
- expect(a.end).toMatchInlineSnapshot(`3`)
- expect(a.step).toMatchInlineSnapshot(`1`)
- expect(a.inclusive).toMatchInlineSnapshot(`false`)
- }
- {
- const a = Number.range(-1, -3, { inclusive: true })
- expect(a.start).toMatchInlineSnapshot(`-1`)
- expect(a.end).toMatchInlineSnapshot(`-3`)
- expect(a.step).toMatchInlineSnapshot(`-1`)
- expect(a.inclusive).toMatchInlineSnapshot(`true`)
- }
- {
- const a = Number.range(-1, -3, { step: 4, inclusive: function () {} })
- expect(a.start).toMatchInlineSnapshot(`-1`)
- expect(a.end).toMatchInlineSnapshot(`-3`)
- expect(a.step).toMatchInlineSnapshot(`4`)
- expect(a.inclusive).toMatchInlineSnapshot(`true`)
- }
- {
- const a = Number.range(0, 5)
- expect(() => Object.getOwnPropertyDescriptor(a, "start").call({})).toThrow()
- }
+ expect(that(Iterator.range(0, 0, { step: NaN }))).toMatchInlineSnapshot(`""`)
+ expect(that(Iterator.range(0, 5, NaN))).toMatchInlineSnapshot(`""`)
})
test("Step infer", () => {
- expect(that(Number.range(0, -2))).toMatchInlineSnapshot(`"0f, -1f"`)
- expect(that(BigInt.range(0n, -2n))).toMatchInlineSnapshot(`"0n, -1n"`)
- expect(that(Number.range(0, -2, { inclusive: true }))).toMatchInlineSnapshot(`"0f, -1f, -2f"`)
- expect(that(BigInt.range(0n, -2n, { inclusive: true }))).toMatchInlineSnapshot(`"0n, -1n, -2n"`)
+ expect(that(Iterator.range(0, -2))).toMatchInlineSnapshot(`"0f, -1f"`)
+ expect(that(Iterator.range(0n, -2n))).toMatchInlineSnapshot(`"0n, -1n"`)
+ expect(that(Iterator.range(0, -2, { inclusive: true }))).toMatchInlineSnapshot(`"0f, -1f, -2f"`)
+ expect(that(Iterator.range(0n, -2n, { inclusive: true }))).toMatchInlineSnapshot(`"0n, -1n, -2n"`)
})
test("Error handling: Type Mismatch", () => {
@@ -123,43 +95,37 @@ test("Error handling: Type Mismatch", () => {
[0n, 1n, { step: 1 }],
]
for (const each of sharedMatrix) {
- expect(() => Number.range(...each)).toThrowError()
- expect(() => BigInt.range(...each)).toThrowError()
+ expect(() => Iterator.range(...each)).toThrowError()
+ expect(() => Iterator.range(...each)).toThrowError()
}
- expect(() => Number.range(0n, 1n)).toThrowError()
- expect(() => Number.range(0n, 1n, 1n)).toThrowError()
- expect(() => Number.range(0n, 1n, { step: 1n })).toThrowError()
- expect(() => BigInt.range(0, 1)).toThrowError()
- expect(() => BigInt.range(0n, NaN)).toThrowError()
- expect(() => BigInt.range(0, 1, 1)).toThrowError()
- expect(() => BigInt.range(0, 1, { step: 1 })).toThrowError()
+ expect(() => Iterator.range(0n, NaN)).toThrowError()
})
test("Error: Zero as step", () => {
- expect(() => Number.range(0, 10, 0)).toThrowError()
- expect(() => Number.range(0, 10, { step: 0 })).toThrowError()
- expect(() => BigInt.range(0n, 10n, 0n)).toThrowError()
- expect(() => BigInt.range(0n, 10n, { step: 0n })).toThrowError()
+ expect(() => Iterator.range(0, 10, 0)).toThrowError()
+ expect(() => Iterator.range(0, 10, { step: 0 })).toThrowError()
+ expect(() => Iterator.range(0n, 10n, 0n)).toThrowError()
+ expect(() => Iterator.range(0n, 10n, { step: 0n })).toThrowError()
})
test("Error: Infinity as start / step", () => {
- expect(() => Number.range(Infinity, 10, 0)).toThrowError()
- expect(() => Number.range(-Infinity, 10, 0)).toThrowError()
- expect(() => Number.range(0, 10, Infinity)).toThrowError()
- expect(() => Number.range(0, 10, { step: Infinity })).toThrowError()
+ expect(() => Iterator.range(Infinity, 10, 0)).toThrowError()
+ expect(() => Iterator.range(-Infinity, 10, 0)).toThrowError()
+ expect(() => Iterator.range(0, 10, Infinity)).toThrowError()
+ expect(() => Iterator.range(0, 10, { step: Infinity })).toThrowError()
})
test("Incompatible receiver", () => {
function* x() {}
const y = x()
- const z = Number.range(0, 8)
+ const z = Iterator.range(0, 8)
expect(() => z.next.call(y)).toThrow()
expect(() => y.next.call(z)).toThrow()
y.next()
})
test("Inclusive on same start-end (issue #38)", () => {
- expect(that(Number.range(0, 0, { inclusive: true }))).toMatchInlineSnapshot(`"0f"`)
+ expect(that(Iterator.range(0, 0, { inclusive: true }))).toMatchInlineSnapshot(`"0f"`)
})
function that(x) {
diff --git a/build-polyfill.mjs b/build-polyfill.mjs
new file mode 100644
index 0000000..083448b
--- /dev/null
+++ b/build-polyfill.mjs
@@ -0,0 +1,11 @@
+import builder from "core-js-builder"
+
+const bundle = await builder({
+ modules: [/esnext.+iterator/],
+ summary: {
+ console: { size: true, modules: false },
+ comment: { size: false, modules: true },
+ },
+ format: "bundle",
+ filename: './iterator-helper.js',
+})
diff --git a/compare.md b/compare.md
index c6859bf..daa05f4 100644
--- a/compare.md
+++ b/compare.md
@@ -8,16 +8,16 @@ Based on the document and REPL of other languages, might have error in it.
### Syntax
-| Language | Syntax |
-| ------------------ | ------------------------------------------------------------------------ |
-| This proposal | `Number.range(start, to, step?)`
`Bigint.range(start, to, step?)` |
-| Python | `range(start, to, step?)`
`range(to)` |
-| Java | `IntStream.range(start, to)`
`LongStream.range(start, to)` |
-| Swift (`Range`) | `start...to`
`start.. `(start..=to)` |
-| Haskell | `[start,next_element_to_infer_step..to]` |
-| F# | `seq { start .. step .. to }` |
+| Language | Syntax |
+| ------------------ | -------------------------------------------------------------------------- |
+| This proposal | `Iterator.range(start, to, step?)`
`Bigint.range(start, to, step?)` |
+| Python | `range(start, to, step?)`
`range(to)` |
+| Java | `IntStream.range(start, to)`
`LongStream.range(start, to)` |
+| Swift (`Range`) | `start...to`
`start.. `(start..=to)` |
+| Haskell | `[start,next_element_to_infer_step..to]` |
+| F# | `seq { start .. step .. to }` |
Haskell: The `[start..to]` syntax produce a list. Due to the lazy evaluation of Haskell, it range semantics is different than most of languages.
@@ -58,7 +58,7 @@ Define:
- This proposal: It doesn't have it own class currently but it have it's own prototype `%RangeIteratorPrototype%` and have unique getters on it.
- Java: The base interface of `IntStream` (`Stream`) doesn't implements `Iterator` protocol but have a `iterator()` methods that returns an Iterator. Must use with `for(int i: range.iterator())`
- Swift (`StrideTo`): According to the [document of `StrideTo`](https://developer.apple.com/documentation/swift/strideto/1689269-lazy), laziness is opt-in.
-- Rust: See https://github.com/tc39/proposal-Number.range/issues/17#issuecomment-642064127
+- Rust: See
- Haskell: No Iterator / Iterable. The laziness is in the language. `The idea of a side-effecting iterator is antithetical to the Haskell Way.` (start StackOverflow)
### Immutable (`start`, `to` and `step` cannot be changed)
diff --git a/global.d.ts b/global.d.ts
index c23ed03..c852fc3 100644
--- a/global.d.ts
+++ b/global.d.ts
@@ -1,21 +1,11 @@
type Infinity = number
-interface RangeIterator
- extends Iterator {
- // This property is not in the spec yet.
- [Symbol.iterator](): RangeIterator
- readonly [Symbol.toStringTag]: "RangeIterator"
- readonly start: T
- readonly end: T | Infinity
- readonly step: T
- readonly inclusive: boolean
+declare var Iterator: {
+ new (): Iterator
+ prototype: Iterator
+ range(start: number, end: number, option: number | NumericRangeOptions): IterableIterator
+ range(start: bigint, end: bigint | Infinity, option: bigint | NumericRangeOptions): IterableIterator
}
-type RangeFunction = {
- range(
- start: T,
- end: T | Infinity,
- option?: T | { step?: T; inclusive?: boolean }
- ): RangeIterator
- range(start: T, end: T | Infinity, step?: T): RangeIterator
+interface NumericRangeOptions {
+ step?: number | number
+ inclusive?: boolean
}
-interface NumberConstructor extends RangeFunction {}
-interface BigIntConstructor extends RangeFunction {}
diff --git a/index.html b/index.html
index aeaf43f..79df8e4 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,7 @@
-Proposal Number.range & BigInt.range
+
+
+ Open your console and Iterator.range is available.
+
+
+
-
+ function display(f) {
+ const stringify = f
+ .toString()
+ .replace(/^\(\) =>/, "")
+ .replace(/^\s+/gm, "")
+ .split("\n")
+ .map((x, i) => (i > 0 ? " " + x : x))
+ .join("\n")
+ console.log(stringify, stringify.includes("\n") ? "\n" : "", f())
+ }
+ display(() => Iterator.range(-2, 8).toArray())
+ display(() => Iterator.range(-2n, 8n).toArray())
+ display(() => Iterator.range(2, -2, -1).toArray())
+ display(() => Iterator.range(0, 5, { step: 1.5 }).toArray())
+ display(() =>
+ Iterator.range(1, 10)
+ .take(4)
+ .map((x) => x ** x)
+ .toArray()
+ )
+
+
+