mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2024-11-20 03:25:52 +01:00
JoinedMap to typescript
This commit is contained in:
parent
f1751a24b0
commit
3ba2bab59f
34
.eslintrc.js
34
.eslintrc.js
@ -1,25 +1,25 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
extends: [
|
||||
// "plugin:@typescript-eslint/recommended",
|
||||
// "plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
"sourceType": "module"
|
||||
},
|
||||
plugins: [
|
||||
'@typescript-eslint',
|
||||
],
|
||||
rules: {
|
||||
"@typescript-eslint/no-floating-promises": 2,
|
||||
"@typescript-eslint/no-misused-promises": 2,
|
||||
"semi": ["error", "always"]
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"no-empty": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-unused-vars": "warn"
|
||||
},
|
||||
"globals": {
|
||||
"DEFINE_VERSION": "readonly",
|
||||
"DEFINE_GLOBAL_HASH": "readonly",
|
||||
// only available in sw.js
|
||||
"DEFINE_UNHASHED_PRECACHED_ASSETS": "readonly",
|
||||
"DEFINE_HASHED_PRECACHED_ASSETS": "readonly",
|
||||
"DEFINE_HASHED_CACHED_ON_REQUEST_ASSETS": "readonly"
|
||||
}
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ export interface IMapObserver<K, V> {
|
||||
}
|
||||
|
||||
export type BaseObservableMapConfig<K, V> = {
|
||||
join(_this: BaseObservableMap<K, V>, ...otherMaps: Array<BaseObservableMap<K, V>>): JoinedMap;
|
||||
join(_this: BaseObservableMap<K, V>, ...otherMaps: Array<BaseObservableMap<K, V>>): JoinedMap<K, V>;
|
||||
mapValues(_this: BaseObservableMap<K, V>, mapper: any, updater?: (params: any) => void): MappedMap;
|
||||
sortValues(_this: BaseObservableMap<K, V>, comparator?: (a: any, b: any) => number): SortedMapList;
|
||||
filterValues(_this: BaseObservableMap<K, V>, filter: (v: V, k: K) => boolean): FilteredMap<K, V>;
|
||||
@ -66,7 +66,7 @@ export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserve
|
||||
// here. See the neighboring `ObservableMap.ts` for an example of how
|
||||
// to easily use the default implementation in a class that extends
|
||||
// this one (which is most likely what you want to do).
|
||||
abstract join(...otherMaps: Array<typeof this>): JoinedMap;
|
||||
abstract join(...otherMaps: Array<typeof this>): JoinedMap<K, V>;
|
||||
abstract mapValues(mapper: any, updater?: (params: any) => void): MappedMap;
|
||||
abstract sortValues(comparator?: (a: any, b: any) => number): SortedMapList;
|
||||
abstract filterValues(filter: (v: V, k: K) => boolean): FilteredMap<K, V>;
|
||||
|
@ -35,7 +35,7 @@ export class FilteredMap<K, V> extends BaseObservableMap<K, V> {
|
||||
this._config = config<K, V>();
|
||||
}
|
||||
|
||||
join(...otherMaps: Array<typeof this>): JoinedMap {
|
||||
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
|
||||
return this._config.join(this, ...otherMaps);
|
||||
}
|
||||
|
||||
|
@ -14,16 +14,41 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {BaseObservableMap} from "./BaseObservableMap";
|
||||
import {BaseObservableMap, BaseObservableMapConfig} from "./BaseObservableMap";
|
||||
import {config} from "./config";
|
||||
import {FilteredMap} from "./FilteredMap.js";
|
||||
import {MappedMap} from "./MappedMap.js";
|
||||
import {SortedMapList} from "../list/SortedMapList.js";
|
||||
|
||||
export class JoinedMap extends BaseObservableMap {
|
||||
constructor(sources) {
|
||||
|
||||
export class JoinedMap<K, V> extends BaseObservableMap<K, V> {
|
||||
protected _sources: BaseObservableMap<K, V>[];
|
||||
private _config: BaseObservableMapConfig<K, V>
|
||||
private _subscriptions?: SourceSubscriptionHandler[];
|
||||
|
||||
constructor(sources: BaseObservableMap<K, V>[]) {
|
||||
super();
|
||||
this._sources = sources;
|
||||
this._subscriptions = null;
|
||||
this._config = config<K, V>();
|
||||
}
|
||||
|
||||
onAdd(source, key, value) {
|
||||
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
|
||||
return this._config.join(this, ...otherMaps);
|
||||
}
|
||||
|
||||
mapValues(mapper: any, updater?: (params: any) => void): MappedMap{
|
||||
return this._config.mapValues(this, mapper, updater);
|
||||
}
|
||||
|
||||
sortValues(comparator?: (a: any, b: any) => number): SortedMapList {
|
||||
return this._config.sortValues(this, comparator);
|
||||
}
|
||||
|
||||
filterValues(filter: (v: V, k: K) => boolean): FilteredMap<K, V> {
|
||||
return this._config.filterValues(this, filter);
|
||||
}
|
||||
|
||||
onAdd(source: BaseObservableMap<K, V>, key: K, value: V) {
|
||||
if (!this._isKeyAtSourceOccluded(source, key)) {
|
||||
const occludingValue = this._getValueFromOccludedSources(source, key);
|
||||
if (occludingValue !== undefined) {
|
||||
@ -35,7 +60,7 @@ export class JoinedMap extends BaseObservableMap {
|
||||
}
|
||||
}
|
||||
|
||||
onRemove(source, key, value) {
|
||||
onRemove(source: BaseObservableMap<K, V>, key: K, value: V) {
|
||||
if (!this._isKeyAtSourceOccluded(source, key)) {
|
||||
this.emitRemove(key, value);
|
||||
const occludedValue = this._getValueFromOccludedSources(source, key);
|
||||
@ -47,7 +72,7 @@ export class JoinedMap extends BaseObservableMap {
|
||||
}
|
||||
}
|
||||
|
||||
onUpdate(source, key, value, params) {
|
||||
onUpdate(source: BaseObservableMap<K, V>, key: K, value: V, params: any) {
|
||||
// if an update is emitted while calling source.subscribe() from onSubscribeFirst, ignore it
|
||||
if (!this._subscriptions) {
|
||||
return;
|
||||
@ -66,7 +91,7 @@ export class JoinedMap extends BaseObservableMap {
|
||||
super.onSubscribeFirst();
|
||||
}
|
||||
|
||||
_isKeyAtSourceOccluded(source, key) {
|
||||
_isKeyAtSourceOccluded(source: BaseObservableMap<K, V>, key: K) {
|
||||
// sources that come first in the sources array can
|
||||
// hide the keys in later sources, to prevent events
|
||||
// being emitted for the same key and different values,
|
||||
@ -81,7 +106,7 @@ export class JoinedMap extends BaseObservableMap {
|
||||
}
|
||||
|
||||
// get the value that the given source and key occlude, if any
|
||||
_getValueFromOccludedSources(source, key) {
|
||||
_getValueFromOccludedSources(source: BaseObservableMap<K, V>, key: K) {
|
||||
// sources that come first in the sources array can
|
||||
// hide the keys in later sources, to prevent events
|
||||
// being emitted for the same key and different values,
|
||||
@ -99,51 +124,55 @@ export class JoinedMap extends BaseObservableMap {
|
||||
|
||||
onUnsubscribeLast() {
|
||||
super.onUnsubscribeLast();
|
||||
for (const s of this._subscriptions) {
|
||||
s.dispose();
|
||||
if (this._subscriptions) {
|
||||
for (const s of this._subscriptions) {
|
||||
s.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return new JoinedIterator(this._sources);
|
||||
return new JoinedIterator<K, V>(this._sources);
|
||||
}
|
||||
|
||||
get size() {
|
||||
return this._sources.reduce((sum, s) => sum + s.size, 0);
|
||||
}
|
||||
|
||||
get(key) {
|
||||
get(key: K): V | undefined{
|
||||
for (const s of this._sources) {
|
||||
const value = s.get(key);
|
||||
if (value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
class JoinedIterator {
|
||||
constructor(sources) {
|
||||
class JoinedIterator<K, V> implements Iterator<[K, V]> {
|
||||
private _sources: {[Symbol.iterator](): Iterator<[K, V]>}[];
|
||||
private _sourceIndex = -1;
|
||||
private _encounteredKeys = new Set();
|
||||
private _currentIterator?: Iterator<[K, V]>
|
||||
|
||||
constructor(sources: {[Symbol.iterator](): Iterator<[K, V]>}[]) {
|
||||
this._sources = sources;
|
||||
this._sourceIndex = -1;
|
||||
this._currentIterator = null;
|
||||
this._encounteredKeys = new Set();
|
||||
}
|
||||
|
||||
next() {
|
||||
let result;
|
||||
next(): IteratorYieldResult<[K, V]> | IteratorReturnResult<null> {
|
||||
let result: IteratorYieldResult<[K, V]> | undefined = undefined;
|
||||
while (!result) {
|
||||
if (!this._currentIterator) {
|
||||
this._sourceIndex += 1;
|
||||
if (this._sources.length <= this._sourceIndex) {
|
||||
return {done: true};
|
||||
return {done: true, value: null};
|
||||
}
|
||||
this._currentIterator = this._sources[this._sourceIndex][Symbol.iterator]();
|
||||
}
|
||||
const sourceResult = this._currentIterator.next();
|
||||
if (sourceResult.done) {
|
||||
this._currentIterator = null;
|
||||
const sourceResult = this._currentIterator?.next();
|
||||
if (!sourceResult || sourceResult.done) {
|
||||
this._currentIterator = undefined;
|
||||
continue;
|
||||
} else {
|
||||
const key = sourceResult.value[0];
|
||||
@ -191,26 +220,29 @@ class SourceSubscriptionHandler {
|
||||
}
|
||||
|
||||
|
||||
import {ObservableMap} from "../";
|
||||
import {ObservableMap} from "..";
|
||||
|
||||
export function tests() {
|
||||
|
||||
function observeMap(map) {
|
||||
const events = [];
|
||||
function observeMap(map: JoinedMap<any, any>) {
|
||||
const events: { type: string, key: any, value: any, params?: any }[] = [];
|
||||
map.subscribe({
|
||||
onAdd(key, value) { events.push({type: "add", key, value}); },
|
||||
onRemove(key, value) { events.push({type: "remove", key, value}); },
|
||||
onUpdate(key, value, params) { events.push({type: "update", key, value, params}); }
|
||||
onAdd(key, value) { events.push({ type: "add", key, value }); },
|
||||
onRemove(key, value) { events.push({ type: "remove", key, value }); },
|
||||
onUpdate(key, value, params) { events.push({ type: "update", key, value, params }); },
|
||||
onReset: function (): void {
|
||||
return;
|
||||
}
|
||||
});
|
||||
return events;
|
||||
}
|
||||
|
||||
return {
|
||||
"joined iterator": assert => {
|
||||
const firstKV = ["a", 1];
|
||||
const secondKV = ["b", 2];
|
||||
const thirdKV = ["c", 3];
|
||||
const it = new JoinedIterator([[firstKV, secondKV], [thirdKV]]);
|
||||
const firstKV: [string, number] = ["a", 1];
|
||||
const secondKV: [string, number] = ["b", 2];
|
||||
const thirdKV: [string, number] = ["c", 3];
|
||||
const it = new JoinedIterator<string, number>([[firstKV, secondKV], [thirdKV]]);
|
||||
assert.equal(it.next().value, firstKV);
|
||||
assert.equal(it.next().value, secondKV);
|
||||
assert.equal(it.next().value, thirdKV);
|
@ -32,7 +32,7 @@ export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
|
||||
this._values = new Map(initialValues);
|
||||
}
|
||||
|
||||
join(...otherMaps: Array<typeof this>): JoinedMap {
|
||||
join(...otherMaps: Array<typeof this>): JoinedMap<K, V> {
|
||||
return this._config.join(this, ...otherMaps);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ import {SortedMapList} from "../list/SortedMapList.js";
|
||||
// (i.e. `new JoinedMap()`) and BaseObservableMap (as they extend it).
|
||||
export function config<K, V>(): BaseObservableMapConfig<K, V> {
|
||||
return {
|
||||
join: (_this: BaseObservableMap<K, V>, ...otherMaps: Array<BaseObservableMap<K, V>>): JoinedMap => {
|
||||
join: (_this: BaseObservableMap<K, V>, ...otherMaps: Array<BaseObservableMap<K, V>>): JoinedMap<K, V> => {
|
||||
return new JoinedMap([_this].concat(otherMaps));
|
||||
},
|
||||
mapValues: (_this: BaseObservableMap<K, V>, mapper: any, updater?: (params: any) => void): MappedMap => {
|
||||
@ -40,4 +40,4 @@ export function config<K, V>(): BaseObservableMapConfig<K, V> {
|
||||
return new FilteredMap(_this, filter);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user