mirror of
https://github.com/vector-im/hydrogen-web.git
synced 2025-01-10 12:16:41 +01:00
refactors ObservableMap
This commit is contained in:
parent
c898bcb46a
commit
b33db1df36
34
.eslintrc.js
34
.eslintrc.js
@ -1,25 +1,25 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
"env": {
|
root: true,
|
||||||
|
env: {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"es6": true
|
"es6": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
extends: [
|
||||||
"parserOptions": {
|
// "plugin:@typescript-eslint/recommended",
|
||||||
|
// "plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
"ecmaVersion": 2020,
|
"ecmaVersion": 2020,
|
||||||
"sourceType": "module"
|
"sourceType": "module",
|
||||||
|
"project": "./tsconfig.json"
|
||||||
},
|
},
|
||||||
"rules": {
|
plugins: [
|
||||||
"no-console": "off",
|
'@typescript-eslint',
|
||||||
"no-empty": "off",
|
],
|
||||||
"no-prototype-builtins": "off",
|
rules: {
|
||||||
"no-unused-vars": "warn"
|
"@typescript-eslint/no-floating-promises": 2,
|
||||||
},
|
"@typescript-eslint/no-misused-promises": 2,
|
||||||
"globals": {
|
"semi": ["error", "always"]
|
||||||
"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"
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {SortedArray} from "../observable/index.js";
|
import {SortedArray} from "../observable";
|
||||||
import {ViewModel} from "./ViewModel";
|
import {ViewModel} from "./ViewModel";
|
||||||
import {avatarInitials, getIdentifierColorNumber} from "./avatar";
|
import {avatarInitials, getIdentifierColorNumber} from "./avatar";
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
import {ObservableMap} from "../../../../observable/map/ObservableMap";
|
import {ObservableMap} from "../../../../observable";
|
||||||
|
|
||||||
export class ReactionsViewModel {
|
export class ReactionsViewModel {
|
||||||
constructor(parentTile) {
|
constructor(parentTile) {
|
||||||
|
@ -21,7 +21,7 @@ import {RoomStatus} from "./room/common";
|
|||||||
import {RoomBeingCreated} from "./room/RoomBeingCreated";
|
import {RoomBeingCreated} from "./room/RoomBeingCreated";
|
||||||
import {Invite} from "./room/Invite.js";
|
import {Invite} from "./room/Invite.js";
|
||||||
import {Pusher} from "./push/Pusher";
|
import {Pusher} from "./push/Pusher";
|
||||||
import { ObservableMap } from "../observable/index.js";
|
import {ObservableMap} from "../observable";
|
||||||
import {User} from "./User.js";
|
import {User} from "./User.js";
|
||||||
import {DeviceMessageHandler} from "./DeviceMessageHandler.js";
|
import {DeviceMessageHandler} from "./DeviceMessageHandler.js";
|
||||||
import {Account as E2EEAccount} from "./e2ee/Account.js";
|
import {Account as E2EEAccount} from "./e2ee/Account.js";
|
||||||
@ -192,7 +192,7 @@ export class Session {
|
|||||||
/**
|
/**
|
||||||
* Enable secret storage by providing the secret storage credential.
|
* Enable secret storage by providing the secret storage credential.
|
||||||
* This will also see if there is a megolm key backup and try to enable that if so.
|
* This will also see if there is a megolm key backup and try to enable that if so.
|
||||||
*
|
*
|
||||||
* @param {string} type either "passphrase" or "recoverykey"
|
* @param {string} type either "passphrase" or "recoverykey"
|
||||||
* @param {string} credential either the passphrase or the recovery key, depending on the type
|
* @param {string} credential either the passphrase or the recovery key, depending on the type
|
||||||
* @return {Promise} resolves or rejects after having tried to enable secret storage
|
* @return {Promise} resolves or rejects after having tried to enable secret storage
|
||||||
@ -663,7 +663,7 @@ export class Session {
|
|||||||
if (this._e2eeAccount && deviceOneTimeKeysCount) {
|
if (this._e2eeAccount && deviceOneTimeKeysCount) {
|
||||||
changes.e2eeAccountChanges = this._e2eeAccount.writeSync(deviceOneTimeKeysCount, txn, log);
|
changes.e2eeAccountChanges = this._e2eeAccount.writeSync(deviceOneTimeKeysCount, txn, log);
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceLists = syncResponse.device_lists;
|
const deviceLists = syncResponse.device_lists;
|
||||||
if (this._deviceTracker && Array.isArray(deviceLists?.changed) && deviceLists.changed.length) {
|
if (this._deviceTracker && Array.isArray(deviceLists?.changed) && deviceLists.changed.length) {
|
||||||
await log.wrap("deviceLists", log => this._deviceTracker.writeDeviceChanges(deviceLists.changed, txn, log));
|
await log.wrap("deviceLists", log => this._deviceTracker.writeDeviceChanges(deviceLists.changed, txn, log));
|
||||||
@ -908,7 +908,7 @@ export class Session {
|
|||||||
Creates an empty (summary isn't loaded) the archived room if it isn't
|
Creates an empty (summary isn't loaded) the archived room if it isn't
|
||||||
loaded already, assuming sync will either remove it (when rejoining) or
|
loaded already, assuming sync will either remove it (when rejoining) or
|
||||||
write a full summary adopting it from the joined room when leaving
|
write a full summary adopting it from the joined room when leaving
|
||||||
|
|
||||||
@internal
|
@internal
|
||||||
*/
|
*/
|
||||||
createOrGetArchivedRoomForSync(roomId) {
|
createOrGetArchivedRoomForSync(roomId) {
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ObservableMap} from "../../../observable/map/ObservableMap";
|
import {ObservableMap} from "../../../observable";
|
||||||
import {RetainedValue} from "../../../utils/RetainedValue";
|
import {RetainedValue} from "../../../utils/RetainedValue";
|
||||||
|
|
||||||
export class MemberList extends RetainedValue {
|
export class MemberList extends RetainedValue {
|
||||||
|
@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {SortedArray, AsyncMappedList, ConcatList, ObservableArray} from "../../../observable/index.js";
|
import {SortedArray, AsyncMappedList, ConcatList, ObservableArray} from "../../../observable";
|
||||||
import {Disposables} from "../../../utils/Disposables";
|
import {Disposables} from "../../../utils/Disposables";
|
||||||
import {Direction} from "./Direction";
|
import {Direction} from "./Direction";
|
||||||
import {TimelineReader} from "./persistence/TimelineReader.js";
|
import {TimelineReader} from "./persistence/TimelineReader.js";
|
||||||
@ -45,7 +45,7 @@ export class Timeline {
|
|||||||
});
|
});
|
||||||
this._readerRequest = null;
|
this._readerRequest = null;
|
||||||
this._allEntries = null;
|
this._allEntries = null;
|
||||||
/** Stores event entries that we had to fetch from hs/storage for reply previews (because they were not in timeline) */
|
/** Stores event entries that we had to fetch from hs/storage for reply previews (because they were not in timeline) */
|
||||||
this._contextEntriesNotInTimeline = new Map();
|
this._contextEntriesNotInTimeline = new Map();
|
||||||
/** Only used to decrypt non-persisted context entries fetched from the homeserver */
|
/** Only used to decrypt non-persisted context entries fetched from the homeserver */
|
||||||
this._decryptEntries = null;
|
this._decryptEntries = null;
|
||||||
@ -189,7 +189,7 @@ export class Timeline {
|
|||||||
// before it has any subscriptions, we bail out if this isn't
|
// before it has any subscriptions, we bail out if this isn't
|
||||||
// the case yet. This can happen when sync adds or replaces entries
|
// the case yet. This can happen when sync adds or replaces entries
|
||||||
// before load has finished and the view has subscribed to the timeline.
|
// before load has finished and the view has subscribed to the timeline.
|
||||||
//
|
//
|
||||||
// Once the subscription is setup, MappedList will set up the local
|
// Once the subscription is setup, MappedList will set up the local
|
||||||
// relations as needed with _applyAndEmitLocalRelationChange,
|
// relations as needed with _applyAndEmitLocalRelationChange,
|
||||||
// so we're not missing anything by bailing out.
|
// so we're not missing anything by bailing out.
|
||||||
@ -239,7 +239,7 @@ export class Timeline {
|
|||||||
if (err.name === "CompareError") {
|
if (err.name === "CompareError") {
|
||||||
// see FragmentIdComparer, if the replacing entry is on a fragment
|
// see FragmentIdComparer, if the replacing entry is on a fragment
|
||||||
// that is currently not loaded into the FragmentIdComparer, it will
|
// that is currently not loaded into the FragmentIdComparer, it will
|
||||||
// throw a CompareError, and it means that the event is not loaded
|
// throw a CompareError, and it means that the event is not loaded
|
||||||
// in the timeline (like when receiving a relation for an event
|
// in the timeline (like when receiving a relation for an event
|
||||||
// that is not loaded in memory) so we can just drop this error as
|
// that is not loaded in memory) so we can just drop this error as
|
||||||
// replacing an event that is not already loaded is a no-op.
|
// replacing an event that is not already loaded is a no-op.
|
||||||
@ -311,7 +311,7 @@ export class Timeline {
|
|||||||
* - timeline
|
* - timeline
|
||||||
* - storage
|
* - storage
|
||||||
* - homeserver
|
* - homeserver
|
||||||
* @param {EventEntry[]} entries
|
* @param {EventEntry[]} entries
|
||||||
*/
|
*/
|
||||||
async _loadContextEntriesWhereNeeded(entries) {
|
async _loadContextEntriesWhereNeeded(entries) {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
@ -392,7 +392,7 @@ export class Timeline {
|
|||||||
* [loadAtTop description]
|
* [loadAtTop description]
|
||||||
* @param {[type]} amount [description]
|
* @param {[type]} amount [description]
|
||||||
* @return {boolean} true if the top of the timeline has been reached
|
* @return {boolean} true if the top of the timeline has been reached
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
async loadAtTop(amount) {
|
async loadAtTop(amount) {
|
||||||
if (this._disposables.isDisposed) {
|
if (this._disposables.isDisposed) {
|
||||||
@ -547,7 +547,7 @@ export function tests() {
|
|||||||
content: {},
|
content: {},
|
||||||
relatedEventId: event2.event_id
|
relatedEventId: event2.event_id
|
||||||
}}));
|
}}));
|
||||||
// 4. subscribe (it's now safe to iterate timeline.entries)
|
// 4. subscribe (it's now safe to iterate timeline.entries)
|
||||||
timeline.entries.subscribe(new ListObserver());
|
timeline.entries.subscribe(new ListObserver());
|
||||||
// 5. check the local relation got correctly aggregated
|
// 5. check the local relation got correctly aggregated
|
||||||
const locallyRedacted = await poll(() => Array.from(timeline.entries)[0].isRedacting);
|
const locallyRedacted = await poll(() => Array.from(timeline.entries)[0].isRedacting);
|
||||||
|
@ -18,14 +18,40 @@ import {SortedMapList} from "./list/SortedMapList.js";
|
|||||||
import {FilteredMap} from "./map/FilteredMap.js";
|
import {FilteredMap} from "./map/FilteredMap.js";
|
||||||
import {MappedMap} from "./map/MappedMap.js";
|
import {MappedMap} from "./map/MappedMap.js";
|
||||||
import {JoinedMap} from "./map/JoinedMap.js";
|
import {JoinedMap} from "./map/JoinedMap.js";
|
||||||
import {BaseObservableMap} from "./map/BaseObservableMap";
|
import {BaseObservableMap, BaseObservableMapConfig} from "./map/BaseObservableMap";
|
||||||
|
import {ObservableMapInternal} from "./map/ObservableMap";
|
||||||
// re-export "root" (of chain) collections
|
// re-export "root" (of chain) collections
|
||||||
export { ObservableArray } from "./list/ObservableArray";
|
export { ObservableArray } from "./list/ObservableArray";
|
||||||
export { SortedArray } from "./list/SortedArray";
|
export { SortedArray } from "./list/SortedArray";
|
||||||
export { MappedList } from "./list/MappedList";
|
export { MappedList } from "./list/MappedList";
|
||||||
export { AsyncMappedList } from "./list/AsyncMappedList";
|
export { AsyncMappedList } from "./list/AsyncMappedList";
|
||||||
export { ConcatList } from "./list/ConcatList";
|
export { ConcatList } from "./list/ConcatList";
|
||||||
export { ObservableMap } from "./map/ObservableMap";
|
|
||||||
|
// avoid circular dependency between these classes
|
||||||
|
// and BaseObservableMap (as they extend it)
|
||||||
|
function config<K, V>(): BaseObservableMapConfig<K, V> {
|
||||||
|
return {
|
||||||
|
join: (_this: BaseObservableMap<K, V>, ...otherMaps: Array<BaseObservableMap<K, V>>): JoinedMap => {
|
||||||
|
return new JoinedMap([_this].concat(otherMaps));
|
||||||
|
},
|
||||||
|
mapValues: (_this: BaseObservableMap<K, V>, mapper: any, updater?: (params: any) => void): MappedMap => {
|
||||||
|
return new MappedMap(_this, mapper, updater);
|
||||||
|
},
|
||||||
|
sortValues: (_this: BaseObservableMap<K, V>, comparator?: (a: any, b: any) => number): SortedMapList => {
|
||||||
|
return new SortedMapList(_this, comparator);
|
||||||
|
},
|
||||||
|
filterValues: (_this: BaseObservableMap<K, V>, filter: (v: V, k: K) => boolean): FilteredMap => {
|
||||||
|
return new FilteredMap(_this, filter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export class ObservableMap<K, V> extends ObservableMapInternal<K, V> {
|
||||||
|
constructor(initialValues?: (readonly [K, V])[]) {
|
||||||
|
super(config<K, V>(), initialValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// avoid circular dependency between these classes
|
// avoid circular dependency between these classes
|
||||||
// and BaseObservableMap (as they extend it)
|
// and BaseObservableMap (as they extend it)
|
||||||
@ -45,4 +71,4 @@ Object.assign(BaseObservableMap.prototype, {
|
|||||||
join(...otherMaps) {
|
join(...otherMaps) {
|
||||||
return new JoinedMap([this].concat(otherMaps));
|
return new JoinedMap([this].concat(otherMaps));
|
||||||
}
|
}
|
||||||
});
|
});
|
@ -53,7 +53,7 @@ export class SortedMapList extends BaseObservableList {
|
|||||||
this._sortedPairs = null;
|
this._sortedPairs = null;
|
||||||
this._mapSubscription = null;
|
this._mapSubscription = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
onAdd(key, value) {
|
onAdd(key, value) {
|
||||||
const pair = {key, value};
|
const pair = {key, value};
|
||||||
const idx = sortedIndex(this._sortedPairs, pair, this._comparator);
|
const idx = sortedIndex(this._sortedPairs, pair, this._comparator);
|
||||||
@ -133,7 +133,7 @@ export class SortedMapList extends BaseObservableList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import {ObservableMap} from "../map/ObservableMap";
|
import {ObservableMap} from "../";
|
||||||
|
|
||||||
export function tests() {
|
export function tests() {
|
||||||
return {
|
return {
|
||||||
|
@ -15,6 +15,10 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {BaseObservable} from "../BaseObservable";
|
import {BaseObservable} from "../BaseObservable";
|
||||||
|
import {JoinedMap} from "../map/JoinedMap.js";
|
||||||
|
import {MappedMap} from "../map/MappedMap.js";
|
||||||
|
import {FilteredMap} from "../map/FilteredMap.js";
|
||||||
|
import {SortedMapList} from "../list/SortedMapList.js";
|
||||||
|
|
||||||
export interface IMapObserver<K, V> {
|
export interface IMapObserver<K, V> {
|
||||||
onReset(): void;
|
onReset(): void;
|
||||||
@ -23,6 +27,13 @@ export interface IMapObserver<K, V> {
|
|||||||
onRemove(key: K, value: V): void
|
onRemove(key: K, value: V): void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type BaseObservableMapConfig<K, V> = {
|
||||||
|
join(_this: BaseObservableMap<K, V>, ...otherMaps: Array<BaseObservableMap<K, V>>): JoinedMap;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserver<K, V>> {
|
export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserver<K, V>> {
|
||||||
emitReset() {
|
emitReset() {
|
||||||
for(let h of this._handlers) {
|
for(let h of this._handlers) {
|
||||||
@ -49,6 +60,10 @@ export abstract class BaseObservableMap<K, V> extends BaseObservable<IMapObserve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract join(...otherMaps: Array<typeof this>): JoinedMap;
|
||||||
|
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;
|
||||||
abstract [Symbol.iterator](): Iterator<[K, V]>;
|
abstract [Symbol.iterator](): Iterator<[K, V]>;
|
||||||
abstract get size(): number;
|
abstract get size(): number;
|
||||||
abstract get(key: K): V | undefined;
|
abstract get(key: K): V | undefined;
|
||||||
|
@ -166,7 +166,7 @@ class FilterIterator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
import {ObservableMap} from "./ObservableMap";
|
import {ObservableMap} from "../";
|
||||||
export function tests() {
|
export function tests() {
|
||||||
return {
|
return {
|
||||||
"filter preloaded list": assert => {
|
"filter preloaded list": assert => {
|
||||||
|
@ -191,7 +191,7 @@ class SourceSubscriptionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
import { ObservableMap } from "./ObservableMap";
|
import {ObservableMap} from "../";
|
||||||
|
|
||||||
export function tests() {
|
export function tests() {
|
||||||
|
|
||||||
|
@ -14,16 +14,38 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {BaseObservableMap} from "./BaseObservableMap";
|
import {BaseObservableMap, BaseObservableMapConfig} from "./BaseObservableMap";
|
||||||
|
import {JoinedMap} from "../map/JoinedMap.js";
|
||||||
|
import {MappedMap} from "../map/MappedMap.js";
|
||||||
|
import {FilteredMap} from "../map/FilteredMap.js";
|
||||||
|
import {SortedMapList} from "../list/SortedMapList.js";
|
||||||
|
|
||||||
export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
|
export class ObservableMapInternal<K, V> extends BaseObservableMap<K, V> {
|
||||||
|
private _config: BaseObservableMapConfig<K, V>
|
||||||
private readonly _values: Map<K, V>;
|
private readonly _values: Map<K, V>;
|
||||||
|
|
||||||
constructor(initialValues?: (readonly [K, V])[]) {
|
constructor(config: BaseObservableMapConfig<K, V>, initialValues?: (readonly [K, V])[]) {
|
||||||
super();
|
super();
|
||||||
|
this._config = config;
|
||||||
this._values = new Map(initialValues);
|
this._values = new Map(initialValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
join(...otherMaps: Array<typeof this>): JoinedMap {
|
||||||
|
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 {
|
||||||
|
return this._config.filterValues(this, filter);
|
||||||
|
}
|
||||||
|
|
||||||
update(key: K, params?: any): boolean {
|
update(key: K, params?: any): boolean {
|
||||||
const value = this._values.get(key);
|
const value = this._values.get(key);
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
@ -61,7 +83,7 @@ export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
|
|||||||
// We set the value here because update only supports inline updates
|
// We set the value here because update only supports inline updates
|
||||||
this._values.set(key, value);
|
this._values.set(key, value);
|
||||||
return this.update(key, undefined);
|
return this.update(key, undefined);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return this.add(key, value);
|
return this.add(key, value);
|
||||||
}
|
}
|
||||||
@ -91,139 +113,139 @@ export class ObservableMap<K, V> extends BaseObservableMap<K, V> {
|
|||||||
keys(): Iterator<K> {
|
keys(): Iterator<K> {
|
||||||
return this._values.keys();
|
return this._values.keys();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export function tests() {
|
// export function tests() {
|
||||||
return {
|
// return {
|
||||||
test_initial_values(assert) {
|
// test_initial_values(assert) {
|
||||||
const map = new ObservableMap([
|
// const map = new ObservableMap([
|
||||||
["a", 5],
|
// ["a", 5],
|
||||||
["b", 10]
|
// ["b", 10]
|
||||||
]);
|
// ]);
|
||||||
assert.equal(map.size, 2);
|
// assert.equal(map.size, 2);
|
||||||
assert.equal(map.get("a"), 5);
|
// assert.equal(map.get("a"), 5);
|
||||||
assert.equal(map.get("b"), 10);
|
// assert.equal(map.get("b"), 10);
|
||||||
},
|
// },
|
||||||
|
|
||||||
test_add(assert) {
|
// test_add(assert) {
|
||||||
let fired = 0;
|
// let fired = 0;
|
||||||
const map = new ObservableMap<number, {value: number}>();
|
// const map = new ObservableMap<number, {value: number}>();
|
||||||
map.subscribe({
|
// map.subscribe({
|
||||||
onAdd(key, value) {
|
// onAdd(key, value) {
|
||||||
fired += 1;
|
// fired += 1;
|
||||||
assert.equal(key, 1);
|
// assert.equal(key, 1);
|
||||||
assert.deepEqual(value, {value: 5});
|
// assert.deepEqual(value, {value: 5});
|
||||||
},
|
// },
|
||||||
onUpdate() {},
|
// onUpdate() {},
|
||||||
onRemove() {},
|
// onRemove() {},
|
||||||
onReset() {}
|
// onReset() {}
|
||||||
});
|
// });
|
||||||
map.add(1, {value: 5});
|
// map.add(1, {value: 5});
|
||||||
assert.equal(map.size, 1);
|
// assert.equal(map.size, 1);
|
||||||
assert.equal(fired, 1);
|
// assert.equal(fired, 1);
|
||||||
},
|
// },
|
||||||
|
|
||||||
test_update(assert) {
|
// test_update(assert) {
|
||||||
let fired = 0;
|
// let fired = 0;
|
||||||
const map = new ObservableMap<number, {number: number}>();
|
// const map = new ObservableMap<number, {number: number}>();
|
||||||
const value = {number: 5};
|
// const value = {number: 5};
|
||||||
map.add(1, value);
|
// map.add(1, value);
|
||||||
map.subscribe({
|
// map.subscribe({
|
||||||
onUpdate(key, value, params) {
|
// onUpdate(key, value, params) {
|
||||||
fired += 1;
|
// fired += 1;
|
||||||
assert.equal(key, 1);
|
// assert.equal(key, 1);
|
||||||
assert.deepEqual(value, {number: 6});
|
// assert.deepEqual(value, {number: 6});
|
||||||
assert.equal(params, "test");
|
// assert.equal(params, "test");
|
||||||
},
|
// },
|
||||||
onAdd() {},
|
// onAdd() {},
|
||||||
onRemove() {},
|
// onRemove() {},
|
||||||
onReset() {}
|
// onReset() {}
|
||||||
});
|
// });
|
||||||
value.number = 6;
|
// value.number = 6;
|
||||||
map.update(1, "test");
|
// map.update(1, "test");
|
||||||
assert.equal(fired, 1);
|
// assert.equal(fired, 1);
|
||||||
},
|
// },
|
||||||
|
|
||||||
test_update_unknown(assert) {
|
// test_update_unknown(assert) {
|
||||||
let fired = 0;
|
// let fired = 0;
|
||||||
const map = new ObservableMap<number, {number: number}>();
|
// const map = new ObservableMap<number, {number: number}>();
|
||||||
map.subscribe({
|
// map.subscribe({
|
||||||
onUpdate() { fired += 1; },
|
// onUpdate() { fired += 1; },
|
||||||
onAdd() {},
|
// onAdd() {},
|
||||||
onRemove() {},
|
// onRemove() {},
|
||||||
onReset() {}
|
// onReset() {}
|
||||||
});
|
// });
|
||||||
const result = map.update(1);
|
// const result = map.update(1);
|
||||||
assert.equal(fired, 0);
|
// assert.equal(fired, 0);
|
||||||
assert.equal(result, false);
|
// assert.equal(result, false);
|
||||||
},
|
// },
|
||||||
|
|
||||||
test_set(assert) {
|
// test_set(assert) {
|
||||||
let add_fired = 0, update_fired = 0;
|
// let add_fired = 0, update_fired = 0;
|
||||||
const map = new ObservableMap<number, {value: number}>();
|
// const map = new ObservableMap<number, {value: number}>();
|
||||||
map.subscribe({
|
// map.subscribe({
|
||||||
onAdd(key, value) {
|
// onAdd(key, value) {
|
||||||
add_fired += 1;
|
// add_fired += 1;
|
||||||
assert.equal(key, 1);
|
// assert.equal(key, 1);
|
||||||
assert.deepEqual(value, {value: 5});
|
// assert.deepEqual(value, {value: 5});
|
||||||
},
|
// },
|
||||||
onUpdate(key, value/*, params*/) {
|
// onUpdate(key, value/*, params*/) {
|
||||||
update_fired += 1;
|
// update_fired += 1;
|
||||||
assert.equal(key, 1);
|
// assert.equal(key, 1);
|
||||||
assert.deepEqual(value, {value: 7});
|
// assert.deepEqual(value, {value: 7});
|
||||||
},
|
// },
|
||||||
onRemove() {},
|
// onRemove() {},
|
||||||
onReset() {}
|
// onReset() {}
|
||||||
});
|
// });
|
||||||
// Add
|
// // Add
|
||||||
map.set(1, {value: 5});
|
// map.set(1, {value: 5});
|
||||||
assert.equal(map.size, 1);
|
// assert.equal(map.size, 1);
|
||||||
assert.equal(add_fired, 1);
|
// assert.equal(add_fired, 1);
|
||||||
// Update
|
// // Update
|
||||||
map.set(1, {value: 7});
|
// map.set(1, {value: 7});
|
||||||
assert.equal(map.size, 1);
|
// assert.equal(map.size, 1);
|
||||||
assert.equal(update_fired, 1);
|
// assert.equal(update_fired, 1);
|
||||||
},
|
// },
|
||||||
|
|
||||||
test_remove(assert) {
|
// test_remove(assert) {
|
||||||
let fired = 0;
|
// let fired = 0;
|
||||||
const map = new ObservableMap<number, {value: number}>();
|
// const map = new ObservableMap<number, {value: number}>();
|
||||||
const value = {value: 5};
|
// const value = {value: 5};
|
||||||
map.add(1, value);
|
// map.add(1, value);
|
||||||
map.subscribe({
|
// map.subscribe({
|
||||||
onRemove(key, value) {
|
// onRemove(key, value) {
|
||||||
fired += 1;
|
// fired += 1;
|
||||||
assert.equal(key, 1);
|
// assert.equal(key, 1);
|
||||||
assert.deepEqual(value, {value: 5});
|
// assert.deepEqual(value, {value: 5});
|
||||||
},
|
// },
|
||||||
onAdd() {},
|
// onAdd() {},
|
||||||
onUpdate() {},
|
// onUpdate() {},
|
||||||
onReset() {}
|
// onReset() {}
|
||||||
});
|
// });
|
||||||
map.remove(1);
|
// map.remove(1);
|
||||||
assert.equal(map.size, 0);
|
// assert.equal(map.size, 0);
|
||||||
assert.equal(fired, 1);
|
// assert.equal(fired, 1);
|
||||||
},
|
// },
|
||||||
|
|
||||||
test_iterate(assert) {
|
// test_iterate(assert) {
|
||||||
const results: any[] = [];
|
// const results: any[] = [];
|
||||||
const map = new ObservableMap<number, {number: number}>();
|
// const map = new ObservableMap<number, {number: number}>();
|
||||||
map.add(1, {number: 5});
|
// map.add(1, {number: 5});
|
||||||
map.add(2, {number: 6});
|
// map.add(2, {number: 6});
|
||||||
map.add(3, {number: 7});
|
// map.add(3, {number: 7});
|
||||||
for (let e of map) {
|
// for (let e of map) {
|
||||||
results.push(e);
|
// results.push(e);
|
||||||
}
|
// }
|
||||||
assert.equal(results.length, 3);
|
// assert.equal(results.length, 3);
|
||||||
assert.equal(results.find(([key]) => key === 1)[1].number, 5);
|
// assert.equal(results.find(([key]) => key === 1)[1].number, 5);
|
||||||
assert.equal(results.find(([key]) => key === 2)[1].number, 6);
|
// assert.equal(results.find(([key]) => key === 2)[1].number, 6);
|
||||||
assert.equal(results.find(([key]) => key === 3)[1].number, 7);
|
// assert.equal(results.find(([key]) => key === 3)[1].number, 7);
|
||||||
},
|
// },
|
||||||
test_size(assert) {
|
// test_size(assert) {
|
||||||
const map = new ObservableMap<number, {number: number}>();
|
// const map = new ObservableMap<number, {number: number}>();
|
||||||
map.add(1, {number: 5});
|
// map.add(1, {number: 5});
|
||||||
map.add(2, {number: 6});
|
// map.add(2, {number: 6});
|
||||||
assert.equal(map.size, 2);
|
// assert.equal(map.size, 2);
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user