diff --git a/src/domain/session/room/timeline/tiles/ImageTile.js b/src/domain/session/room/timeline/tiles/ImageTile.js index 61746097..8bdaa514 100644 --- a/src/domain/session/room/timeline/tiles/ImageTile.js +++ b/src/domain/session/room/timeline/tiles/ImageTile.js @@ -15,7 +15,6 @@ limitations under the License. */ import {MessageTile} from "./MessageTile.js"; -import {readPath, Type} from "../../../../../utils/validate.js"; const MAX_HEIGHT = 300; const MAX_WIDTH = 400; @@ -27,40 +26,38 @@ export class ImageTile extends MessageTile { } get thumbnailUrl() { - try { - const mxcUrl = readPath(this._getContent(), ["url"], Type.String); + const mxcUrl = this._getContent()?.url; + if (typeof mxcUrl === "string") { return this._room.mxcUrlThumbnail(mxcUrl, this.thumbnailWidth, this.thumbnailHeight, "scale"); - } catch (err) { - return null; } + return null; } get url() { - try { - const mxcUrl = readPath(this._getContent(), ["url"], Type.String); + const mxcUrl = this._getContent()?.url; + if (typeof mxcUrl === "string") { return this._room.mxcUrl(mxcUrl); - } catch (err) { - return null; } + return null; } _scaleFactor() { - const {info} = this._getContent(); - const scaleHeightFactor = MAX_HEIGHT / info.h; - const scaleWidthFactor = MAX_WIDTH / info.w; + const info = this._getContent()?.info; + const scaleHeightFactor = MAX_HEIGHT / info?.h; + const scaleWidthFactor = MAX_WIDTH / info?.w; // take the smallest scale factor, to respect all constraints // we should not upscale images, so limit scale factor to 1 upwards return Math.min(scaleWidthFactor, scaleHeightFactor, 1); } get thumbnailWidth() { - const {info} = this._getContent(); - return Math.round(info.w * this._scaleFactor()); + const info = this._getContent()?.info; + return Math.round(info?.w * this._scaleFactor()); } get thumbnailHeight() { - const {info} = this._getContent(); - return Math.round(info.h * this._scaleFactor()); + const info = this._getContent()?.info; + return Math.round(info?.h * this._scaleFactor()); } get label() { diff --git a/src/matrix/Sync.js b/src/matrix/Sync.js index 2e1d577e..73eeb7c1 100644 --- a/src/matrix/Sync.js +++ b/src/matrix/Sync.js @@ -18,7 +18,6 @@ limitations under the License. import {AbortError} from "./error.js"; import {ObservableValue} from "../observable/ObservableValue.js"; import {createEnum} from "../utils/enum.js"; -import {readPath, Type} from "../utils/validate.js"; const INCREMENTAL_TIMEOUT = 30000; const SYNC_EVENT_LIMIT = 10; @@ -47,8 +46,8 @@ function parseRooms(roomsSection, roomCallback) { function timelineIsEmpty(roomResponse) { try { - const events = readPath(roomResponse, ["timeline", "events"], Type.Array); - return events.length === 0; + const events = roomResponse?.timeline?.events; + return Array.isArray(events) && events.length === 0; } catch (err) { return true; } diff --git a/src/matrix/room/timeline/entries/EventEntry.js b/src/matrix/room/timeline/entries/EventEntry.js index d4843bca..ead383fa 100644 --- a/src/matrix/room/timeline/entries/EventEntry.js +++ b/src/matrix/room/timeline/entries/EventEntry.js @@ -35,8 +35,7 @@ export class EventEntry extends BaseEntry { } get prevContent() { - const unsigned = this._eventEntry.event.unsigned; - return unsigned && unsigned.prev_content; + return this._eventEntry.event.unsigned?.prev_content; } get eventType() { diff --git a/src/matrix/storage/idb/utils.js b/src/matrix/storage/idb/utils.js index 18126177..f9d98d4a 100644 --- a/src/matrix/storage/idb/utils.js +++ b/src/matrix/storage/idb/utils.js @@ -15,13 +15,12 @@ limitations under the License. */ import { StorageError } from "../common.js"; -import { readPath } from "../../../utils/validate.js"; class WrappedDOMException extends StorageError { constructor(request) { - // protect against browsers not implementing any of these properties by using readPath - const storeName = readPath(request, ["source", "name"], ""); - const databaseName = readPath(request, ["source", "transaction", "db", "name"], ""); + const source = request?.source; + const storeName = source?.name || ""; + const databaseName = source?.transaction?.db?.name || ""; super(`Failed IDBRequest on ${databaseName}.${storeName}`, request.error); this.storeName = storeName; this.databaseName = databaseName; diff --git a/src/utils/validate.js b/src/utils/validate.js deleted file mode 100644 index c185ad5c..00000000 --- a/src/utils/validate.js +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright 2020 The Matrix.org Foundation C.I.C. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -export class InvalidPathError extends Error { - constructor(obj, path, field) { - super(`Could not read path ${path.join("/")}, stopped at ${field}. Base value is ${obj}`); - } - - get name() { - return "InvalidPathError"; - } -} - -export class InvalidTypeError extends Error { - constructor(path, fieldValue, validator) { - super(`Value ${path.join("/")} is not of type ${getTypeName(validator)} but is: ${fieldValue}`); - } - - get name() { - return "InvalidTypeError"; - } -} - -function getTypeName(validator) { - if (validator === Type.Array) { - return "Array"; - } - if (validator === Type.Integer) { - return "Integer"; - } - if (validator === Type.String) { - return "String"; - } - if (validator === Type.Object) { - return "Object"; - } - if (typeof validator === "function") { - return "Custom"; - } - return "None"; -} - -export function readPath(obj, path, typeOrDefaultValue) { - if (!obj) { - throw new InvalidPathError(obj, path); - } - const hasDefaultValue = typeof typeOrDefaultValue !== "function"; - let currentValue = obj; - for (const field of path) { - currentValue = currentValue[field]; - if (typeof currentValue === "undefined") { - if (hasDefaultValue) { - return typeOrDefaultValue; - } else { - throw new InvalidPathError(obj, path, field); - } - } - } - if (!hasDefaultValue) { - const validator = typeOrDefaultValue; - if (!validator(currentValue)) { - throw new InvalidTypeError(path, currentValue, validator); - } - } - return currentValue; -} - -export const Type = Object.freeze({ - "Array": Array.isArray, - "Integer": Number.isSafeInteger, - "Boolean": value => value === true || value === false, - "String": value => typeof value === "string", - "Object": value => value !== null && typeof value === "object", -}); - -export function tests() { - return { - "readPath value at top level": assert => { - assert.strictEqual(readPath({a: 5}, ["a"]), 5); - }, - "readPath value at deep level": assert => { - assert.strictEqual(readPath({a: {b: {c: 5}}}, ["a", "b", "c"]), 5); - }, - "readPath value with correct type": assert => { - assert.strictEqual(readPath({a: 5}, ["a"], Type.Integer), 5); - }, - "readPath value with failing type": assert => { - assert.throws( - () => readPath({a: 5}, ["a"], Type.String), - {name: "InvalidTypeError"} - ); - }, - "readPath value with failing path with intermediate field not being an object": assert => { - assert.throws( - () => readPath({a: {b: "bar"}}, ["a", "b", "c"], Type.Integer), - {name: "InvalidPathError"} - ); - }, - "readPath returns default value for incomplete path": assert => { - assert.strictEqual(readPath({a: {b: "bar"}}, ["a", "b", "c"], 5), 5); - }, - - } -}