diff --git a/docs/source/index.rst b/docs/source/index.rst index 1f8b7e502..8774dbdc3 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,7 @@ Lumino changelog api examples + migration Indices and tables ================== diff --git a/docs/source/migration.md b/docs/source/migration.md new file mode 100644 index 000000000..1b0d7d6b6 --- /dev/null +++ b/docs/source/migration.md @@ -0,0 +1,146 @@ +# Migration guide for Lumino 1 to Lumino 2 + +## Iterables, iterators, and generators + +### Overview and suggestions on iteration + +These are some guiding principles that came up over the course of refactoring the way we handle iteration in Lumino. They are not hard and fast rules, rather they are intuitions that arose while implementing the changes Lumino 2. + +### Use `each(...)` sparingly + +Iterating through an iterable `bar: Iterable` using native `for...of`, e.g., `for (const foo of bar) {...}` is almost always a better option than using `each(bar, foo => ...)`. Some exceptions to this are: + +- When you need the index of an item during iteration and you are _not_ iterating through an array, which already provides the index as a second parameter to a function passed into `.forEach(...)` +- When you could use the array `.forEach(...)` method but you want to be able to terminate iteration early, which you cannot do natively, but can with `each(...)` by returning `false` + +Nearly all invocations of `each(...)` have been removed in Lumino 2 (except for tests). See, for example, [this commit](https://github.com/jupyterlab/lumino/pull/346/commits/efb1e919bb359192caeedb726e16ec42d17b3b0f). + +### Use `[].forEach(...)` sparingly + +Now that we support native ES6 iteration, `for (const value of someArray) {...}` should be favored over `someArray.forEach(...)` because it will not require a context shift every time it invokes the function being applied. + +### Use `[Symbol.iterator]()` sparingly + +Unless you need a handle on multiple iterators simultaneously (e.g., the way `zip(...)` is implemented in Lumino 2) or you need to hold on to multiple values of your iterable during iteration (e.g., the way we need both the first and the second value of an iterable to implement `reduce(...)` in Lumino 2), most of the time you can simply use `for...of` to iterate through any object that has a `Symbol.iterator` method without invoking that method. + +In many places where the Lumino `iter()` utility function has been replaced in Lumino 2 it is not replaced with an invocation of the new `Symbol.iterator` method. + +### Use `Array.from(...)` sparingly + +`toArray(...)` has been deprecated. You may be tempted to swap in `Array.from(...)` when you update your code. This _will_ work, but if you simply need to iterate through an iterable, you can use `for...of` directly on the iterable object. This is more performant both in terms of CPU and memory than allocating and populating new `Array` instance before iteration. + +If you need a snapshot of every item in your iterable as an array, then `Array.from(...)` is an appropriate replacement for `toArray(...)`. + +## Public API changes + +### `@lumino/algorithm` + +All of the iterator utilities have been changed to use native generators and iterators. + +| | `export` | name | note | +| --- | ----------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ❌ | `type` | `IterableOrArrayLike` | Switch to [`Iterable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol) | +| ❌ | `interface` | `IIterable` | Switch to `Iterable` | +| ❌ | `interface` | `IIterator` | Switch to [`Iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol) / `IterableIterator` | +| ❌ | `function` | `iter(...)` | Switch to [`Symbol.iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator) and [`function*`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) | +| ❌ | `function` | `iterFn(...)` | Switch to `function*` | +| ❌ | `function` | `iterItems(...)` | We aren't using this function anywhere | +| ❌ | `function` | `iterKeys(...)` | Switch to [`for ... in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) | +| ❌ | `function` | `iterValues(...)` | Switch to [`for ... of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) | +| ❌ | `function` | `toArray(...)` | Switch to [`Array.from(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) | +| ❌ | `function` | `toObject(...)` | We aren't using this function anywhere | +| ❌ | `class` | `ArrayIterator` | Switch to `[][Symbol.iterator]()` | +| ❌ | `class` | `ChainIterator` | Previous implementation of `chain()` | +| ❌ | `class` | `EmptyIterator` | Previous implementation of `empty()` | +| ❌ | `class` | `EnumerateIterator` | Previous implementation of `enumerate()` | +| ❌ | `class` | `FilterIterator` | Previous implementation of `filter()` | +| ❌ | `class` | `FnIterator` | Switch to [generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator) | +| ❌ | `class` | `ItemIterator` | We aren't using this class anywhere | +| ❌ | `class` | `KeyIterator` | Switch to `for ... in` | +| ❌ | `class` | `MapIterator` | Previous implementation of `map()` | +| ❌ | `class` | `RangeIterator` | Previous implementation of `range()` | +| ❌ | `class` | `RetroIterator` | Previous implementation of `retro()` | +| ❌ | `class` | `StrideIterator` | Previous implementation of `stride()` | +| ❌ | `class` | `TakeIterator` | Previous implementation of `take()` | +| ❌ | `class` | `ValueIterator` | Switch to `for ... of` | +| ❌ | `class` | `ZipIterator` | Previous implementation of `zip()` | +| ✅ | `function` | `chain(...)` | Reimplement with native types | +| ✅ | `function` | `each(...)` | Reimplement with native types | +| ✅ | `function` | `empty(...)` | Reimplement with native types | +| ✅ | `function` | `enumerate(...)` | Reimplement with native types | +| ✅ | `function` | `every(...)` | Reimplement with native types | +| ✅ | `function` | `filter(...)` | Reimplement with native types | +| ✅ | `function` | `find(...)` | Reimplement with native types | +| ✅ | `function` | `findIndex(...)` | Reimplement with native types | +| ✅ | `function` | `map(...)` | Reimplement with native types | +| ✅ | `function` | `max(...)` | Reimplement with native types | +| ✅ | `function` | `min(...)` | Reimplement with native types | +| ✅ | `function` | `minmax(...)` | Support native types | +| ✅ | `function` | `reduce(...)` | Support native types | +| ✅ | `function` | `range(...)` | Reimplement with native types | +| ✅ | `function` | `retro(...)` | Reimplement with native types | +| ✅ | `function` | `some(...)` | Reimplement with native types | +| ✅ | `function` | `stride(...)` | Reimplement with native types | +| ✅ | `function` | `take(...)` | Reimplement with native types | + +| ☑️ | `function` | `toArray(...)` | `@deprecated`, use [`Array.from(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) or [`for ... of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) | +| ✅ | `function` | `toObject(...)` | Reimplement with native types | + +| ✅ | `function` | `topologicSort(...)` | Support native types | +| ✅ | `function` | `zip(...)` | Reimplement with native types | + +### `@lumino/collections` + +`LinkedList` has been updated to accept native iterables and return native iterators. + +| | `export` | name | note | +| --- | ---------- | --------------------------------- | ---------------------------------------------------- | +| ❌ | `class` | `LinkedList.ForwardValueIterator` | Switch to `LinkedList#[Symbol.iterator]` | +| ❌ | `class` | `LinkedList.RetroValueIterator` | Previous implementation of `LinkedList#retro()` | +| ❌ | `class` | `LinkedList.ForwardNodeIterator` | Previous implementation of `LinkedList#nodes()` | +| ❌ | `class` | `LinkedList.RetroNodeIterator` | Previous implementation of `LinkedList#retroNodes()` | +| ❌ | `method` | `LinkedList#iter()` | Switch to `LinkedList#[Symbol.iterator]` | +| ✅ | `function` | `LinkedList.from(...)` | Accept `Iterable` | +| ✅ | `method` | `LinkedList#assign(...)` | Accept `Iterable` | +| ✅ | `method` | `LinkedList#nodes()` | Return `IterableIterator>` | +| ✅ | `method` | `LinkedList#retro()` | Return `IterableIterator` | +| ✅ | `method` | `LinkedList#retroNodes()` | Return `IterableIterator>` | + +### `@lumino/datagrid` + +`DataGrid` selections are now native iterators. + +| | `export` | name | note | +| --- | -------- | ---------------------------------- | --------------------------------------------------- | +| ✅ | `method` | `BasicSelectionModel#selections()` | Return `IterableIterator` | +| ✅ | `method` | `SelectionModel#selections()` | Return `IterableIterator` | + +### `@lumino/disposable` + +Helper functions for `DisposableSet` and `ObservableDisposableSet` have been udpated. + +| | `export` | name | note | +| --- | ---------- | ----------------------------------- | ------------------------------ | +| ✅ | `function` | `DisposableSet.from(...)` | Accept `Iterable` | +| ✅ | `function` | `ObservableDisposableSet.from(...)` | Accept `Iterable` | + +### `@lumino/widgets` + +`Layout` and its sub-classes now use native iterators, e.g. `implements Iterable`. + +| | `export` | name | note | +| --- | -------- | ------------------------------ | --------------------------------------------- | +| ❌ | `method` | `DockLayout#iter()` | Switch to `DockLayout#[Symbol.iterator]` | +| ❌ | `method` | `GridLayout#iter()` | Switch to `GridLayout#[Symbol.iterator]` | +| ❌ | `method` | `Layout#iter()` | Switch to `Layout#[Symbol.iterator]` | +| ❌ | `method` | `PanelLayout#iter()` | Switch to `PanelLayout#[Symbol.iterator]` | +| ❌ | `method` | `SingletonLayout#iter()` | Switch to `SingletonLayout#[Symbol.iterator]` | +| ✅ | `method` | `DockLayout#handles()` | Return `IterableIterator` | +| ✅ | `method` | `DockLayout#selectedWidgets()` | Return `IterableIterator` | +| ✅ | `method` | `DockLayout#tabBars()` | Return `IterableIterator>` | +| ✅ | `method` | `DockLayout#widgets()` | Return `IterableIterator` | +| ✅ | `method` | `DockPanel#handles()` | Return `IterableIterator` | +| ✅ | `method` | `DockPanel#selectedWidgets()` | Return `IterableIterator` | +| ✅ | `method` | `DockPanel#tabBars()` | Return `IterableIterator>` | +| ✅ | `method` | `DockPanel#widgets()` | Return `IterableIterator` | +| ✅ | `method` | `Widget#children()` | Return `IterableIterator` | diff --git a/examples/example-dockpanel-amd/src/index.js b/examples/example-dockpanel-amd/src/index.js index eeca51a03..9aae018de 100644 --- a/examples/example-dockpanel-amd/src/index.js +++ b/examples/example-dockpanel-amd/src/index.js @@ -53,15 +53,18 @@ define(['@lumino/commands', '@lumino/widgets'], function ( return root; } - function ContentWidget(name) { - Widget.call(this, { node: ContentWidget.prototype.createNode() }); - this.setFlag(Widget.Flag.DisallowLayout); - this.addClass('content'); - this.addClass(name.toLowerCase()); - this.title.label = name; - this.title.closable = true; - this.title.caption = 'Long description for: ' + name; + class ContentWidget extends Widget { + constructor(name) { + super({ node: ContentWidget.prototype.createNode() }); + this.setFlag(Widget.Flag.DisallowLayout); + this.addClass('content'); + this.addClass(name.toLowerCase()); + this.title.label = name; + this.title.closable = true; + this.title.caption = 'Long description for: ' + name; + } } + ContentWidget.prototype = Object.create(Widget.prototype); ContentWidget.prototype.createNode = function () { diff --git a/examples/example-dockpanel/tsconfig.json b/examples/example-dockpanel/tsconfig.json index 8f3f94b49..812ad282c 100644 --- a/examples/example-dockpanel/tsconfig.json +++ b/examples/example-dockpanel/tsconfig.json @@ -8,9 +8,9 @@ "sourceMap": true, "module": "commonjs", "moduleResolution": "node", - "target": "ES5", + "target": "ES6", "outDir": "./build", - "lib": ["ES5", "ES2015.Promise", "ES2015.Iterable", "DOM"], + "lib": ["ES6", "DOM"], "types": [] }, "include": ["src/*"] diff --git a/packages/algorithm/src/chain.ts b/packages/algorithm/src/chain.ts index a4c6bdda7..18e6844c7 100644 --- a/packages/algorithm/src/chain.ts +++ b/packages/algorithm/src/chain.ts @@ -7,90 +7,31 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; /** * Chain together several iterables. * - * @param objects - The iterable or array-like objects of interest. + * @param objects - The iterable objects of interest. * * @returns An iterator which yields the values of the iterables * in the order in which they are supplied. * * #### Example * ```typescript - * import { chain, toArray } from '@lumino/algorithm'; + * import { chain } from '@lumino/algorithm'; * * let data1 = [1, 2, 3]; * let data2 = [4, 5, 6]; * * let stream = chain(data1, data2); * - * toArray(stream); // [1, 2, 3, 4, 5, 6] + * Array.from(stream); // [1, 2, 3, 4, 5, 6] * ``` */ -export function chain(...objects: IterableOrArrayLike[]): IIterator { - return new ChainIterator(iter(objects.map(iter))); -} - -/** - * An iterator which chains together several iterators. - */ -export class ChainIterator implements IIterator { - /** - * Construct a new chain iterator. - * - * @param source - The iterator of iterators of interest. - */ - constructor(source: IIterator>) { - this._source = source; - this._active = undefined; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new ChainIterator(this._source.clone()); - result._active = this._active && this._active.clone(); - result._cloned = true; - this._cloned = true; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (this._active === undefined) { - let active = this._source.next(); - if (active === undefined) { - return undefined; - } - this._active = this._cloned ? active.clone() : active; - } - let value = this._active.next(); - if (value !== undefined) { - return value; +export function* chain(...objects: Iterable[]): IterableIterator { + for (const object of objects) { + for (const value of object) { + yield value; } - this._active = undefined; - return this.next(); } - - private _source: IIterator>; - private _active: IIterator | undefined; - private _cloned = false; } diff --git a/packages/algorithm/src/empty.ts b/packages/algorithm/src/empty.ts index efa830f81..2bb1c3d19 100644 --- a/packages/algorithm/src/empty.ts +++ b/packages/algorithm/src/empty.ts @@ -7,7 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator } from './iter'; /** * Create an empty iterator. @@ -16,45 +15,14 @@ import { IIterator } from './iter'; * * #### Example * ```typescript - * import { empty, toArray } from '@lumino/algorithm'; + * import { empty } from '@lumino/algorithm'; * * let stream = empty(); * - * toArray(stream); // [] + * Array.from(stream); // [] * ``` */ -export function empty(): IIterator { - return new EmptyIterator(); -} - -/** - * An iterator which is always empty. - */ -export class EmptyIterator implements IIterator { - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new EmptyIterator(); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - return undefined; - } +// eslint-disable-next-line require-yield, @typescript-eslint/no-unused-vars +export function* empty(): IterableIterator { + return; } diff --git a/packages/algorithm/src/enumerate.ts b/packages/algorithm/src/enumerate.ts index 381498d47..6ab1347be 100644 --- a/packages/algorithm/src/enumerate.ts +++ b/packages/algorithm/src/enumerate.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; /** * Enumerate an iterable object. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param start - The starting enum value. The default is `0`. * @@ -20,69 +19,20 @@ import { IIterator, iter, IterableOrArrayLike } from './iter'; * * #### Example * ```typescript - * import { enumerate, toArray } from '@lumino/algorithm'; + * import { enumerate } from '@lumino/algorithm'; * * let data = ['foo', 'bar', 'baz']; * * let stream = enumerate(data, 1); * - * toArray(stream); // [[1, 'foo'], [2, 'bar'], [3, 'baz']] + * Array.from(stream); // [[1, 'foo'], [2, 'bar'], [3, 'baz']] * ``` */ -export function enumerate( - object: IterableOrArrayLike, +export function* enumerate( + object: Iterable, start = 0 -): IIterator<[number, T]> { - return new EnumerateIterator(iter(object), start); -} - -/** - * An iterator which enumerates the source values. - */ -export class EnumerateIterator implements IIterator<[number, T]> { - /** - * Construct a new enumerate iterator. - * - * @param source - The iterator of values of interest. - * - * @param start - The starting enum value. - */ - constructor(source: IIterator, start: number) { - this._source = source; - this._index = start; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator<[number, T]> { - return this; +): IterableIterator<[number, T]> { + for (const value of object) { + yield [start++, value]; } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator<[number, T]> { - return new EnumerateIterator(this._source.clone(), this._index); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): [number, T] | undefined { - let value = this._source.next(); - if (value === undefined) { - return undefined; - } - return [this._index++, value]; - } - - private _source: IIterator; - private _index: number; } diff --git a/packages/algorithm/src/filter.ts b/packages/algorithm/src/filter.ts index 0c85ba9bf..e0d9ac873 100644 --- a/packages/algorithm/src/filter.ts +++ b/packages/algorithm/src/filter.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; /** * Filter an iterable for values which pass a test. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param fn - The predicate function to invoke for each value. * @@ -20,76 +19,23 @@ import { IIterator, iter, IterableOrArrayLike } from './iter'; * * #### Example * ```typescript - * import { filter, toArray } from '@lumino/algorithm'; + * import { filter } from '@lumino/algorithm'; * * let data = [1, 2, 3, 4, 5, 6]; * * let stream = filter(data, value => value % 2 === 0); * - * toArray(stream); // [2, 4, 6] + * Array.from(stream); // [2, 4, 6] * ``` */ -export function filter( - object: IterableOrArrayLike, +export function* filter( + object: Iterable, fn: (value: T, index: number) => boolean -): IIterator { - return new FilterIterator(iter(object), fn); -} - -/** - * An iterator which yields values which pass a test. - */ -export class FilterIterator implements IIterator { - /** - * Construct a new filter iterator. - * - * @param source - The iterator of values of interest. - * - * @param fn - The predicate function to invoke for each value. - */ - constructor(source: IIterator, fn: (value: T, index: number) => boolean) { - this._source = source; - this._fn = fn; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new FilterIterator(this._source.clone(), this._fn); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - let fn = this._fn; - let it = this._source; - let value: T | undefined; - while ((value = it.next()) !== undefined) { - if (fn(value, this._index++)) { - return value; - } +): IterableIterator { + let index = 0; + for (const value of object) { + if (fn(value, index++)) { + yield value; } - return undefined; } - - private _index = 0; - private _source: IIterator; - private _fn: (value: T, index: number) => boolean; } diff --git a/packages/algorithm/src/find.ts b/packages/algorithm/src/find.ts index dff870474..e6ae7ef74 100644 --- a/packages/algorithm/src/find.ts +++ b/packages/algorithm/src/find.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { iter, IterableOrArrayLike } from './iter'; /** * Find the first value in an iterable which matches a predicate. * - * @param object - The iterable or array-like object to search. + * @param object - The iterable object to search. * * @param fn - The predicate function to apply to the values. * @@ -42,13 +41,11 @@ import { iter, IterableOrArrayLike } from './iter'; * ``` */ export function find( - object: IterableOrArrayLike, + object: Iterable, fn: (value: T, index: number) => boolean ): T | undefined { let index = 0; - let it = iter(object); - let value: T | undefined; - while ((value = it.next()) !== undefined) { + for (const value of object) { if (fn(value, index++)) { return value; } @@ -59,7 +56,7 @@ export function find( /** * Find the index of the first value which matches a predicate. * - * @param object - The iterable or array-like object to search. + * @param object - The iterable object to search. * * @param fn - The predicate function to apply to the values. * @@ -89,13 +86,11 @@ export function find( * ``` */ export function findIndex( - object: IterableOrArrayLike, + object: Iterable, fn: (value: T, index: number) => boolean ): number { let index = 0; - let it = iter(object); - let value: T | undefined; - while ((value = it.next()) !== undefined) { + for (const value of object) { if (fn(value, index++)) { return index - 1; } @@ -106,7 +101,7 @@ export function findIndex( /** * Find the minimum value in an iterable. * - * @param object - The iterable or array-like object to search. + * @param object - The iterable object to search. * * @param fn - The 3-way comparison function to apply to the values. * It should return `< 0` if the first value is less than the second. @@ -132,16 +127,15 @@ export function findIndex( * ``` */ export function min( - object: IterableOrArrayLike, + object: Iterable, fn: (first: T, second: T) => number ): T | undefined { - let it = iter(object); - let value = it.next(); - if (value === undefined) { - return undefined; - } - let result = value; - while ((value = it.next()) !== undefined) { + let result: T | undefined = undefined; + for (const value of object) { + if (result === undefined) { + result = value; + continue; + } if (fn(value, result) < 0) { result = value; } @@ -152,7 +146,7 @@ export function min( /** * Find the maximum value in an iterable. * - * @param object - The iterable or array-like object to search. + * @param object - The iterable object to search. * * @param fn - The 3-way comparison function to apply to the values. * It should return `< 0` if the first value is less than the second. @@ -178,16 +172,15 @@ export function min( * ``` */ export function max( - object: IterableOrArrayLike, + object: Iterable, fn: (first: T, second: T) => number ): T | undefined { - let it = iter(object); - let value = it.next(); - if (value === undefined) { - return undefined; - } - let result = value; - while ((value = it.next()) !== undefined) { + let result: T | undefined = undefined; + for (const value of object) { + if (result === undefined) { + result = value; + continue; + } if (fn(value, result) > 0) { result = value; } @@ -198,7 +191,7 @@ export function max( /** * Find the minimum and maximum values in an iterable. * - * @param object - The iterable or array-like object to search. + * @param object - The iterable object to search. * * @param fn - The 3-way comparison function to apply to the values. * It should return `< 0` if the first value is less than the second. @@ -224,22 +217,22 @@ export function max( * ``` */ export function minmax( - object: IterableOrArrayLike, + object: Iterable, fn: (first: T, second: T) => number ): [T, T] | undefined { - let it = iter(object); - let value = it.next(); - if (value === undefined) { - return undefined; - } - let vmin = value; - let vmax = value; - while ((value = it.next()) !== undefined) { - if (fn(value, vmin) < 0) { + let empty = true; + let vmin: T; + let vmax: T; + for (const value of object) { + if (empty) { + vmin = value; + vmax = value; + empty = false; + } else if (fn(value, vmin!) < 0) { vmin = value; - } else if (fn(value, vmax) > 0) { + } else if (fn(value, vmax!) > 0) { vmax = value; } } - return [vmin, vmax]; + return empty ? undefined : [vmin!, vmax!]; } diff --git a/packages/algorithm/src/iter.ts b/packages/algorithm/src/iter.ts index 6d92fe045..6fd6cdd80 100644 --- a/packages/algorithm/src/iter.ts +++ b/packages/algorithm/src/iter.ts @@ -9,194 +9,57 @@ |----------------------------------------------------------------------------*/ /** - * An object which can produce an iterator over its values. - */ -export interface IIterable { - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - * - * #### Notes - * Depending on the iterable, the returned iterator may or may not be - * a new object. A collection or other container-like object should - * typically return a new iterator, while an iterator itself should - * normally return `this`. - */ - iter(): IIterator; -} - -/** - * An object which traverses a collection of values. + * Create an array from an iterable of values. * - * #### Notes - * An `IIterator` is itself an `IIterable`. Most implementations of - * `IIterator` should simply return `this` from the `iter()` method. - */ -export interface IIterator extends IIterable { - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - * - * #### Notes - * The cloned iterator can be consumed independently of the current - * iterator. In essence, it is a copy of the iterator value stream - * which starts at the current location. - * - * This can be useful for lookahead and stream duplication. - */ - clone(): IIterator; - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - * - * #### Notes - * The `undefined` value is used to signal the end of iteration and - * should therefore not be used as a value in a collection. - * - * The use of the `undefined` sentinel is an explicit design choice - * which favors performance over purity. The ES6 iterator design of - * returning a `{ value, done }` pair is suboptimal, as it requires - * an object allocation on each iteration; and an `isDone()` method - * would increase implementation and runtime complexity. - */ - next(): T | undefined; -} - -/** - * A type alias for an iterable or builtin array-like object. - */ -export type IterableOrArrayLike = IIterable | ArrayLike; - -/** - * Create an iterator for an iterable object. + * @deprecated * * @param object - The iterable or array-like object of interest. * - * @returns A new iterator for the given object. - * - * #### Notes - * This function allows iteration algorithms to operate on user-defined - * iterable types and builtin array-like objects in a uniform fashion. - */ -export function iter(object: IterableOrArrayLike): IIterator { - let it: IIterator; - if (typeof (object as any).iter === 'function') { - it = (object as IIterable).iter(); - } else { - it = new ArrayIterator(object as ArrayLike); - } - return it; -} - -/** - * Create an iterator for the keys in an object. - * - * @param object - The object of interest. - * - * @returns A new iterator for the keys in the given object. - * - * #### Complexity - * Linear. - * - * #### Example - * ```typescript - * import { each, keys } from '@lumino/algorithm'; - * - * let data = { one: 1, two: 2, three: 3 }; - * - * each(keys(data), key => { console.log(key); }); // 'one', 'two', 'three' - * ``` - */ -export function iterKeys(object: { - readonly [key: string]: T; -}): IIterator { - return new KeyIterator(object); -} - -/** - * Create an iterator for the values in an object. - * - * @param object - The object of interest. - * - * @returns A new iterator for the values in the given object. - * - * #### Complexity - * Linear. - * - * #### Example - * ```typescript - * import { each, values } from '@lumino/algorithm'; - * - * let data = { one: 1, two: 2, three: 3 }; - * - * each(values(data), value => { console.log(value); }); // 1, 2, 3 - * ``` - */ -export function iterValues(object: { - readonly [key: string]: T; -}): IIterator { - return new ValueIterator(object); -} - -/** - * Create an iterator for the items in an object. - * - * @param object - The object of interest. - * - * @returns A new iterator for the items in the given object. - * - * #### Complexity - * Linear. + * @returns A new array of values from the given object. * * #### Example * ```typescript - * import { each, items } from '@lumino/algorithm'; + * import { toArray } from '@lumino/algorithm'; * - * let data = { one: 1, two: 2, three: 3 }; + * let stream = [1, 2, 3, 4, 5, 6][Symbol.iterator](); * - * each(items(data), value => { console.log(value); }); // ['one', 1], ['two', 2], ['three', 3] + * toArray(stream); // [1, 2, 3, 4, 5, 6]; * ``` */ -export function iterItems(object: { - readonly [key: string]: T; -}): IIterator<[string, T]> { - return new ItemIterator(object); +export function toArray(object: Iterable): T[] { + return Array.from(object); } /** - * Create an iterator for an iterator-like function. - * - * @param fn - A function which behaves like an iterator `next` method. + * Create an object from an iterable of key/value pairs. * - * @returns A new iterator for the given function. + * @param object - The iterable or array-like object of interest. * - * #### Notes - * The returned iterator **cannot** be cloned. + * @returns A new object mapping keys to values. * * #### Example * ```typescript - * import { each, iterFn } from '@lumino/algorithm'; + * import { toObject } from '@lumino/algorithm'; * - * let it = iterFn((() => { - * let i = 0; - * return () => i > 3 ? undefined : i++; - * })()); + * let data: [string, number][] = [['one', 1], ['two', 2], ['three', 3]]; * - * each(it, v => { console.log(v); }); // 0, 1, 2, 3 + * toObject(data); // { one: 1, two: 2, three: 3 } * ``` */ -export function iterFn(fn: () => T | undefined): IIterator { - return new FnIterator(fn); +export function toObject(object: Iterable<[string, T]>): { + [key: string]: T; +} { + const result: { [key: string]: T } = {}; + for (const [key, value] of object) { + result[key] = value; + } + return result; } /** * Invoke a function for each value in an iterable. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param fn - The callback function to invoke for each value. * @@ -217,14 +80,12 @@ export function iterFn(fn: () => T | undefined): IIterator { * ``` */ export function each( - object: IterableOrArrayLike, + object: Iterable, fn: (value: T, index: number) => boolean | void ): void { let index = 0; - let it = iter(object); - let value: T | undefined; - while ((value = it.next()) !== undefined) { - if (fn(value, index++) === false) { + for (const value of object) { + if (false === fn(value, index++)) { return; } } @@ -233,7 +94,7 @@ export function each( /** * Test whether all values in an iterable satisfy a predicate. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param fn - The predicate function to invoke for each value. * @@ -256,14 +117,12 @@ export function each( * ``` */ export function every( - object: IterableOrArrayLike, + object: Iterable, fn: (value: T, index: number) => boolean ): boolean { let index = 0; - let it = iter(object); - let value: T | undefined; - while ((value = it.next()) !== undefined) { - if (!fn(value, index++)) { + for (const value of object) { + if (false === fn(value, index++)) { return false; } } @@ -273,7 +132,7 @@ export function every( /** * Test whether any value in an iterable satisfies a predicate. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param fn - The predicate function to invoke for each value. * @@ -296,357 +155,14 @@ export function every( * ``` */ export function some( - object: IterableOrArrayLike, + object: Iterable, fn: (value: T, index: number) => boolean ): boolean { let index = 0; - let it = iter(object); - let value: T | undefined; - while ((value = it.next()) !== undefined) { + for (const value of object) { if (fn(value, index++)) { return true; } } return false; } - -/** - * Create an array from an iterable of values. - * - * @param object - The iterable or array-like object of interest. - * - * @returns A new array of values from the given object. - * - * #### Example - * ```typescript - * import { iter, toArray } from '@lumino/algorithm'; - * - * let data = [1, 2, 3, 4, 5, 6]; - * - * let stream = iter(data); - * - * toArray(stream); // [1, 2, 3, 4, 5, 6]; - * ``` - */ -export function toArray(object: IterableOrArrayLike): T[] { - let index = 0; - let result: T[] = []; - let it = iter(object); - let value: T | undefined; - while ((value = it.next()) !== undefined) { - result[index++] = value; - } - return result; -} - -/** - * Create an object from an iterable of key/value pairs. - * - * @param object - The iterable or array-like object of interest. - * - * @returns A new object mapping keys to values. - * - * #### Example - * ```typescript - * import { toObject } from '@lumino/algorithm'; - * - * let data = [['one', 1], ['two', 2], ['three', 3]]; - * - * toObject(data); // { one: 1, two: 2, three: 3 } - * ``` - */ -export function toObject(object: IterableOrArrayLike<[string, T]>): { - [key: string]: T; -} { - let it = iter(object); - let pair: [string, T] | undefined; - let result: { [key: string]: T } = {}; - while ((pair = it.next()) !== undefined) { - result[pair[0]] = pair[1]; - } - return result; -} - -/** - * An iterator for an array-like object. - * - * #### Notes - * This iterator can be used for any builtin JS array-like object. - */ -export class ArrayIterator implements IIterator { - /** - * Construct a new array iterator. - * - * @param source - The array-like object of interest. - */ - constructor(source: ArrayLike) { - this._source = source; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new ArrayIterator(this._source); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (this._index >= this._source.length) { - return undefined; - } - return this._source[this._index++]; - } - - private _index = 0; - private _source: ArrayLike; -} - -/** - * An iterator for the keys in an object. - * - * #### Notes - * This iterator can be used for any JS object. - */ -export class KeyIterator implements IIterator { - /** - * Construct a new key iterator. - * - * @param source - The object of interest. - * - * @param keys - The keys to iterate, if known. - */ - constructor( - source: { readonly [key: string]: any }, - keys = Object.keys(source) - ) { - this._source = source; - this._keys = keys; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new KeyIterator(this._source, this._keys); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): string | undefined { - if (this._index >= this._keys.length) { - return undefined; - } - let key = this._keys[this._index++]; - if (key in this._source) { - return key; - } - return this.next(); - } - - private _index = 0; - private _keys: string[]; - private _source: { readonly [key: string]: any }; -} - -/** - * An iterator for the values in an object. - * - * #### Notes - * This iterator can be used for any JS object. - */ -export class ValueIterator implements IIterator { - /** - * Construct a new value iterator. - * - * @param source - The object of interest. - * - * @param keys - The keys to iterate, if known. - */ - constructor( - source: { readonly [key: string]: T }, - keys = Object.keys(source) - ) { - this._source = source; - this._keys = keys; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new ValueIterator(this._source, this._keys); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (this._index >= this._keys.length) { - return undefined; - } - let key = this._keys[this._index++]; - if (key in this._source) { - return this._source[key]; - } - return this.next(); - } - - private _index = 0; - private _keys: string[]; - private _source: { readonly [key: string]: T }; -} - -/** - * An iterator for the items in an object. - * - * #### Notes - * This iterator can be used for any JS object. - */ -export class ItemIterator implements IIterator<[string, T]> { - /** - * Construct a new item iterator. - * - * @param source - The object of interest. - * - * @param keys - The keys to iterate, if known. - */ - constructor( - source: { readonly [key: string]: T }, - keys = Object.keys(source) - ) { - this._source = source; - this._keys = keys; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator<[string, T]> { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator<[string, T]> { - let result = new ItemIterator(this._source, this._keys); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): [string, T] | undefined { - if (this._index >= this._keys.length) { - return undefined; - } - let key = this._keys[this._index++]; - if (key in this._source) { - return [key, this._source[key]]; - } - return this.next(); - } - - private _index = 0; - private _keys: string[]; - private _source: { readonly [key: string]: T }; -} - -/** - * An iterator for an iterator-like function. - */ -export class FnIterator implements IIterator { - /** - * Construct a new function iterator. - * - * @param fn - The iterator-like function of interest. - */ - constructor(fn: () => T | undefined) { - this._fn = fn; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - throw new Error('An `FnIterator` cannot be cloned.'); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - return this._fn.call(undefined); - } - - private _fn: () => T | undefined; -} diff --git a/packages/algorithm/src/map.ts b/packages/algorithm/src/map.ts index 6a8cd4cc7..59469e396 100644 --- a/packages/algorithm/src/map.ts +++ b/packages/algorithm/src/map.ts @@ -7,12 +7,10 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; - /** * Transform the values of an iterable with a mapping function. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param fn - The mapping function to invoke for each value. * @@ -20,72 +18,21 @@ import { IIterator, iter, IterableOrArrayLike } from './iter'; * * #### Example * ```typescript - * import { map, toArray } from '@lumino/algorithm'; + * import { map } from '@lumino/algorithm'; * * let data = [1, 2, 3]; * * let stream = map(data, value => value * 2); * - * toArray(stream); // [2, 4, 6] + * Array.from(stream); // [2, 4, 6] * ``` */ -export function map( - object: IterableOrArrayLike, +export function* map( + object: Iterable, fn: (value: T, index: number) => U -): IIterator { - return new MapIterator(iter(object), fn); -} - -/** - * An iterator which transforms values using a mapping function. - */ -export class MapIterator implements IIterator { - /** - * Construct a new map iterator. - * - * @param source - The iterator of values of interest. - * - * @param fn - The mapping function to invoke for each value. - */ - constructor(source: IIterator, fn: (value: T, index: number) => U) { - this._source = source; - this._fn = fn; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new MapIterator(this._source.clone(), this._fn); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): U | undefined { - let value = this._source.next(); - if (value === undefined) { - return undefined; - } - return this._fn.call(undefined, value, this._index++); +): IterableIterator { + let index = 0; + for (const value of object) { + yield fn(value, index++); } - - private _index = 0; - private _source: IIterator; - private _fn: (value: T, index: number) => U; } diff --git a/packages/algorithm/src/range.ts b/packages/algorithm/src/range.ts index ec2514698..66d1ab0a3 100644 --- a/packages/algorithm/src/range.ts +++ b/packages/algorithm/src/range.ts @@ -7,8 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator } from './iter'; - /** * Create an iterator of evenly spaced values. * @@ -26,78 +24,32 @@ import { IIterator } from './iter'; * * In the two argument form of `range(start, stop)`, `step` defaults * to `1`. + * + * #### Example + * ```typescript + * import { range } from '@lumino/algorithm'; + * + * let stream = range(2, 4); + * + * Array.from(stream); // [2, 3] + * ``` */ -export function range( +export function* range( start: number, stop?: number, step?: number -): IIterator { +): IterableIterator { if (stop === undefined) { - return new RangeIterator(0, start, 1); - } - if (step === undefined) { - return new RangeIterator(start, stop, 1); - } - return new RangeIterator(start, stop, step); -} - -/** - * An iterator which produces a range of evenly spaced values. - */ -export class RangeIterator implements IIterator { - /** - * Construct a new range iterator. - * - * @param start - The starting value for the range, inclusive. - * - * @param stop - The stopping value for the range, exclusive. - * - * @param step - The distance between each value. - */ - constructor(start: number, stop: number, step: number) { - this._start = start; - this._stop = stop; - this._step = step; - this._length = Private.rangeLength(start, stop, step); + stop = start; + start = 0; + step = 1; + } else if (step === undefined) { + step = 1; } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; + const length = Private.rangeLength(start, stop, step); + for (let index = 0; index < length; index++) { + yield start + step * index; } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new RangeIterator(this._start, this._stop, this._step); - result._index = this._index; - return result; - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): number | undefined { - if (this._index >= this._length) { - return undefined; - } - return this._start + this._step * this._index++; - } - - private _index = 0; - private _length: number; - private _start: number; - private _stop: number; - private _step: number; } /** diff --git a/packages/algorithm/src/reduce.ts b/packages/algorithm/src/reduce.ts index bfd754637..55341999f 100644 --- a/packages/algorithm/src/reduce.ts +++ b/packages/algorithm/src/reduce.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { iter, IterableOrArrayLike } from './iter'; /** * Summarize all values in an iterable using a reducer function. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param fn - The reducer function to invoke for each value. * @@ -47,59 +46,59 @@ import { iter, IterableOrArrayLike } from './iter'; * ``` */ export function reduce( - object: IterableOrArrayLike, + object: Iterable, fn: (accumulator: T, value: T, index: number) => T ): T; export function reduce( - object: IterableOrArrayLike, + object: Iterable, fn: (accumulator: U, value: T, index: number) => U, initial: U ): U; export function reduce( - object: IterableOrArrayLike, + object: Iterable, fn: (accumulator: any, value: T, index: number) => any, initial?: unknown ): any { // Setup the iterator and fetch the first value. + const it = object[Symbol.iterator](); let index = 0; - let it = iter(object); let first = it.next(); // An empty iterator and no initial value is an error. - if (first === undefined && initial === undefined) { + if (first.done && initial === undefined) { throw new TypeError('Reduce of empty iterable with no initial value.'); } // If the iterator is empty, return the initial value. - if (first === undefined) { + if (first.done) { return initial; } // If the iterator has a single item and no initial value, the // reducer is not invoked and the first item is the return value. let second = it.next(); - if (second === undefined && initial === undefined) { - return first; + if (second.done && initial === undefined) { + return first.value; } // If iterator has a single item and an initial value is provided, // the reducer is invoked and that result is the return value. - if (second === undefined) { - return fn(initial, first, index++); + if (second.done) { + return fn(initial, first.value, index++); } // Setup the initial accumlated value. let accumulator: any; if (initial === undefined) { - accumulator = fn(first, second, index++); + accumulator = fn(first.value, second.value, index++); } else { - accumulator = fn(fn(initial, first, index++), second, index++); + accumulator = fn(fn(initial, first.value, index++), second.value, index++); } // Iterate the rest of the values, updating the accumulator. - let next: T | undefined; - while ((next = it.next()) !== undefined) { - accumulator = fn(accumulator, next, index++); + let next: IteratorResult; + while (!(next = it.next()).done) { + accumulator = fn(accumulator, next.value, index++); } // Return the final accumulated value. diff --git a/packages/algorithm/src/repeat.ts b/packages/algorithm/src/repeat.ts index 4e2a30389..499736713 100644 --- a/packages/algorithm/src/repeat.ts +++ b/packages/algorithm/src/repeat.ts @@ -7,7 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator } from './iter'; /** * Create an iterator which repeats a value a number of times. @@ -20,15 +19,17 @@ import { IIterator } from './iter'; * * #### Example * ```typescript - * import { repeat, toArray } from '@lumino/algorithm'; + * import { repeat } from '@lumino/algorithm'; * * let stream = repeat(7, 3); * - * toArray(stream); // [7, 7, 7] + * Array.from(stream); // [7, 7, 7] * ``` */ -export function repeat(value: T, count: number): IIterator { - return new RepeatIterator(value, count); +export function* repeat(value: T, count: number): IterableIterator { + while (0 < count--) { + yield value; + } } /** @@ -40,64 +41,13 @@ export function repeat(value: T, count: number): IIterator { * * #### Example * ```typescript - * import { once, toArray } from '@lumino/algorithm'; + * import { once } from '@lumino/algorithm'; * * let stream = once(7); * - * toArray(stream); // [7] + * Array.from(stream); // [7] * ``` */ -export function once(value: T): IIterator { - return new RepeatIterator(value, 1); -} - -/** - * An iterator which repeats a value a specified number of times. - */ -export class RepeatIterator implements IIterator { - /** - * Construct a new repeat iterator. - * - * @param value - The value to repeat. - * - * @param count - The number of times to repeat the value. - */ - constructor(value: T, count: number) { - this._value = value; - this._count = count; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new RepeatIterator(this._value, this._count); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (this._count <= 0) { - return undefined; - } - this._count--; - return this._value; - } - - private _value: T; - private _count: number; +export function* once(value: T): IterableIterator { + yield value; } diff --git a/packages/algorithm/src/retro.ts b/packages/algorithm/src/retro.ts index 54e39eacb..a5583c48e 100644 --- a/packages/algorithm/src/retro.ts +++ b/packages/algorithm/src/retro.ts @@ -7,7 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator } from './iter'; /** * An object which can produce a reverse iterator over its values. @@ -18,14 +17,9 @@ export interface IRetroable { * * @returns An iterator which yields the object's values in reverse. */ - retro(): IIterator; + retro(): IterableIterator; } -/** - * A type alias for a retroable or builtin array-like object. - */ -export type RetroableOrArrayLike = IRetroable | ArrayLike; - /** * Create an iterator for a retroable object. * @@ -35,74 +29,24 @@ export type RetroableOrArrayLike = IRetroable | ArrayLike; * * #### Example * ```typescript - * import { retro, toArray } from '@lumino/algorithm'; + * import { retro } from '@lumino/algorithm'; * * let data = [1, 2, 3, 4, 5, 6]; * * let stream = retro(data); * - * toArray(stream); // [6, 5, 4, 3, 2, 1] + * Array.from(stream); // [6, 5, 4, 3, 2, 1] * ``` */ -export function retro(object: RetroableOrArrayLike): IIterator { - let it: IIterator; +export function retro( + object: IRetroable | ArrayLike +): IterableIterator { if (typeof (object as any).retro === 'function') { - it = (object as IRetroable).retro(); - } else { - it = new RetroArrayIterator(object as ArrayLike); - } - return it; -} - -/** - * An iterator which traverses an array-like object in reverse. - * - * #### Notes - * This iterator can be used for any builtin JS array-like object. - */ -export class RetroArrayIterator implements IIterator { - /** - * Construct a new retro iterator. - * - * @param source - The array-like object of interest. - */ - constructor(source: ArrayLike) { - this._source = source; - this._index = source.length - 1; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - let result = new RetroArrayIterator(this._source); - result._index = this._index; - return result; + return (object as IRetroable).retro(); } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (this._index < 0 || this._index >= this._source.length) { - return undefined; + return (function* (object) { + for (let index = object.length - 1; index > -1; index--) { + yield object[index]; } - return this._source[this._index--]; - } - - private _index: number; - private _source: ArrayLike; + })(object as ArrayLike); } diff --git a/packages/algorithm/src/sort.ts b/packages/algorithm/src/sort.ts index a1efdbc44..08233926b 100644 --- a/packages/algorithm/src/sort.ts +++ b/packages/algorithm/src/sort.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { each, IterableOrArrayLike } from './iter'; /** * Topologically sort an iterable of edges. * - * @param edges - The iterable or array-like object of edges to sort. + * @param edges - The iterable object of edges to sort. * An edge is represented as a 2-tuple of `[fromNode, toNode]`. * * @returns The topologically sorted array of nodes. @@ -35,19 +34,21 @@ import { each, IterableOrArrayLike } from './iter'; * topologicSort(data); // ['a', 'b', 'c', 'd', 'e'] * ``` */ -export function topologicSort(edges: IterableOrArrayLike<[T, T]>): T[] { +export function topologicSort(edges: Iterable<[T, T]>): T[] { // Setup the shared sorting state. let sorted: T[] = []; let visited = new Set(); let graph = new Map(); // Add the edges to the graph. - each(edges, addEdge); + for (const edge of edges) { + addEdge(edge); + } // Visit each node in the graph. - graph.forEach((v, k) => { + for (const [k] of graph) { visit(k); - }); + } // Return the sorted results. return sorted; @@ -71,7 +72,9 @@ export function topologicSort(edges: IterableOrArrayLike<[T, T]>): T[] { visited.add(node); let children = graph.get(node); if (children) { - children.forEach(visit); + for (const child of children) { + visit(child); + } } sorted.push(node); } diff --git a/packages/algorithm/src/stride.ts b/packages/algorithm/src/stride.ts index 85cb44f2e..e32e385ef 100644 --- a/packages/algorithm/src/stride.ts +++ b/packages/algorithm/src/stride.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; /** * Iterate over an iterable using a stepped increment. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param step - The distance to step on each iteration. A value * of less than `1` will behave the same as a value of `1`. @@ -21,70 +20,23 @@ import { IIterator, iter, IterableOrArrayLike } from './iter'; * * #### Example * ```typescript - * import { stride, toArray } from '@lumino/algorithm'; + * import { stride } from '@lumino/algorithm'; * * let data = [1, 2, 3, 4, 5, 6]; * * let stream = stride(data, 2); * - * toArray(stream); // [1, 3, 5]; + * Array.from(stream); // [1, 3, 5]; * ``` */ -export function stride( - object: IterableOrArrayLike, +export function* stride( + object: Iterable, step: number -): IIterator { - return new StrideIterator(iter(object), step); -} - -/** - * An iterator which traverses a source iterator step-wise. - */ -export class StrideIterator implements IIterator { - /** - * Construct a new stride iterator. - * - * @param source - The iterator of values of interest. - * - * @param step - The distance to step on each iteration. A value - * of less than `1` will behave the same as a value of `1`. - */ - constructor(source: IIterator, step: number) { - this._source = source; - this._step = step; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new StrideIterator(this._source.clone(), this._step); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - let value = this._source.next(); - for (let n = this._step - 1; n > 0; --n) { - this._source.next(); +): IterableIterator { + let count = 0; + for (const value of object) { + if (0 === count++ % step) { + yield value; } - return value; } - - private _source: IIterator; - private _step: number; } diff --git a/packages/algorithm/src/take.ts b/packages/algorithm/src/take.ts index cccd4021d..bb12709aa 100644 --- a/packages/algorithm/src/take.ts +++ b/packages/algorithm/src/take.ts @@ -7,12 +7,11 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; /** * Take a fixed number of items from an iterable. * - * @param object - The iterable or array-like object of interest. + * @param object - The iterable object of interest. * * @param count - The number of items to take from the iterable. * @@ -22,65 +21,26 @@ import { IIterator, iter, IterableOrArrayLike } from './iter'; * #### Notes * The returned iterator will exhaust early if the source iterable * contains an insufficient number of items. + * + * #### Example + * ```typescript + * import { take } from '@lumino/algorithm'; + * + * let stream = take([5, 4, 3, 2, 1, 0, -1], 3); + * + * Array.from(stream); // [5, 4, 3] + * ``` */ -export function take( - object: IterableOrArrayLike, +export function* take( + object: Iterable, count: number -): IIterator { - return new TakeIterator(iter(object), count); -} - -/** - * An iterator which takes a fixed number of items from a source. - */ -export class TakeIterator implements IIterator { - /** - * Construct a new take iterator. - * - * @param source - The iterator of interest. - * - * @param count - The number of items to take from the source. - */ - constructor(source: IIterator, count: number) { - this._source = source; - this._count = count; +): IterableIterator { + if (count < 1) { + return; } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new TakeIterator(this._source.clone(), this._count); + const it = object[Symbol.iterator](); + let item: IteratorResult; + while (0 < count-- && !(item = it.next()).done) { + yield item.value; } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (this._count <= 0) { - return undefined; - } - let value = this._source.next(); - if (value === undefined) { - return undefined; - } - this._count--; - return value; - } - - private _count: number; - private _source: IIterator; } diff --git a/packages/algorithm/src/zip.ts b/packages/algorithm/src/zip.ts index 790dd74c7..c426b2b86 100644 --- a/packages/algorithm/src/zip.ts +++ b/packages/algorithm/src/zip.ts @@ -7,12 +7,12 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter, IterableOrArrayLike } from './iter'; +import { every } from './iter'; /** * Iterate several iterables in lockstep. * - * @param objects - The iterable or array-like objects of interest. + * @param objects - The iterable objects of interest. * * @returns An iterator which yields successive tuples of values where * each value is taken in turn from the provided iterables. It will @@ -20,67 +20,20 @@ import { IIterator, iter, IterableOrArrayLike } from './iter'; * * #### Example * ```typescript - * import { zip, toArray } from '@lumino/algorithm'; + * import { zip } from '@lumino/algorithm'; * * let data1 = [1, 2, 3]; * let data2 = [4, 5, 6]; * * let stream = zip(data1, data2); * - * toArray(stream); // [[1, 4], [2, 5], [3, 6]] + * Array.from(stream); // [[1, 4], [2, 5], [3, 6]] * ``` */ -export function zip(...objects: IterableOrArrayLike[]): IIterator { - return new ZipIterator(objects.map(iter)); -} - -/** - * An iterator which iterates several sources in lockstep. - */ -export class ZipIterator implements IIterator { - /** - * Construct a new zip iterator. - * - * @param source - The iterators of interest. - */ - constructor(source: IIterator[]) { - this._source = source; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; +export function* zip(...objects: Iterable[]): IterableIterator { + const iters = objects.map(obj => obj[Symbol.iterator]()); + let tuple = iters.map(it => it.next()); + for (; every(tuple, item => !item.done); tuple = iters.map(it => it.next())) { + yield tuple.map(item => item.value); } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new ZipIterator(this._source.map(it => it.clone())); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T[] | undefined { - let result = new Array(this._source.length); - for (let i = 0, n = this._source.length; i < n; ++i) { - let value = this._source[i].next(); - if (value === undefined) { - return undefined; - } - result[i] = value; - } - return result; - } - - private _source: IIterator[]; } diff --git a/packages/algorithm/tests/src/chain.spec.ts b/packages/algorithm/tests/src/chain.spec.ts index 0761842c9..cefc857b3 100644 --- a/packages/algorithm/tests/src/chain.spec.ts +++ b/packages/algorithm/tests/src/chain.spec.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { chain, ChainIterator, iter } from '@lumino/algorithm'; +import { chain } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; @@ -22,11 +22,11 @@ describe('@lumino/algorithm', () => { describe('ChainIterator', () => { testIterator(() => { - let a = iter([1, 2, 3]); - let b = iter(['four', 'five']); - let c = iter([true, false]); + let a = [1, 2, 3]; + let b = ['four', 'five']; + let c = [true, false][Symbol.iterator](); type T = number | string | boolean; - let it = new ChainIterator(iter([a, b, c])); + let it = chain(a, b, c); let expected = [1, 2, 3, 'four', 'five', true, false]; return [it, expected]; }); diff --git a/packages/algorithm/tests/src/empty.spec.ts b/packages/algorithm/tests/src/empty.spec.ts index 6c4f3627a..0159e6146 100644 --- a/packages/algorithm/tests/src/empty.spec.ts +++ b/packages/algorithm/tests/src/empty.spec.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { empty, EmptyIterator } from '@lumino/algorithm'; +import { empty } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; @@ -17,10 +17,4 @@ describe('@lumino/algorithm', () => { return [empty(), []]; }); }); - - describe('EmptyIterator', () => { - testIterator(() => { - return [new EmptyIterator(), []]; - }); - }); }); diff --git a/packages/algorithm/tests/src/filter.spec.ts b/packages/algorithm/tests/src/filter.spec.ts index 51c3843a0..f5fbf1bc3 100644 --- a/packages/algorithm/tests/src/filter.spec.ts +++ b/packages/algorithm/tests/src/filter.spec.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { filter, FilterIterator, iter } from '@lumino/algorithm'; +import { filter } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; @@ -21,11 +21,11 @@ describe('@lumino/algorithm', () => { }); }); - describe('FilterIterator', () => { + describe('filter()', () => { testIterator(() => { let expected = [1, 3, 5]; - let data = [0, 1, 2, 3, 4, 5]; - let it = new FilterIterator(iter(data), n => n % 2 !== 0); + let data = [0, 1, 2, 3, 4, 5][Symbol.iterator](); + let it = filter(data, n => n % 2 !== 0); return [it, expected]; }); }); diff --git a/packages/algorithm/tests/src/iter.spec.ts b/packages/algorithm/tests/src/iter.spec.ts index adb02697c..807435ad1 100644 --- a/packages/algorithm/tests/src/iter.spec.ts +++ b/packages/algorithm/tests/src/iter.spec.ts @@ -9,20 +9,7 @@ |----------------------------------------------------------------------------*/ import { expect } from 'chai'; -import { - ArrayIterator, - each, - every, - IIterator, - iter, - some, - toArray -} from '@lumino/algorithm'; - -/** - * A factory which returns an iterator and expected results. - */ -export type IteratorFactory = () => [IIterator, T[]]; +import { each, every, some, toArray, toObject, zip } from '@lumino/algorithm'; /** * A helper function to test the methods of an iterator. @@ -30,45 +17,34 @@ export type IteratorFactory = () => [IIterator, T[]]; * @param factory - A function which produces an iterator and the * expected results of that iterator. */ -export function testIterator(factory: IteratorFactory): void { - describe('iter()', () => { - it('should return `this` iterator', () => { - let [it] = factory(); - expect(it.iter()).to.equal(it); - }); - }); - - describe('clone()', () => { - it('should return a new independent iterator', () => { +export function testIterator( + factory: () => [IterableIterator, T[]] +): void { + describe('yield', () => { + it('should return the same values in the iterator', () => { let [it, results] = factory(); - let it2 = it.clone(); - expect(it).to.not.equal(it2); - expect(toArray(it)).to.deep.equal(results); - expect(toArray(it2)).to.deep.equal(results); - }); - }); - - describe('next()', () => { - it('should return the next value in the iterator', () => { - let value: T | undefined; - let [it, results] = factory(); - for (let i = 0; (value = it.next()) !== undefined; ++i) { - expect(value).to.deep.equal(results[i]); - } + expect(Array.from(it)).to.deep.equal(results); }); }); } describe('@lumino/algorithm', () => { - describe('iter()', () => { - it('should create an iterator for an array-like object', () => { - let data = [0, 1, 2, 3]; - expect(toArray(iter(data))).to.deep.equal(data); + describe('toArray()', () => { + it('should create an array from an iterable', () => { + let data = [1, 2, 3, 4, 5, 6]; + let stream = data[Symbol.iterator](); + let result = toArray(stream); + expect(result).to.deep.equal([1, 2, 3, 4, 5, 6]); }); + }); - it('should call `iter` on an iterable', () => { - let iterator = iter([1, 2, 3, 4]); - expect(iter(iterator)).to.equal(iterator); + describe('toObject()', () => { + it('should create an object from a [key, value] iterable', () => { + let keys = ['one', 'two', 'three']; + let values = [1, 2, 3]; + let stream = zip(keys, values); + let result = toObject(stream as Iterable<[string, number]>); + expect(result).to.deep.equal({ one: 1, two: 2, three: 3 }); }); }); @@ -115,21 +91,4 @@ describe('@lumino/algorithm', () => { expect(invalid).to.equal(false); }); }); - - describe('toArray()', () => { - it('should create an array from an iterable', () => { - let data = [0, 1, 2, 3, 4, 5]; - let result = toArray(data); - expect(result).to.deep.equal(data); - expect(result).to.not.equal(data); - }); - }); - - describe('ArrayIterator', () => { - testIterator(() => { - let results = [1, 2, 3, 4, 5]; - let it = new ArrayIterator(results); - return [it, results]; - }); - }); }); diff --git a/packages/algorithm/tests/src/map.spec.ts b/packages/algorithm/tests/src/map.spec.ts index e9e658f38..dbfce8c15 100644 --- a/packages/algorithm/tests/src/map.spec.ts +++ b/packages/algorithm/tests/src/map.spec.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { iter, map, MapIterator } from '@lumino/algorithm'; +import { map } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; @@ -19,12 +19,4 @@ describe('@lumino/algorithm', () => { return [it, result]; }); }); - - describe('MapIterator', () => { - testIterator(() => { - let result = [0, 1, 8, 27]; - let it = new MapIterator(iter([0, 1, 2, 3]), x => x ** 3); - return [it, result]; - }); - }); }); diff --git a/packages/algorithm/tests/src/range.spec.ts b/packages/algorithm/tests/src/range.spec.ts index cc1901bfc..06dd576a5 100644 --- a/packages/algorithm/tests/src/range.spec.ts +++ b/packages/algorithm/tests/src/range.spec.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { range, RangeIterator } from '@lumino/algorithm'; +import { range } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; @@ -43,10 +43,4 @@ describe('@lumino/algorithm', () => { }); }); }); - - describe('RangeIterator', () => { - testIterator(() => { - return [new RangeIterator(0, 11, 2), [0, 2, 4, 6, 8, 10]]; - }); - }); }); diff --git a/packages/algorithm/tests/src/repeat.spec.ts b/packages/algorithm/tests/src/repeat.spec.ts index ccc92e712..179ceb300 100644 --- a/packages/algorithm/tests/src/repeat.spec.ts +++ b/packages/algorithm/tests/src/repeat.spec.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { once, repeat, RepeatIterator } from '@lumino/algorithm'; +import { once, repeat } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; @@ -23,10 +23,4 @@ describe('@lumino/algorithm', () => { return [once('foo'), ['foo']]; }); }); - - describe('RepeatIterator', () => { - testIterator(() => { - return [new RepeatIterator('foo', 3), ['foo', 'foo', 'foo']]; - }); - }); }); diff --git a/packages/algorithm/tests/src/retro.spec.ts b/packages/algorithm/tests/src/retro.spec.ts index f3051a26d..8c98455bc 100644 --- a/packages/algorithm/tests/src/retro.spec.ts +++ b/packages/algorithm/tests/src/retro.spec.ts @@ -9,26 +9,26 @@ |----------------------------------------------------------------------------*/ import { expect } from 'chai'; -import { iter, retro, RetroArrayIterator, toArray } from '@lumino/algorithm'; +import { retro } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; describe('@lumino/algorithm', () => { describe('retro()', () => { it('should create an iterator for an array-like object', () => { - expect(toArray(retro([0, 1, 2, 3]))).to.deep.equal([3, 2, 1, 0]); + expect(Array.from(retro([0, 1, 2, 3]))).to.deep.equal([3, 2, 1, 0]); }); it('should call `retro` on a retroable', () => { - let iterator = iter([1, 2, 3, 4]); + let iterator = [1, 2, 3, 4][Symbol.iterator](); let retroable = { retro: () => iterator }; expect(retro(retroable)).to.equal(iterator); }); - }); - describe('RetroArrayIterator', () => { - testIterator(() => { - return [new RetroArrayIterator([1, 2, 3]), [3, 2, 1]]; + it('should reverse an array', () => { + testIterator(() => { + return [retro([1, 2, 3]), [3, 2, 1]]; + }); }); }); }); diff --git a/packages/algorithm/tests/src/stride.spec.ts b/packages/algorithm/tests/src/stride.spec.ts index 21e436c8d..a51d3e348 100644 --- a/packages/algorithm/tests/src/stride.spec.ts +++ b/packages/algorithm/tests/src/stride.spec.ts @@ -7,21 +7,21 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { iter, stride, StrideIterator } from '@lumino/algorithm'; +import { stride } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; describe('@lumino/algorithm', () => { - describe('stride()', () => { + describe('stride() with an array', () => { testIterator(() => { return [stride([0, 1, 2, 3, 4, 5], 2), [0, 2, 4]]; }); }); - describe('StrideIterator', () => { + describe('stride() with an iterable iterator', () => { testIterator(() => { - let it = iter([1, 2, 3, 4, 5, 6, 7]); - return [new StrideIterator(it, 3), [1, 4, 7]]; + let it = [1, 2, 3, 4, 5, 6, 7][Symbol.iterator](); + return [stride(it, 3), [1, 4, 7]]; }); }); }); diff --git a/packages/algorithm/tests/src/take.spec.ts b/packages/algorithm/tests/src/take.spec.ts index 9cb54e305..aa7bd0c34 100644 --- a/packages/algorithm/tests/src/take.spec.ts +++ b/packages/algorithm/tests/src/take.spec.ts @@ -7,20 +7,31 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { iter, take, TakeIterator } from '@lumino/algorithm'; +import { take } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; describe('@lumino/algorithm', () => { - describe('take()', () => { + describe('take() from an array', () => { testIterator(() => { return [take([1, 2, 3, 4, 5], 2), [1, 2]]; }); }); - describe('TakeIterator', () => { + describe('take() from an iterable iterator', () => { testIterator(() => { - return [new TakeIterator(iter([0, 1, 2, 3]), 1), [0]]; + return [take([0, 1, 2, 3], 1), [0]]; }); }); + + describe('take() with count=0', () => { + testIterator(() => [take([0, 1, 2, 3], 0), []]); + }); + + describe('take() only takes as many as count or are left', () => { + const it = [0, 1, 2, 3, 4, 5, 6][Symbol.iterator](); + testIterator(() => [take(it, 2), [0, 1]]); + testIterator(() => [take(it, 4), [2, 3, 4, 5]]); + testIterator(() => [take(it, 25), [6]]); + }); }); diff --git a/packages/algorithm/tests/src/zip.spec.ts b/packages/algorithm/tests/src/zip.spec.ts index a6a071602..f38ba995e 100644 --- a/packages/algorithm/tests/src/zip.spec.ts +++ b/packages/algorithm/tests/src/zip.spec.ts @@ -7,12 +7,12 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { iter, zip, ZipIterator } from '@lumino/algorithm'; +import { zip } from '@lumino/algorithm'; import { testIterator } from './iter.spec'; describe('@lumino/algorithm', () => { - describe('zip()', () => { + describe('zip() with same-length iterables', () => { testIterator(() => { return [ zip([1, 2, 3], [4, 5, 6]), @@ -25,16 +25,17 @@ describe('@lumino/algorithm', () => { }); }); - describe('ZipIterator', () => { + describe('zip() with different-length iterables', () => { testIterator(() => { - let i1 = iter(['one', 'two']); - let i2 = iter([1, 2]); - let i3 = iter([true, false]); - type T = string | number | boolean; - let it = new ZipIterator([i1, i2, i3]); + let i1 = ['one', 'two', 'three', 'four']; + let i2 = [true, false, true]; + let i3 = [1, 2, 3, 4]; + type T = string | boolean | number; + let it = zip(i1, i2, i3); let results = [ - ['one', 1, true], - ['two', 2, false] + ['one', true, 1], + ['two', false, 2], + ['three', true, 3] ]; return [it, results]; }); diff --git a/packages/collections/src/linkedlist.ts b/packages/collections/src/linkedlist.ts index a98fe9567..45666116f 100644 --- a/packages/collections/src/linkedlist.ts +++ b/packages/collections/src/linkedlist.ts @@ -7,18 +7,12 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { - each, - IIterable, - IIterator, - IRetroable, - IterableOrArrayLike -} from '@lumino/algorithm'; +import { IRetroable } from '@lumino/algorithm'; /** * A generic doubly-linked list. */ -export class LinkedList implements IIterable, IRetroable { +export class LinkedList implements Iterable, IRetroable { /** * Whether the list is empty. * @@ -113,8 +107,13 @@ export class LinkedList implements IIterable, IRetroable { * #### Complexity * Constant. */ - iter(): IIterator { - return new LinkedList.ForwardValueIterator(this._first); + [Symbol.iterator](): IterableIterator { + return (function* (node) { + while (node) { + yield node.value; + node = node.next; + } + })(this._first); } /** @@ -125,8 +124,13 @@ export class LinkedList implements IIterable, IRetroable { * #### Complexity * Constant. */ - retro(): IIterator { - return new LinkedList.RetroValueIterator(this._last); + retro(): IterableIterator { + return (function* (node) { + while (node) { + yield node.value; + node = node.prev; + } + })(this._last); } /** @@ -137,8 +141,13 @@ export class LinkedList implements IIterable, IRetroable { * #### Complexity * Constant. */ - nodes(): IIterator> { - return new LinkedList.ForwardNodeIterator(this._first); + nodes(): IterableIterator> { + return (function* (node) { + while (node) { + yield node; + node = node.next; + } + })(this._first); } /** @@ -149,8 +158,13 @@ export class LinkedList implements IIterable, IRetroable { * #### Complexity * Constant. */ - retroNodes(): IIterator> { - return new LinkedList.RetroNodeIterator(this._last); + retroNodes(): IterableIterator> { + return (function* (node) { + while (node) { + yield node; + node = node.prev; + } + })(this._last); } /** @@ -161,11 +175,11 @@ export class LinkedList implements IIterable, IRetroable { * #### Complexity * Linear. */ - assign(values: IterableOrArrayLike): void { + assign(values: Iterable): void { this.clear(); - each(values, value => { + for (const value of values) { this.addLast(value); - }); + } } /** @@ -502,210 +516,18 @@ export namespace LinkedList { /** * Create a linked list from an iterable of values. * - * @param values - The iterable or array-like object of interest. + * @param values - The iterable object of interest. * * @returns A new linked list initialized with the given values. * * #### Complexity * Linear. */ - export function from(values: IterableOrArrayLike): LinkedList { + export function from(values: Iterable): LinkedList { let list = new LinkedList(); list.assign(values); return list; } - - /** - * A forward iterator for values in a linked list. - */ - export class ForwardValueIterator implements IIterator { - /** - * Construct a forward value iterator. - * - * @param node - The first node in the list. - */ - constructor(node: INode | null) { - this._node = node; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new ForwardValueIterator(this._node); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (!this._node) { - return undefined; - } - let node = this._node; - this._node = node.next; - return node.value; - } - - private _node: INode | null; - } - - /** - * A reverse iterator for values in a linked list. - */ - export class RetroValueIterator implements IIterator { - /** - * Construct a retro value iterator. - * - * @param node - The last node in the list. - */ - constructor(node: INode | null) { - this._node = node; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator { - return new RetroValueIterator(this._node); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): T | undefined { - if (!this._node) { - return undefined; - } - let node = this._node; - this._node = node.prev; - return node.value; - } - - private _node: INode | null; - } - - /** - * A forward iterator for nodes in a linked list. - */ - export class ForwardNodeIterator implements IIterator> { - /** - * Construct a forward node iterator. - * - * @param node - The first node in the list. - */ - constructor(node: INode | null) { - this._node = node; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator> { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator> { - return new ForwardNodeIterator(this._node); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): INode | undefined { - if (!this._node) { - return undefined; - } - let node = this._node; - this._node = node.next; - return node; - } - - private _node: INode | null; - } - - /** - * A reverse iterator for nodes in a linked list. - */ - export class RetroNodeIterator implements IIterator> { - /** - * Construct a retro node iterator. - * - * @param node - The last node in the list. - */ - constructor(node: INode | null) { - this._node = node; - } - - /** - * Get an iterator over the object's values. - * - * @returns An iterator which yields the object's values. - */ - iter(): IIterator> { - return this; - } - - /** - * Create an independent clone of the iterator. - * - * @returns A new independent clone of the iterator. - */ - clone(): IIterator> { - return new RetroNodeIterator(this._node); - } - - /** - * Get the next value from the iterator. - * - * @returns The next value from the iterator, or `undefined`. - */ - next(): INode | undefined { - if (!this._node) { - return undefined; - } - let node = this._node; - this._node = node.prev; - return node; - } - - private _node: INode | null; - } } /** diff --git a/packages/collections/tests/src/linkedlist.spec.ts b/packages/collections/tests/src/linkedlist.spec.ts index 61c47d82e..2ee372603 100644 --- a/packages/collections/tests/src/linkedlist.spec.ts +++ b/packages/collections/tests/src/linkedlist.spec.ts @@ -9,7 +9,7 @@ |----------------------------------------------------------------------------*/ import { expect } from 'chai'; -import { find, map, toArray } from '@lumino/algorithm'; +import { find, map } from '@lumino/algorithm'; import { LinkedList } from '@lumino/collections'; @@ -98,16 +98,17 @@ describe('@lumino/collections', () => { }); }); - describe('#iter()', () => { + describe('[Symbol.iterator]()', () => { it('should return an iterator over the list values', () => { let data = [0, 1, 2, 3, 4, 5]; let list = LinkedList.from(data); - let it1 = list.iter(); - let it2 = it1.clone(); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(it1)).to.deep.equal(data); - expect(toArray(it2)).to.deep.equal(data); + let it1 = list[Symbol.iterator](); + let it2 = list[Symbol.iterator](); + expect(it1[Symbol.iterator]()).to.equal(it1); + expect(it2[Symbol.iterator]()).to.equal(it2); + expect(it1).to.not.equal(it2); + expect(Array.from(it1)).to.deep.equal(data); + expect(Array.from(it2)).to.deep.equal(data); }); }); @@ -117,11 +118,12 @@ describe('@lumino/collections', () => { let reversed = data.slice().reverse(); let list = LinkedList.from(data); let it1 = list.retro(); - let it2 = it1.clone(); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(it1)).to.deep.equal(reversed); - expect(toArray(it2)).to.deep.equal(reversed); + let it2 = list.retro(); + expect(it1[Symbol.iterator]()).to.equal(it1); + expect(it2[Symbol.iterator]()).to.equal(it2); + expect(it1).to.not.equal(it2); + expect(Array.from(it1)).to.deep.equal(reversed); + expect(Array.from(it2)).to.deep.equal(reversed); }); }); @@ -130,13 +132,14 @@ describe('@lumino/collections', () => { let data = [0, 1, 2, 3, 4, 5]; let list = LinkedList.from(data); let it1 = list.nodes(); - let it2 = it1.clone(); + let it2 = list.nodes(); let v1 = map(it1, n => n.value); let v2 = map(it2, n => n.value); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(v1)).to.deep.equal(data); - expect(toArray(v2)).to.deep.equal(data); + expect(it1[Symbol.iterator]()).to.equal(it1); + expect(it2[Symbol.iterator]()).to.equal(it2); + expect(it1).to.not.equal(it2); + expect(Array.from(v1)).to.deep.equal(data); + expect(Array.from(v2)).to.deep.equal(data); }); }); @@ -146,13 +149,14 @@ describe('@lumino/collections', () => { let reversed = data.slice().reverse(); let list = LinkedList.from(data); let it1 = list.retroNodes(); - let it2 = it1.clone(); + let it2 = list.retroNodes(); let v1 = map(it1, n => n.value); let v2 = map(it2, n => n.value); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(v1)).to.deep.equal(reversed); - expect(toArray(v2)).to.deep.equal(reversed); + expect(it1[Symbol.iterator]()).to.equal(it1); + expect(it2[Symbol.iterator]()).to.equal(it2); + expect(it1).to.not.equal(it2); + expect(Array.from(v1)).to.deep.equal(reversed); + expect(Array.from(v2)).to.deep.equal(reversed); }); }); @@ -186,7 +190,7 @@ describe('@lumino/collections', () => { expect(list.first).to.equal(7); expect(list.last).to.equal(99); - expect(toArray(list)).to.deep.equal([7, 42, 99]); + expect(Array.from(list)).to.deep.equal([7, 42, 99]); expect(n1.list).to.equal(list); expect(n1.next).to.equal(null); @@ -235,7 +239,7 @@ describe('@lumino/collections', () => { expect(list.first).to.equal(99); expect(list.last).to.equal(7); - expect(toArray(list)).to.deep.equal([99, 42, 7]); + expect(Array.from(list)).to.deep.equal([99, 42, 7]); expect(n1.list).to.equal(list); expect(n1.next).to.equal(n2); @@ -270,7 +274,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(7); expect(list.first).to.equal(9); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([9, 0, 1, 8, 7, 2, 3]); + expect(Array.from(list)).to.deep.equal([9, 0, 1, 8, 7, 2, 3]); expect(n1.list).to.equal(list); expect(n1.next).to.equal(list.lastNode); @@ -319,7 +323,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(7); expect(list.first).to.equal(0); expect(list.last).to.equal(9); - expect(toArray(list)).to.deep.equal([0, 1, 2, 7, 8, 3, 9]); + expect(Array.from(list)).to.deep.equal([0, 1, 2, 7, 8, 3, 9]); expect(n1.list).to.equal(list); expect(n1.next).to.equal(n2); @@ -360,7 +364,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(4); expect(list.first).to.equal(0); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([0, 1, 2, 3]); + expect(Array.from(list)).to.deep.equal([0, 1, 2, 3]); let v1 = list.removeFirst(); @@ -368,7 +372,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(3); expect(list.first).to.equal(1); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([1, 2, 3]); + expect(Array.from(list)).to.deep.equal([1, 2, 3]); let v2 = list.removeFirst(); @@ -376,7 +380,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(2); expect(list.first).to.equal(2); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([2, 3]); + expect(Array.from(list)).to.deep.equal([2, 3]); let v3 = list.removeFirst(); @@ -384,7 +388,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(1); expect(list.first).to.equal(3); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([3]); + expect(Array.from(list)).to.deep.equal([3]); let v4 = list.removeFirst(); @@ -392,7 +396,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(0); expect(list.first).to.equal(undefined); expect(list.last).to.equal(undefined); - expect(toArray(list)).to.deep.equal([]); + expect(Array.from(list)).to.deep.equal([]); let v5 = list.removeFirst(); @@ -400,7 +404,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(0); expect(list.first).to.equal(undefined); expect(list.last).to.equal(undefined); - expect(toArray(list)).to.deep.equal([]); + expect(Array.from(list)).to.deep.equal([]); expect(v1).to.equal(0); expect(v2).to.equal(1); @@ -418,7 +422,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(4); expect(list.first).to.equal(0); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([0, 1, 2, 3]); + expect(Array.from(list)).to.deep.equal([0, 1, 2, 3]); let v1 = list.removeLast(); @@ -426,7 +430,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(3); expect(list.first).to.equal(0); expect(list.last).to.equal(2); - expect(toArray(list)).to.deep.equal([0, 1, 2]); + expect(Array.from(list)).to.deep.equal([0, 1, 2]); let v2 = list.removeLast(); @@ -434,7 +438,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(2); expect(list.first).to.equal(0); expect(list.last).to.equal(1); - expect(toArray(list)).to.deep.equal([0, 1]); + expect(Array.from(list)).to.deep.equal([0, 1]); let v3 = list.removeLast(); @@ -442,7 +446,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(1); expect(list.first).to.equal(0); expect(list.last).to.equal(0); - expect(toArray(list)).to.deep.equal([0]); + expect(Array.from(list)).to.deep.equal([0]); let v4 = list.removeLast(); @@ -450,7 +454,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(0); expect(list.first).to.equal(undefined); expect(list.last).to.equal(undefined); - expect(toArray(list)).to.deep.equal([]); + expect(Array.from(list)).to.deep.equal([]); let v5 = list.removeLast(); @@ -458,7 +462,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(0); expect(list.first).to.equal(undefined); expect(list.last).to.equal(undefined); - expect(toArray(list)).to.deep.equal([]); + expect(Array.from(list)).to.deep.equal([]); expect(v1).to.equal(3); expect(v2).to.equal(2); @@ -476,7 +480,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(4); expect(list.first).to.equal(0); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([0, 1, 2, 3]); + expect(Array.from(list)).to.deep.equal([0, 1, 2, 3]); let n1 = find(list.nodes(), n => n.value === 2)!; list.removeNode(n1); @@ -484,7 +488,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(3); expect(list.first).to.equal(0); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([0, 1, 3]); + expect(Array.from(list)).to.deep.equal([0, 1, 3]); expect(n1.list).to.equal(null); expect(n1.next).to.equal(null); expect(n1.prev).to.equal(null); @@ -496,7 +500,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(2); expect(list.first).to.equal(0); expect(list.last).to.equal(1); - expect(toArray(list)).to.deep.equal([0, 1]); + expect(Array.from(list)).to.deep.equal([0, 1]); expect(n2.list).to.equal(null); expect(n2.next).to.equal(null); expect(n2.prev).to.equal(null); @@ -508,7 +512,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(1); expect(list.first).to.equal(1); expect(list.last).to.equal(1); - expect(toArray(list)).to.deep.equal([1]); + expect(Array.from(list)).to.deep.equal([1]); expect(n3.list).to.equal(null); expect(n3.next).to.equal(null); expect(n3.prev).to.equal(null); @@ -520,7 +524,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(0); expect(list.first).to.equal(undefined); expect(list.last).to.equal(undefined); - expect(toArray(list)).to.deep.equal([]); + expect(Array.from(list)).to.deep.equal([]); expect(n4.list).to.equal(null); expect(n4.next).to.equal(null); expect(n4.prev).to.equal(null); @@ -536,7 +540,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(4); expect(list.first).to.equal(0); expect(list.last).to.equal(3); - expect(toArray(list)).to.deep.equal([0, 1, 2, 3]); + expect(Array.from(list)).to.deep.equal([0, 1, 2, 3]); list.clear(); @@ -544,7 +548,7 @@ describe('@lumino/collections', () => { expect(list.length).to.equal(0); expect(list.first).to.equal(undefined); expect(list.last).to.equal(undefined); - expect(toArray(list)).to.deep.equal([]); + expect(Array.from(list)).to.deep.equal([]); }); }); @@ -556,63 +560,7 @@ describe('@lumino/collections', () => { expect(list2.length).to.equal(4); expect(list2.first).to.equal(0); expect(list2.last).to.equal(3); - expect(toArray(list2)).to.deep.equal([0, 1, 2, 3]); - }); - }); - - describe('.ForwardValueIterator', () => { - it('should create a forward iterator over the values', () => { - let list = LinkedList.from([0, 1, 2, 3, 4]); - let n = find(list.nodes(), n => n.value === 2)!; - let it1 = new LinkedList.ForwardValueIterator(n); - let it2 = it1.clone(); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(it1)).to.deep.equal([2, 3, 4]); - expect(toArray(it2)).to.deep.equal([2, 3, 4]); - }); - }); - - describe('.RetroValueIterator', () => { - it('should create a reverse iterator over the values', () => { - let list = LinkedList.from([0, 1, 2, 3, 4]); - let n = find(list.nodes(), n => n.value === 2)!; - let it1 = new LinkedList.RetroValueIterator(n); - let it2 = it1.clone(); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(it1)).to.deep.equal([2, 1, 0]); - expect(toArray(it2)).to.deep.equal([2, 1, 0]); - }); - }); - - describe('.ForwardNodeIterator', () => { - it('should create a forward iterator over the nodes', () => { - let list = LinkedList.from([0, 1, 2, 3, 4]); - let n = find(list.nodes(), n => n.value === 2)!; - let it1 = new LinkedList.ForwardNodeIterator(n); - let it2 = it1.clone(); - let v1 = map(it1, n => n.value); - let v2 = map(it2, n => n.value); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(v1)).to.deep.equal([2, 3, 4]); - expect(toArray(v2)).to.deep.equal([2, 3, 4]); - }); - }); - - describe('.RetroNodeIterator', () => { - it('should create a reverse iterator over the nodes', () => { - let list = LinkedList.from([0, 1, 2, 3, 4]); - let n = find(list.nodes(), n => n.value === 2)!; - let it1 = new LinkedList.RetroNodeIterator(n); - let it2 = it1.clone(); - let v1 = map(it1, n => n.value); - let v2 = map(it2, n => n.value); - expect(it1.iter()).to.equal(it1); - expect(it2.iter()).to.equal(it2); - expect(toArray(v1)).to.deep.equal([2, 1, 0]); - expect(toArray(v2)).to.deep.equal([2, 1, 0]); + expect(Array.from(list2)).to.deep.equal([0, 1, 2, 3]); }); }); }); diff --git a/packages/datagrid/src/basickeyhandler.ts b/packages/datagrid/src/basickeyhandler.ts index 64d7a5190..a92ca401d 100644 --- a/packages/datagrid/src/basickeyhandler.ts +++ b/packages/datagrid/src/basickeyhandler.ts @@ -758,9 +758,7 @@ export class BasicKeyHandler implements DataGrid.IKeyHandler { let maxRow = dataModel.rowCount('body') - 1; let maxColumn = dataModel.columnCount('body') - 1; - const it = grid.selectionModel!.selections(); - let s: SelectionModel.Selection | undefined; - while ((s = it.next()) !== undefined) { + for (let s of grid.selectionModel!.selections()) { // Clamp the cell to the model bounds. let sr1 = Math.max(0, Math.min(s.r1, maxRow)); let sc1 = Math.max(0, Math.min(s.c1, maxColumn)); diff --git a/packages/datagrid/src/basicselectionmodel.ts b/packages/datagrid/src/basicselectionmodel.ts index ffd04d296..75791babb 100644 --- a/packages/datagrid/src/basicselectionmodel.ts +++ b/packages/datagrid/src/basicselectionmodel.ts @@ -7,8 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, iter } from '@lumino/algorithm'; - import { DataModel } from './datamodel'; import { SelectionModel } from './selectionmodel'; @@ -152,8 +150,8 @@ export class BasicSelectionModel extends SelectionModel { * #### Notes * The data grid will render the selections in order. */ - selections(): IIterator { - return iter(this._selections); + selections(): IterableIterator { + return this._selections[Symbol.iterator](); } /** diff --git a/packages/datagrid/src/datagrid.ts b/packages/datagrid/src/datagrid.ts index 7dda9b21f..ed0c69fc9 100644 --- a/packages/datagrid/src/datagrid.ts +++ b/packages/datagrid/src/datagrid.ts @@ -7,8 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { toArray } from '@lumino/algorithm'; - import { IDisposable } from '@lumino/disposable'; import { ClipboardExt, ElementExt, Platform } from '@lumino/domutils'; @@ -1767,7 +1765,7 @@ export class DataGrid extends Widget { } // Coerce the selections to an array. - let selections = toArray(selectionModel.selections()); + let selections = Array.from(selectionModel.selections()); // Bail early if there are no selections. if (selections.length === 0) { @@ -5194,9 +5192,7 @@ export class DataGrid extends Widget { } // Iterate over the selections. - let it = model.selections(); - let s: SelectionModel.Selection | undefined; - while ((s = it.next()) !== undefined) { + for (let s of model.selections()) { // Skip the section if it's not visible. if (s.r1 < r1 && s.r2 < r1) { continue; diff --git a/packages/datagrid/src/selectionmodel.ts b/packages/datagrid/src/selectionmodel.ts index 912275b80..721780d4e 100644 --- a/packages/datagrid/src/selectionmodel.ts +++ b/packages/datagrid/src/selectionmodel.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { IIterator, some } from '@lumino/algorithm'; +import { some } from '@lumino/algorithm'; import { ISignal, Signal } from '@lumino/signaling'; @@ -82,7 +82,7 @@ export abstract class SelectionModel { * #### Notes * The data grid will render the selections in order. */ - abstract selections(): IIterator; + abstract selections(): IterableIterator; /** * Select the specified cells. diff --git a/packages/disposable/package.json b/packages/disposable/package.json index b0e3fd3f1..4b8df7215 100644 --- a/packages/disposable/package.json +++ b/packages/disposable/package.json @@ -40,7 +40,6 @@ "watch": "tsc --build --watch" }, "dependencies": { - "@lumino/algorithm": "^1.9.1", "@lumino/signaling": "^1.10.1" }, "devDependencies": { diff --git a/packages/disposable/src/index.ts b/packages/disposable/src/index.ts index ab6a7be05..d9cc31476 100644 --- a/packages/disposable/src/index.ts +++ b/packages/disposable/src/index.ts @@ -7,8 +7,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { each, IterableOrArrayLike } from '@lumino/algorithm'; - import { ISignal, Signal } from '@lumino/signaling'; /** @@ -192,15 +190,15 @@ export namespace DisposableSet { /** * Create a disposable set from an iterable of items. * - * @param items - The iterable or array-like object of interest. + * @param items - The iterable object of interest. * * @returns A new disposable initialized with the given items. */ - export function from(items: IterableOrArrayLike): DisposableSet { + export function from(items: Iterable): DisposableSet { let set = new DisposableSet(); - each(items, item => { + for (const item of items) { set.add(item); - }); + } return set; } } @@ -244,17 +242,15 @@ export namespace ObservableDisposableSet { /** * Create an observable disposable set from an iterable of items. * - * @param items - The iterable or array-like object of interest. + * @param items - The iterable object of interest. * * @returns A new disposable initialized with the given items. */ - export function from( - items: IterableOrArrayLike - ): ObservableDisposableSet { + export function from(items: Iterable): ObservableDisposableSet { let set = new ObservableDisposableSet(); - each(items, item => { + for (const item of items) { set.add(item); - }); + } return set; } } diff --git a/packages/messaging/src/index.ts b/packages/messaging/src/index.ts index d72a68129..0602758b0 100644 --- a/packages/messaging/src/index.ts +++ b/packages/messaging/src/index.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each, every, retro, some } from '@lumino/algorithm'; +import { ArrayExt, every, retro, some } from '@lumino/algorithm'; import { LinkedList } from '@lumino/collections'; @@ -366,12 +366,12 @@ export namespace MessageLoop { } // Clear all posted messages for the handler. - each(messageQueue, posted => { + for (const posted of messageQueue) { if (posted.handler === handler) { posted.handler = null; posted.msg = null; } - }); + } } /** diff --git a/packages/signaling/src/index.ts b/packages/signaling/src/index.ts index 4b1d6234e..1dd57f923 100644 --- a/packages/signaling/src/index.ts +++ b/packages/signaling/src/index.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each, find } from '@lumino/algorithm'; +import { ArrayExt, find } from '@lumino/algorithm'; /** * A type alias for a slot function. @@ -416,17 +416,17 @@ namespace Private { } // Clear each connection between the sender and receiver. - each(senders, connection => { + for (const connection of senders) { // Skip connections which have already been cleared. if (!connection.signal) { - return; + continue; } // Clear the connection if it matches the sender. if (connection.signal.sender === sender) { connection.signal = null; } - }); + } // Schedule a cleanup of the senders and receivers. scheduleCleanup(receivers); @@ -446,10 +446,10 @@ namespace Private { } // Clear each receiver connection. - each(receivers, connection => { + for (const connection of receivers) { // Skip connections which have already been cleared. if (!connection.signal) { - return; + continue; } // Choose the best object for the receiver. @@ -460,7 +460,7 @@ namespace Private { // Cleanup the array of senders, which is now known to exist. scheduleCleanup(sendersForReceiver.get(receiver)!); - }); + } // Schedule a cleanup of the receivers. scheduleCleanup(receivers); @@ -479,10 +479,10 @@ namespace Private { } // Clear each sender connection. - each(senders, connection => { + for (const connection of senders) { // Skip connections which have already been cleared. if (!connection.signal) { - return; + continue; } // Lookup the sender for the connection. @@ -493,7 +493,7 @@ namespace Private { // Cleanup the array of receivers, which is now known to exist. scheduleCleanup(receiversForSender.get(sender)!); - }); + } // Schedule a cleanup of the list of senders. scheduleCleanup(senders); diff --git a/packages/widgets/src/boxlayout.ts b/packages/widgets/src/boxlayout.ts index 558c05801..331c323d0 100644 --- a/packages/widgets/src/boxlayout.ts +++ b/packages/widgets/src/boxlayout.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each } from '@lumino/algorithm'; +import { ArrayExt } from '@lumino/algorithm'; import { ElementExt } from '@lumino/domutils'; @@ -52,9 +52,9 @@ export class BoxLayout extends PanelLayout { */ dispose(): void { // Dispose of the layout items. - each(this._items, item => { + for (const item of this._items) { item.dispose(); - }); + } // Clear the layout state. this._box = null; diff --git a/packages/widgets/src/contextmenu.ts b/packages/widgets/src/contextmenu.ts index d62ea1ab5..a3fd006e1 100644 --- a/packages/widgets/src/contextmenu.ts +++ b/packages/widgets/src/contextmenu.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each } from '@lumino/algorithm'; +import { ArrayExt } from '@lumino/algorithm'; import { CommandRegistry } from '@lumino/commands'; @@ -100,9 +100,9 @@ export class ContextMenu { } // Add the filtered items to the menu. - each(items, item => { + for (const item of items) { this.menu.addItem(item); - }); + } // Open the context menu at the current mouse position. this.menu.open(event.clientX, event.clientY); diff --git a/packages/widgets/src/docklayout.ts b/packages/widgets/src/docklayout.ts index b9bf62f63..bb4a1523b 100644 --- a/packages/widgets/src/docklayout.ts +++ b/packages/widgets/src/docklayout.ts @@ -7,17 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { - ArrayExt, - chain, - ChainIterator, - each, - empty, - IIterator, - map, - once, - reduce -} from '@lumino/algorithm'; +import { ArrayExt, chain, empty, map, once } from '@lumino/algorithm'; import { ElementExt } from '@lumino/domutils'; @@ -68,7 +58,7 @@ export class DockLayout extends Layout { */ dispose(): void { // Get an iterator over the widgets in the layout. - let widgets = this.iter(); + let widgets = this[Symbol.iterator](); // Dispose of the layout items. this._items.forEach(item => { @@ -81,9 +71,9 @@ export class DockLayout extends Layout { this._items.clear(); // Dispose of the widgets contained in the old layout root. - each(widgets, widget => { + for (const widget of widgets) { widget.dispose(); - }); + } // Dispose of the base class. super.dispose(); @@ -109,13 +99,13 @@ export class DockLayout extends Layout { return; } this._hiddenMode = v; - each(this.tabBars(), bar => { + for (const bar of this.tabBars()) { if (bar.titles.length > 1) { - bar.titles.forEach(title => { + for (const title of bar.titles) { title.owner.hiddenMode = this._hiddenMode; - }); + } } - }); + } } /** @@ -155,7 +145,7 @@ export class DockLayout extends Layout { * #### Notes * This iterator includes the generated tab bars. */ - iter(): IIterator { + [Symbol.iterator](): IterableIterator { return this._root ? this._root.iterAllWidgets() : empty(); } @@ -167,7 +157,7 @@ export class DockLayout extends Layout { * #### Notes * This iterator does not include the generated tab bars. */ - widgets(): IIterator { + widgets(): IterableIterator { return this._root ? this._root.iterUserWidgets() : empty(); } @@ -180,7 +170,7 @@ export class DockLayout extends Layout { * This iterator yields the widgets corresponding to the current tab * of each tab bar in the layout. */ - selectedWidgets(): IIterator { + selectedWidgets(): IterableIterator { return this._root ? this._root.iterSelectedWidgets() : empty(); } @@ -192,7 +182,7 @@ export class DockLayout extends Layout { * #### Notes * This iterator does not include the user widgets. */ - tabBars(): IIterator> { + tabBars(): IterableIterator> { return this._root ? this._root.iterTabBars() : empty>(); } @@ -201,7 +191,7 @@ export class DockLayout extends Layout { * * @returns A new iterator over the handles in the layout. */ - handles(): IIterator { + handles(): IterableIterator { return this._root ? this._root.iterHandles() : empty(); } @@ -315,28 +305,28 @@ export class DockLayout extends Layout { this._root = null; // Unparent the old widgets which are not in the new config. - each(oldWidgets, widget => { + for (const widget of oldWidgets) { if (!widgetSet.has(widget)) { widget.parent = null; } - }); + } // Dispose of the old tab bars. - each(oldTabBars, tabBar => { + for (const tabBar of oldTabBars) { tabBar.dispose(); - }); + } // Remove the old handles. - each(oldHandles, handle => { + for (const handle of oldHandles) { if (handle.parentNode) { handle.parentNode.removeChild(handle); } - }); + } // Reparent the new widgets to the current parent. - widgetSet.forEach(widget => { + for (const widget of widgetSet) { widget.parent = this.parent; - }); + } // Create the root node for the new config. if (mainConfig) { @@ -520,14 +510,14 @@ export class DockLayout extends Layout { super.init(); // Attach each widget to the parent. - each(this, widget => { + for (const widget of this) { this.attachWidget(widget); - }); + } // Attach each handle to the parent. - each(this.handles(), handle => { + for (const handle of this.handles()) { this.parent!.node.appendChild(handle); - }); + } // Post a fit request for the parent widget. this.parent!.fit(); @@ -1561,21 +1551,21 @@ namespace Private { /** * Create an iterator for all widgets in the layout tree. */ - iterAllWidgets(): IIterator { + iterAllWidgets(): IterableIterator { return chain(once(this.tabBar), this.iterUserWidgets()); } /** * Create an iterator for the user widgets in the layout tree. */ - iterUserWidgets(): IIterator { + iterUserWidgets(): IterableIterator { return map(this.tabBar.titles, title => title.owner); } /** * Create an iterator for the selected widgets in the layout tree. */ - iterSelectedWidgets(): IIterator { + iterSelectedWidgets(): IterableIterator { let title = this.tabBar.currentTitle; return title ? once(title.owner) : empty(); } @@ -1583,14 +1573,14 @@ namespace Private { /** * Create an iterator for the tab bars in the layout tree. */ - iterTabBars(): IIterator> { + iterTabBars(): IterableIterator> { return once(this.tabBar); } /** * Create an iterator for the handles in the layout tree. */ - iterHandles(): IIterator { + iterHandles(): IterableIterator { return empty(); } @@ -1797,41 +1787,41 @@ namespace Private { /** * Create an iterator for all widgets in the layout tree. */ - iterAllWidgets(): IIterator { + iterAllWidgets(): IterableIterator { let children = map(this.children, child => child.iterAllWidgets()); - return new ChainIterator(children); + return chain(...children); } /** * Create an iterator for the user widgets in the layout tree. */ - iterUserWidgets(): IIterator { + iterUserWidgets(): IterableIterator { let children = map(this.children, child => child.iterUserWidgets()); - return new ChainIterator(children); + return chain(...children); } /** * Create an iterator for the selected widgets in the layout tree. */ - iterSelectedWidgets(): IIterator { + iterSelectedWidgets(): IterableIterator { let children = map(this.children, child => child.iterSelectedWidgets()); - return new ChainIterator(children); + return chain(...children); } /** * Create an iterator for the tab bars in the layout tree. */ - iterTabBars(): IIterator> { + iterTabBars(): IterableIterator> { let children = map(this.children, child => child.iterTabBars()); - return new ChainIterator>(children); + return chain>(...children); } /** * Create an iterator for the handles in the layout tree. */ - iterHandles(): IIterator { + iterHandles(): IterableIterator { let children = map(this.children, child => child.iterHandles()); - return chain(this.handles, new ChainIterator(children)); + return chain(this.handles, ...children); } /** @@ -1903,7 +1893,7 @@ namespace Private { * Sync the visibility and orientation of the handles. */ syncHandles(): void { - each(this.handles, (handle, i) => { + this.handles.forEach((handle, i) => { handle.setAttribute('data-orientation', this.orientation); if (i === this.handles.length - 1) { handle.classList.add('lm-mod-hidden'); @@ -1919,9 +1909,9 @@ namespace Private { * This sets the size hint of each sizer to its current size. */ holdSizes(): void { - each(this.sizers, sizer => { + for (const sizer of this.sizers) { sizer.sizeHint = sizer.size; - }); + } } /** @@ -1930,7 +1920,9 @@ namespace Private { * This ignores the sizers of tab layout nodes. */ holdAllSizes(): void { - each(this.children, child => child.holdAllSizes()); + for (const child of this.children) { + child.holdAllSizes(); + } this.holdSizes(); } @@ -1948,17 +1940,17 @@ namespace Private { this.holdSizes(); // Compute the sum of the sizes. - let sum = reduce(this.sizers, (v, sizer) => v + sizer.sizeHint, 0); + let sum = this.sizers.reduce((v, sizer) => v + sizer.sizeHint, 0); // Normalize the sizes based on the sum. if (sum === 0) { - each(this.sizers, sizer => { + for (const sizer of this.sizers) { sizer.size = sizer.sizeHint = 1 / n; - }); + } } else { - each(this.sizers, sizer => { + for (const sizer of this.sizers) { sizer.size = sizer.sizeHint /= sum; - }); + } } // Mark the sizes as normalized. @@ -1979,17 +1971,17 @@ namespace Private { let sizes = this.sizers.map(sizer => sizer.size); // Compute the sum of the sizes. - let sum = reduce(sizes, (v, size) => v + size, 0); + let sum = sizes.reduce((v, size) => v + size, 0); // Normalize the sizes based on the sum. if (sum === 0) { - each(sizes, (size, i) => { + for (let i = sizes.length - 1; i > -1; i--) { sizes[i] = 1 / n; - }); + } } else { - each(sizes, (size, i) => { - sizes[i] = size / sum; - }); + for (let i = sizes.length - 1; i > -1; i--) { + sizes[i] /= sum; + } } // Return the normalized sizes. @@ -2046,9 +2038,9 @@ namespace Private { // De-normalize the sizes if needed. if (this.normalized) { - each(this.sizers, sizer => { + for (const sizer of this.sizers) { sizer.sizeHint *= space; - }); + } this.normalized = false; } @@ -2115,12 +2107,12 @@ namespace Private { let widgets: Widget[] = []; // Filter the config for unique widgets. - each(config.widgets, widget => { + for (const widget of config.widgets) { if (!widgetSet.has(widget)) { widgetSet.add(widget); widgets.push(widget); } - }); + } // Bail if there are no effective widgets. if (widgets.length === 0) { @@ -2195,11 +2187,11 @@ namespace Private { let tabBar = renderer.createTabBar(document); // Hide each widget and add it to the tab bar. - each(config.widgets, widget => { + for (const widget of config.widgets) { widget.hide(); tabBar.addTab(widget.title); Private.addAria(widget, tabBar); - }); + } // Set the current index of the tab bar. tabBar.currentIndex = config.currentIndex; @@ -2220,7 +2212,7 @@ namespace Private { let node = new SplitLayoutNode(config.orientation); // Add each child to the layout node. - each(config.children, (child, i) => { + config.children.forEach((child, i) => { // Create the child data for the layout node. let childNode = realizeAreaConfig(child, renderer, document); let sizer = createSizer(config.sizes[i]); diff --git a/packages/widgets/src/dockpanel.ts b/packages/widgets/src/dockpanel.ts index 743bd15b3..53d30590d 100644 --- a/packages/widgets/src/dockpanel.ts +++ b/packages/widgets/src/dockpanel.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { each, find, IIterator, toArray } from '@lumino/algorithm'; +import { find } from '@lumino/algorithm'; import { MimeData } from '@lumino/coreutils'; @@ -192,9 +192,9 @@ export class DockPanel extends Widget { // Configure the layout for the specified mode. switch (value) { case 'multiple-document': - each(layout.tabBars(), tabBar => { + for (const tabBar of layout.tabBars()) { tabBar.show(); - }); + } break; case 'single-document': layout.restoreLayout(Private.createSingleDocumentConfig(this)); @@ -219,9 +219,9 @@ export class DockPanel extends Widget { */ set tabsMovable(value: boolean) { this._tabsMovable = value; - each(this.tabBars(), tabbar => { - tabbar.tabsMovable = value; - }); + for (const tabBar of this.tabBars()) { + tabBar.tabsMovable = value; + } } /** @@ -250,9 +250,9 @@ export class DockPanel extends Widget { */ set addButtonEnabled(value: boolean) { this._addButtonEnabled = value; - each(this.tabBars(), tabbar => { - tabbar.addButtonEnabled = value; - }); + for (const tabBar of this.tabBars()) { + tabBar.addButtonEnabled = value; + } } /** @@ -270,7 +270,7 @@ export class DockPanel extends Widget { * #### Notes * This iterator does not include the generated tab bars. */ - widgets(): IIterator { + widgets(): IterableIterator { return (this.layout as DockLayout).widgets(); } @@ -283,7 +283,7 @@ export class DockPanel extends Widget { * This iterator yields the widgets corresponding to the current tab * of each tab bar in the panel. */ - selectedWidgets(): IIterator { + selectedWidgets(): IterableIterator { return (this.layout as DockLayout).selectedWidgets(); } @@ -295,7 +295,7 @@ export class DockPanel extends Widget { * #### Notes * This iterator does not include the user widgets. */ - tabBars(): IIterator> { + tabBars(): IterableIterator> { return (this.layout as DockLayout).tabBars(); } @@ -304,7 +304,7 @@ export class DockPanel extends Widget { * * @returns A new iterator over the handles in the panel. */ - handles(): IIterator { + handles(): IterableIterator { return (this.layout as DockLayout).handles(); } @@ -1553,10 +1553,10 @@ namespace Private { } // Get a flat array of the widgets in the panel. - let widgets = toArray(panel.widgets()); + let widgets = Array.from(panel.widgets()); // Get the first selected widget in the panel. - let selected = panel.selectedWidgets().next(); + let selected = panel.selectedWidgets().next().value; // Compute the current index for the new config. let currentIndex = selected ? widgets.indexOf(selected) : -1; diff --git a/packages/widgets/src/focustracker.ts b/packages/widgets/src/focustracker.ts index e12a1bb66..c5241833c 100644 --- a/packages/widgets/src/focustracker.ts +++ b/packages/widgets/src/focustracker.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each, filter, find, max } from '@lumino/algorithm'; +import { ArrayExt, find, max } from '@lumino/algorithm'; import { IDisposable } from '@lumino/disposable'; @@ -38,10 +38,10 @@ export class FocusTracker implements IDisposable { Signal.clearData(this); // Remove all event listeners. - each(this._widgets, w => { - w.node.removeEventListener('focus', this, true); - w.node.removeEventListener('blur', this, true); - }); + for (const widget of this._widgets) { + widget.node.removeEventListener('focus', this, true); + widget.node.removeEventListener('blur', this, true); + } // Clear the internal data structures. this._activeWidget = null; @@ -226,7 +226,7 @@ export class FocusTracker implements IDisposable { } // Filter the widgets for those which have had focus. - let valid = filter(this._widgets, w => this._numbers.get(w) !== -1); + let valid = this._widgets.filter(w => this._numbers.get(w) !== -1); // Get the valid widget with the max focus number. let previous = diff --git a/packages/widgets/src/gridlayout.ts b/packages/widgets/src/gridlayout.ts index a77f05121..f9398a165 100644 --- a/packages/widgets/src/gridlayout.ts +++ b/packages/widgets/src/gridlayout.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each, IIterator, map } from '@lumino/algorithm'; +import { ArrayExt, map } from '@lumino/algorithm'; import { ElementExt } from '@lumino/domutils'; @@ -51,11 +51,11 @@ export class GridLayout extends Layout { */ dispose(): void { // Dispose of the widgets and layout items. - each(this._items, item => { + for (const item of this._items) { let widget = item.widget; item.dispose(); widget.dispose(); - }); + } // Clear the layout state. this._box = null; @@ -288,7 +288,7 @@ export class GridLayout extends Layout { * * @returns A new iterator over the widgets in the layout. */ - iter(): IIterator { + [Symbol.iterator](): IterableIterator { return map(this._items, item => item.widget); } @@ -357,9 +357,9 @@ export class GridLayout extends Layout { */ protected init(): void { super.init(); - each(this, widget => { + for (const widget of this) { this.attachWidget(widget); - }); + } } /** diff --git a/packages/widgets/src/layout.ts b/packages/widgets/src/layout.ts index d4337f9c0..296456f87 100644 --- a/packages/widgets/src/layout.ts +++ b/packages/widgets/src/layout.ts @@ -8,8 +8,6 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { each, IIterable, IIterator } from '@lumino/algorithm'; - import { IDisposable } from '@lumino/disposable'; import { ElementExt } from '@lumino/domutils'; @@ -36,7 +34,7 @@ import { Widget } from './widget'; * widgets to the layout. A subclass should define that API in a way * which is meaningful for its intended use. */ -export abstract class Layout implements IIterable, IDisposable { +export abstract class Layout implements Iterable, IDisposable { /** * Construct a new layout. * @@ -151,7 +149,7 @@ export abstract class Layout implements IIterable, IDisposable { * #### Notes * This abstract method must be implemented by a subclass. */ - abstract iter(): IIterator; + abstract [Symbol.iterator](): IterableIterator; /** * Remove a widget from the layout. @@ -239,9 +237,9 @@ export abstract class Layout implements IIterable, IDisposable { * widget nodes to the parent widget's node. */ protected init(): void { - each(this, widget => { + for (const widget of this) { widget.parent = this.parent; - }); + } } /** @@ -258,9 +256,9 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onResize(msg: Widget.ResizeMessage): void { - each(this, widget => { + for (const widget of this) { MessageLoop.sendMessage(widget, Widget.ResizeMessage.UnknownSize); - }); + } } /** @@ -277,9 +275,9 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onUpdateRequest(msg: Message): void { - each(this, widget => { + for (const widget of this) { MessageLoop.sendMessage(widget, Widget.ResizeMessage.UnknownSize); - }); + } } /** @@ -293,9 +291,9 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onBeforeAttach(msg: Message): void { - each(this, widget => { + for (const widget of this) { MessageLoop.sendMessage(widget, msg); - }); + } } /** @@ -309,9 +307,9 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onAfterAttach(msg: Message): void { - each(this, widget => { + for (const widget of this) { MessageLoop.sendMessage(widget, msg); - }); + } } /** @@ -325,9 +323,9 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onBeforeDetach(msg: Message): void { - each(this, widget => { + for (const widget of this) { MessageLoop.sendMessage(widget, msg); - }); + } } /** @@ -341,9 +339,9 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onAfterDetach(msg: Message): void { - each(this, widget => { + for (const widget of this) { MessageLoop.sendMessage(widget, msg); - }); + } } /** @@ -357,11 +355,11 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onBeforeShow(msg: Message): void { - each(this, widget => { + for (const widget of this) { if (!widget.isHidden) { MessageLoop.sendMessage(widget, msg); } - }); + } } /** @@ -375,11 +373,11 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onAfterShow(msg: Message): void { - each(this, widget => { + for (const widget of this) { if (!widget.isHidden) { MessageLoop.sendMessage(widget, msg); } - }); + } } /** @@ -393,11 +391,11 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onBeforeHide(msg: Message): void { - each(this, widget => { + for (const widget of this) { if (!widget.isHidden) { MessageLoop.sendMessage(widget, msg); } - }); + } } /** @@ -411,11 +409,11 @@ export abstract class Layout implements IIterable, IDisposable { * This may be reimplemented by subclasses as needed. */ protected onAfterHide(msg: Message): void { - each(this, widget => { + for (const widget of this) { if (!widget.isHidden) { MessageLoop.sendMessage(widget, msg); } - }); + } } /** diff --git a/packages/widgets/src/panellayout.ts b/packages/widgets/src/panellayout.ts index 98197e5c7..cce7751af 100644 --- a/packages/widgets/src/panellayout.ts +++ b/packages/widgets/src/panellayout.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each, IIterator, iter } from '@lumino/algorithm'; +import { ArrayExt, each } from '@lumino/algorithm'; import { MessageLoop } from '@lumino/messaging'; @@ -53,8 +53,8 @@ export class PanelLayout extends Layout { * * @returns A new iterator over the widgets in the layout. */ - iter(): IIterator { - return iter(this._widgets); + [Symbol.iterator](): IterableIterator { + return this._widgets[Symbol.iterator](); } /** diff --git a/packages/widgets/src/singletonlayout.ts b/packages/widgets/src/singletonlayout.ts index 400364516..b84460dd6 100644 --- a/packages/widgets/src/singletonlayout.ts +++ b/packages/widgets/src/singletonlayout.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { each, empty, IIterator, once } from '@lumino/algorithm'; +import { empty, once } from '@lumino/algorithm'; import { MessageLoop } from '@lumino/messaging'; @@ -81,7 +81,7 @@ export class SingletonLayout extends Layout { * * @returns A new iterator over the widgets in the layout. */ - iter(): IIterator { + [Symbol.iterator](): IterableIterator { return this._widget ? once(this._widget) : empty(); } @@ -118,9 +118,9 @@ export class SingletonLayout extends Layout { */ protected init(): void { super.init(); - each(this, widget => { + for (const widget of this) { this.attachWidget(widget); - }); + } } /** diff --git a/packages/widgets/src/splitlayout.ts b/packages/widgets/src/splitlayout.ts index 6b71501ec..52702995d 100644 --- a/packages/widgets/src/splitlayout.ts +++ b/packages/widgets/src/splitlayout.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each } from '@lumino/algorithm'; +import { ArrayExt } from '@lumino/algorithm'; import { ElementExt } from '@lumino/domutils'; @@ -53,9 +53,9 @@ export class SplitLayout extends PanelLayout { */ dispose(): void { // Dispose of the layout items. - each(this._items, item => { + for (const item of this._items) { item.dispose(); - }); + } // Clear the layout state. this._box = null; diff --git a/packages/widgets/src/stackedlayout.ts b/packages/widgets/src/stackedlayout.ts index 36bdf535c..b4e952c2f 100644 --- a/packages/widgets/src/stackedlayout.ts +++ b/packages/widgets/src/stackedlayout.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each } from '@lumino/algorithm'; +import { ArrayExt } from '@lumino/algorithm'; import { ElementExt } from '@lumino/domutils'; @@ -69,9 +69,9 @@ export class StackedLayout extends PanelLayout { */ dispose(): void { // Dispose of the layout items. - each(this._items, item => { + for (const item of this._items) { item.dispose(); - }); + } // Clear the layout state. this._box = null; diff --git a/packages/widgets/src/tabbar.ts b/packages/widgets/src/tabbar.ts index 233aa3c91..0f23c23b0 100644 --- a/packages/widgets/src/tabbar.ts +++ b/packages/widgets/src/tabbar.ts @@ -7,7 +7,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { ArrayExt, each } from '@lumino/algorithm'; +import { ArrayExt } from '@lumino/algorithm'; import { IDisposable } from '@lumino/disposable'; @@ -2005,12 +2005,12 @@ namespace Private { tabs: HTMLCollection, orientation: TabBar.Orientation ): void { - each(tabs, tab => { + for (const tab of tabs) { if (orientation === 'horizontal') { (tab as HTMLElement).style.left = ''; } else { (tab as HTMLElement).style.top = ''; } - }); + } } } diff --git a/packages/widgets/src/widget.ts b/packages/widgets/src/widget.ts index 9f5ef8259..09a84cf55 100644 --- a/packages/widgets/src/widget.ts +++ b/packages/widgets/src/widget.ts @@ -8,7 +8,7 @@ | | The full license is in the file LICENSE, distributed with this software. |----------------------------------------------------------------------------*/ -import { empty, IIterator } from '@lumino/algorithm'; +import { empty } from '@lumino/algorithm'; import { IObservableDisposable } from '@lumino/disposable'; @@ -283,8 +283,8 @@ export class Widget implements IMessageHandler, IObservableDisposable { * * If a layout is not installed, the returned iterator will be empty. */ - children(): IIterator { - return this._layout ? this._layout.iter() : empty(); + children(): IterableIterator { + return this._layout ? this._layout[Symbol.iterator]() : empty(); } /** diff --git a/packages/widgets/tests/src/layout.spec.ts b/packages/widgets/tests/src/layout.spec.ts index 5da8173e6..2696cf7f8 100644 --- a/packages/widgets/tests/src/layout.spec.ts +++ b/packages/widgets/tests/src/layout.spec.ts @@ -9,7 +9,7 @@ |----------------------------------------------------------------------------*/ import { expect } from 'chai'; -import { ArrayExt, every, IIterator, iter, toArray } from '@lumino/algorithm'; +import { ArrayExt, every } from '@lumino/algorithm'; import { Message, MessageLoop } from '@lumino/messaging'; @@ -29,8 +29,8 @@ class LogLayout extends Layout { super.dispose(); } - iter(): IIterator { - return iter(this.widgets); + [Symbol.iterator](): IterableIterator { + return this.widgets[Symbol.iterator](); } removeWidget(widget: Widget): void { @@ -91,7 +91,7 @@ class LogLayout extends Layout { describe('@lumino/widgets', () => { describe('Layout', () => { - describe('#iter()', () => { + describe('[Symbol.iterator]()', () => { it('should create an iterator over the widgets in the layout', () => { let layout = new LogLayout(); expect(every(layout, child => child instanceof Widget)).to.equal(true); @@ -113,10 +113,9 @@ describe('@lumino/widgets', () => { let widget = new Widget(); let layout = new LogLayout(); widget.layout = layout; - let children = toArray(widget.children()); layout.dispose(); expect(layout.parent).to.equal(null); - expect(every(children, w => w.isDisposed)).to.equal(true); + expect(every(widget.children(), w => w.isDisposed)).to.equal(true); }); it('should be called automatically when the parent is disposed', () => { diff --git a/packages/widgets/tests/src/panellayout.spec.ts b/packages/widgets/tests/src/panellayout.spec.ts index cae746164..911b9b91a 100644 --- a/packages/widgets/tests/src/panellayout.spec.ts +++ b/packages/widgets/tests/src/panellayout.spec.ts @@ -87,7 +87,7 @@ describe('@lumino/widgets', () => { }); }); - describe('#iter()', () => { + describe('[Symbol.iterator]()', () => { it('should create an iterator over the widgets in the layout', () => { let layout = new PanelLayout(); let widgets = [new Widget(), new Widget()]; @@ -97,9 +97,10 @@ describe('@lumino/widgets', () => { each(widgets, w => { w.title.label = 'foo'; }); - let iter = layout.iter(); - expect(every(iter, w => w.title.label === 'foo')).to.equal(true); - expect(layout.iter()).to.not.equal(iter); + expect(every(layout, w => w.title.label === 'foo')).to.equal(true); + let it1 = layout[Symbol.iterator](), + it2 = layout[Symbol.iterator](); + expect(it1).to.not.equal(it2); }); }); diff --git a/packages/widgets/tests/src/widget.spec.ts b/packages/widgets/tests/src/widget.spec.ts index 82e6c750f..e2fe4cd8c 100644 --- a/packages/widgets/tests/src/widget.spec.ts +++ b/packages/widgets/tests/src/widget.spec.ts @@ -9,7 +9,7 @@ |----------------------------------------------------------------------------*/ import { expect } from 'chai'; -import { ArrayExt, each, IIterator, iter } from '@lumino/algorithm'; +import { ArrayExt, each } from '@lumino/algorithm'; import { Message, MessageLoop } from '@lumino/messaging'; @@ -93,8 +93,8 @@ class TestLayout extends Layout { super.dispose(); } - iter(): IIterator { - return iter(this._widgets); + [Symbol.iterator](): IterableIterator { + return this._widgets[Symbol.iterator](); } removeWidget(widget: Widget): void { @@ -401,7 +401,7 @@ describe('@lumino/widgets', () => { it('should return an empty iterator if there is no layout', () => { let widget = new Widget(); - expect(widget.children().next()).to.equal(undefined); + expect(widget.children().next().done).to.equal(true); }); }); diff --git a/packages/widgets/tsconfig.json b/packages/widgets/tsconfig.json index ea4f91321..5e66d6012 100644 --- a/packages/widgets/tsconfig.json +++ b/packages/widgets/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfigbase", "compilerOptions": { "declarationDir": "types", - "lib": ["DOM", "ES6"], + "lib": ["DOM", "DOM.Iterable", "ES6"], "outDir": "lib", "rootDir": "src" }, diff --git a/review/api/algorithm.api.md b/review/api/algorithm.api.md index 36c74bc7b..f03979016 100644 --- a/review/api/algorithm.api.md +++ b/review/api/algorithm.api.md @@ -48,214 +48,69 @@ export namespace ArrayExt { } // @public -export class ArrayIterator implements IIterator { - constructor(source: ArrayLike); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} - -// @public -export function chain(...objects: IterableOrArrayLike[]): IIterator; - -// @public -export class ChainIterator implements IIterator { - constructor(source: IIterator>); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} - -// @public -export function each(object: IterableOrArrayLike, fn: (value: T, index: number) => boolean | void): void; - -// @public -export function empty(): IIterator; +export function chain(...objects: Iterable[]): IterableIterator; // @public -export class EmptyIterator implements IIterator { - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} +export function each(object: Iterable, fn: (value: T, index: number) => boolean | void): void; // @public -export function enumerate(object: IterableOrArrayLike, start?: number): IIterator<[number, T]>; +export function empty(): IterableIterator; // @public -export class EnumerateIterator implements IIterator<[number, T]> { - constructor(source: IIterator, start: number); - clone(): IIterator<[number, T]>; - iter(): IIterator<[number, T]>; - next(): [number, T] | undefined; -} +export function enumerate(object: Iterable, start?: number): IterableIterator<[number, T]>; // @public -export function every(object: IterableOrArrayLike, fn: (value: T, index: number) => boolean): boolean; +export function every(object: Iterable, fn: (value: T, index: number) => boolean): boolean; // @public -export function filter(object: IterableOrArrayLike, fn: (value: T, index: number) => boolean): IIterator; +export function filter(object: Iterable, fn: (value: T, index: number) => boolean): IterableIterator; // @public -export class FilterIterator implements IIterator { - constructor(source: IIterator, fn: (value: T, index: number) => boolean); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} +export function find(object: Iterable, fn: (value: T, index: number) => boolean): T | undefined; // @public -export function find(object: IterableOrArrayLike, fn: (value: T, index: number) => boolean): T | undefined; - -// @public -export function findIndex(object: IterableOrArrayLike, fn: (value: T, index: number) => boolean): number; - -// @public -export class FnIterator implements IIterator { - constructor(fn: () => T | undefined); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} - -// @public -export interface IIterable { - iter(): IIterator; -} - -// @public -export interface IIterator extends IIterable { - clone(): IIterator; - next(): T | undefined; -} +export function findIndex(object: Iterable, fn: (value: T, index: number) => boolean): number; // @public export interface IRetroable { - retro(): IIterator; -} - -// @public -export class ItemIterator implements IIterator<[string, T]> { - constructor(source: { - readonly [key: string]: T; - }, keys?: string[]); - clone(): IIterator<[string, T]>; - iter(): IIterator<[string, T]>; - next(): [string, T] | undefined; + retro(): IterableIterator; } // @public -export function iter(object: IterableOrArrayLike): IIterator; +export function map(object: Iterable, fn: (value: T, index: number) => U): IterableIterator; // @public -export type IterableOrArrayLike = IIterable | ArrayLike; +export function max(object: Iterable, fn: (first: T, second: T) => number): T | undefined; // @public -export function iterFn(fn: () => T | undefined): IIterator; +export function min(object: Iterable, fn: (first: T, second: T) => number): T | undefined; // @public -export function iterItems(object: { - readonly [key: string]: T; -}): IIterator<[string, T]>; +export function minmax(object: Iterable, fn: (first: T, second: T) => number): [T, T] | undefined; // @public -export function iterKeys(object: { - readonly [key: string]: T; -}): IIterator; +export function once(value: T): IterableIterator; // @public -export function iterValues(object: { - readonly [key: string]: T; -}): IIterator; - -// @public -export class KeyIterator implements IIterator { - constructor(source: { - readonly [key: string]: any; - }, keys?: string[]); - clone(): IIterator; - iter(): IIterator; - next(): string | undefined; -} - -// @public -export function map(object: IterableOrArrayLike, fn: (value: T, index: number) => U): IIterator; - -// @public -export class MapIterator implements IIterator { - constructor(source: IIterator, fn: (value: T, index: number) => U); - clone(): IIterator; - iter(): IIterator; - next(): U | undefined; -} +export function range(start: number, stop?: number, step?: number): IterableIterator; // @public -export function max(object: IterableOrArrayLike, fn: (first: T, second: T) => number): T | undefined; - -// @public -export function min(object: IterableOrArrayLike, fn: (first: T, second: T) => number): T | undefined; - -// @public -export function minmax(object: IterableOrArrayLike, fn: (first: T, second: T) => number): [T, T] | undefined; - -// @public -export function once(value: T): IIterator; - -// @public -export function range(start: number, stop?: number, step?: number): IIterator; - -// @public -export class RangeIterator implements IIterator { - constructor(start: number, stop: number, step: number); - clone(): IIterator; - iter(): IIterator; - next(): number | undefined; -} - -// @public -export function reduce(object: IterableOrArrayLike, fn: (accumulator: T, value: T, index: number) => T): T; +export function reduce(object: Iterable, fn: (accumulator: T, value: T, index: number) => T): T; // @public (undocumented) -export function reduce(object: IterableOrArrayLike, fn: (accumulator: U, value: T, index: number) => U, initial: U): U; - -// @public -export function repeat(value: T, count: number): IIterator; - -// @public -export class RepeatIterator implements IIterator { - constructor(value: T, count: number); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} +export function reduce(object: Iterable, fn: (accumulator: U, value: T, index: number) => U, initial: U): U; // @public -export function retro(object: RetroableOrArrayLike): IIterator; +export function repeat(value: T, count: number): IterableIterator; // @public -export type RetroableOrArrayLike = IRetroable | ArrayLike; +export function retro(object: IRetroable | ArrayLike): IterableIterator; // @public -export class RetroArrayIterator implements IIterator { - constructor(source: ArrayLike); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} +export function some(object: Iterable, fn: (value: T, index: number) => boolean): boolean; // @public -export function some(object: IterableOrArrayLike, fn: (value: T, index: number) => boolean): boolean; - -// @public -export function stride(object: IterableOrArrayLike, step: number): IIterator; - -// @public -export class StrideIterator implements IIterator { - constructor(source: IIterator, step: number); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} +export function stride(object: Iterable, step: number): IterableIterator; // @public export namespace StringExt { @@ -271,47 +126,21 @@ export namespace StringExt { } // @public -export function take(object: IterableOrArrayLike, count: number): IIterator; +export function take(object: Iterable, count: number): IterableIterator; -// @public -export class TakeIterator implements IIterator { - constructor(source: IIterator, count: number); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} +// @public @deprecated +export function toArray(object: Iterable): T[]; // @public -export function toArray(object: IterableOrArrayLike): T[]; - -// @public -export function toObject(object: IterableOrArrayLike<[string, T]>): { +export function toObject(object: Iterable<[string, T]>): { [key: string]: T; }; // @public -export function topologicSort(edges: IterableOrArrayLike<[T, T]>): T[]; - -// @public -export class ValueIterator implements IIterator { - constructor(source: { - readonly [key: string]: T; - }, keys?: string[]); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; -} - -// @public -export function zip(...objects: IterableOrArrayLike[]): IIterator; +export function topologicSort(edges: Iterable<[T, T]>): T[]; // @public -export class ZipIterator implements IIterator { - constructor(source: IIterator[]); - clone(): IIterator; - iter(): IIterator; - next(): T[] | undefined; -} +export function zip(...objects: Iterable[]): IterableIterator; // (No @packageDocumentation comment for this package) diff --git a/review/api/collections.api.md b/review/api/collections.api.md index e6c4e5565..e96b4f08e 100644 --- a/review/api/collections.api.md +++ b/review/api/collections.api.md @@ -4,34 +4,31 @@ ```ts -import { IIterable } from '@lumino/algorithm'; -import { IIterator } from '@lumino/algorithm'; import { IRetroable } from '@lumino/algorithm'; -import { IterableOrArrayLike } from '@lumino/algorithm'; // @public -export class LinkedList implements IIterable, IRetroable { +export class LinkedList implements Iterable, IRetroable { + [Symbol.iterator](): IterableIterator; addFirst(value: T): LinkedList.INode; addLast(value: T): LinkedList.INode; - assign(values: IterableOrArrayLike): void; + assign(values: Iterable): void; clear(): void; get first(): T | undefined; get firstNode(): LinkedList.INode | null; insertAfter(value: T, ref: LinkedList.INode | null): LinkedList.INode; insertBefore(value: T, ref: LinkedList.INode | null): LinkedList.INode; get isEmpty(): boolean; - iter(): IIterator; get last(): T | undefined; get lastNode(): LinkedList.INode | null; get length(): number; - nodes(): IIterator>; + nodes(): IterableIterator>; pop(): T | undefined; push(value: T): void; removeFirst(): T | undefined; removeLast(): T | undefined; removeNode(node: LinkedList.INode): void; - retro(): IIterator; - retroNodes(): IIterator>; + retro(): IterableIterator; + retroNodes(): IterableIterator>; shift(value: T): void; get size(): number; unshift(): T | undefined; @@ -39,37 +36,13 @@ export class LinkedList implements IIterable, IRetroable { // @public export namespace LinkedList { - export class ForwardNodeIterator implements IIterator> { - constructor(node: INode | null); - clone(): IIterator>; - iter(): IIterator>; - next(): INode | undefined; - } - export class ForwardValueIterator implements IIterator { - constructor(node: INode | null); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; - } - export function from(values: IterableOrArrayLike): LinkedList; + export function from(values: Iterable): LinkedList; export interface INode { readonly list: LinkedList | null; readonly next: INode | null; readonly prev: INode | null; readonly value: T; } - export class RetroNodeIterator implements IIterator> { - constructor(node: INode | null); - clone(): IIterator>; - iter(): IIterator>; - next(): INode | undefined; - } - export class RetroValueIterator implements IIterator { - constructor(node: INode | null); - clone(): IIterator; - iter(): IIterator; - next(): T | undefined; - } } // (No @packageDocumentation comment for this package) diff --git a/review/api/datagrid.api.md b/review/api/datagrid.api.md index 8e02f9f68..9197a5041 100644 --- a/review/api/datagrid.api.md +++ b/review/api/datagrid.api.md @@ -5,7 +5,6 @@ ```ts import { IDisposable } from '@lumino/disposable'; -import { IIterator } from '@lumino/algorithm'; import { IMessageHandler } from '@lumino/messaging'; import { ISignal } from '@lumino/signaling'; import { Message } from '@lumino/messaging'; @@ -58,7 +57,7 @@ export class BasicSelectionModel extends SelectionModel { moveCursorWithinSelections(direction: SelectionModel.CursorMoveDirection): void; protected onDataModelChanged(sender: DataModel, args: DataModel.ChangedArgs): void; select(args: SelectionModel.SelectArgs): void; - selections(): IIterator; + selections(): IterableIterator; } // @public @@ -851,7 +850,7 @@ export abstract class SelectionModel { abstract select(args: SelectionModel.SelectArgs): void; get selectionMode(): SelectionModel.SelectionMode; set selectionMode(value: SelectionModel.SelectionMode); - abstract selections(): IIterator; + abstract selections(): IterableIterator; } // @public diff --git a/review/api/disposable.api.md b/review/api/disposable.api.md index 5a3163362..dca0605b5 100644 --- a/review/api/disposable.api.md +++ b/review/api/disposable.api.md @@ -5,7 +5,6 @@ ```ts import { ISignal } from '@lumino/signaling'; -import { IterableOrArrayLike } from '@lumino/algorithm'; // @public export class DisposableDelegate implements IDisposable { @@ -26,7 +25,7 @@ export class DisposableSet implements IDisposable { // @public export namespace DisposableSet { - export function from(items: IterableOrArrayLike): DisposableSet; + export function from(items: Iterable): DisposableSet; } // @public @@ -54,7 +53,7 @@ export class ObservableDisposableSet extends DisposableSet implements IObservabl // @public export namespace ObservableDisposableSet { - export function from(items: IterableOrArrayLike): ObservableDisposableSet; + export function from(items: Iterable): ObservableDisposableSet; } // (No @packageDocumentation comment for this package) diff --git a/review/api/widgets.api.md b/review/api/widgets.api.md index df1bc06e5..c0c6a11a8 100644 --- a/review/api/widgets.api.md +++ b/review/api/widgets.api.md @@ -11,8 +11,6 @@ import { ElementDataset } from '@lumino/virtualdom'; import { ElementInlineStyle } from '@lumino/virtualdom'; import { h } from '@lumino/virtualdom'; import { IDisposable } from '@lumino/disposable'; -import { IIterable } from '@lumino/algorithm'; -import { IIterator } from '@lumino/algorithm'; import { IMessageHandler } from '@lumino/messaging'; import { IObservableDisposable } from '@lumino/disposable'; import { ISignal } from '@lumino/signaling'; @@ -281,18 +279,18 @@ export namespace ContextMenu { // @public export class DockLayout extends Layout { + [Symbol.iterator](): IterableIterator; constructor(options: DockLayout.IOptions); addWidget(widget: Widget, options?: DockLayout.IAddOptions): void; protected attachWidget(widget: Widget): void; protected detachWidget(widget: Widget): void; dispose(): void; - handles(): IIterator; + handles(): IterableIterator; get hiddenMode(): Widget.HiddenMode; set hiddenMode(v: Widget.HiddenMode); hitTestTabAreas(clientX: number, clientY: number): DockLayout.ITabAreaGeometry | null; protected init(): void; get isEmpty(): boolean; - iter(): IIterator; moveHandle(handle: HTMLDivElement, offsetX: number, offsetY: number): void; protected onBeforeAttach(msg: Message): void; protected onBeforeShow(msg: Message): void; @@ -305,11 +303,11 @@ export class DockLayout extends Layout { readonly renderer: DockLayout.IRenderer; restoreLayout(config: DockLayout.ILayoutConfig): void; saveLayout(): DockLayout.ILayoutConfig; - selectedWidgets(): IIterator; + selectedWidgets(): IterableIterator; get spacing(): number; set spacing(value: number); - tabBars(): IIterator>; - widgets(): IIterator; + tabBars(): IterableIterator>; + widgets(): IterableIterator; } // @public @@ -419,7 +417,7 @@ export class DockPanel extends Widget { addWidget(widget: Widget, options?: DockPanel.IAddOptions): void; dispose(): void; handleEvent(event: Event): void; - handles(): IIterator; + handles(): IterableIterator; get hiddenMode(): Widget.HiddenMode; set hiddenMode(v: Widget.HiddenMode); get isEmpty(): boolean; @@ -435,16 +433,16 @@ export class DockPanel extends Widget { get renderer(): DockPanel.IRenderer; restoreLayout(config: DockPanel.ILayoutConfig): void; saveLayout(): DockPanel.ILayoutConfig; - selectedWidgets(): IIterator; + selectedWidgets(): IterableIterator; selectWidget(widget: Widget): void; get spacing(): number; set spacing(value: number); - tabBars(): IIterator>; + tabBars(): IterableIterator>; get tabsConstrained(): boolean; set tabsConstrained(value: boolean); get tabsMovable(): boolean; set tabsMovable(value: boolean); - widgets(): IIterator; + widgets(): IterableIterator; } // @public @@ -534,6 +532,7 @@ export namespace FocusTracker { // @public export class GridLayout extends Layout { + [Symbol.iterator](): IterableIterator; constructor(options?: GridLayout.IOptions); addWidget(widget: Widget): void; protected attachWidget(widget: Widget): void; @@ -545,7 +544,6 @@ export class GridLayout extends Layout { protected detachWidget(widget: Widget): void; dispose(): void; protected init(): void; - iter(): IIterator; protected onBeforeAttach(msg: Message): void; protected onBeforeShow(msg: Message): void; protected onChildHidden(msg: Widget.ChildMessage): void; @@ -582,14 +580,14 @@ export namespace GridLayout { } // @public -export abstract class Layout implements IIterable, IDisposable { +export abstract class Layout implements Iterable, IDisposable { + abstract [Symbol.iterator](): IterableIterator; constructor(options?: Layout.IOptions); dispose(): void; get fitPolicy(): Layout.FitPolicy; set fitPolicy(value: Layout.FitPolicy); protected init(): void; get isDisposed(): boolean; - abstract iter(): IIterator; protected onAfterAttach(msg: Message): void; protected onAfterDetach(msg: Message): void; protected onAfterHide(msg: Message): void; @@ -812,13 +810,13 @@ export namespace Panel { // @public export class PanelLayout extends Layout { + [Symbol.iterator](): IterableIterator; addWidget(widget: Widget): void; protected attachWidget(index: number, widget: Widget): void; protected detachWidget(index: number, widget: Widget): void; dispose(): void; protected init(): void; insertWidget(index: number, widget: Widget): void; - iter(): IIterator; protected moveWidget(fromIndex: number, toIndex: number, widget: Widget): void; removeWidget(widget: Widget): void; removeWidgetAt(index: number): void; @@ -862,11 +860,11 @@ export namespace ScrollBar { // @public export class SingletonLayout extends Layout { + [Symbol.iterator](): IterableIterator; protected attachWidget(widget: Widget): void; protected detachWidget(widget: Widget): void; dispose(): void; protected init(): void; - iter(): IIterator; removeWidget(widget: Widget): void; get widget(): Widget | null; set widget(widget: Widget | null); @@ -1256,7 +1254,7 @@ export class Widget implements IMessageHandler, IObservableDisposable { constructor(options?: Widget.IOptions); activate(): void; addClass(name: string): void; - children(): IIterator; + children(): IterableIterator; clearFlag(flag: Widget.Flag): void; close(): void; contains(widget: Widget): boolean;