From 25d7420035ca376a1f6207f5152732b5983bb167 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 12 Mar 2022 13:46:59 +0100 Subject: [PATCH] Convert the `BasePreferences` class to use private fields Given that none of these fields were ever intended to be accessed directly from the *outside*, since that will lead to inconsistent/broken state, we can use modern ECMAScript features to ensure that they are indeed private. --- web/preferences.js | 65 +++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/web/preferences.js b/web/preferences.js index ea1ffd483..39656e4e0 100644 --- a/web/preferences.js +++ b/web/preferences.js @@ -21,29 +21,36 @@ import { AppOptions, OptionKind } from "./app_options.js"; * or every time the viewer is loaded. */ class BasePreferences { + #defaults = Object.freeze( + typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION") + ? AppOptions.getAll(OptionKind.PREFERENCE) + : PDFJSDev.eval("DEFAULT_PREFERENCES") + ); + + #prefs = Object.create(null); + + #initializedPromise = null; + constructor() { if (this.constructor === BasePreferences) { throw new Error("Cannot initialize BasePreferences."); } - Object.defineProperty(this, "defaults", { - value: Object.freeze( - typeof PDFJSDev === "undefined" || !PDFJSDev.test("PRODUCTION") - ? AppOptions.getAll(OptionKind.PREFERENCE) - : PDFJSDev.eval("DEFAULT_PREFERENCES") - ), - writable: false, - enumerable: true, - configurable: false, - }); - this.prefs = Object.create(null); - this._initializedPromise = this._readFromStorage(this.defaults).then( + if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("CHROME")) { + Object.defineProperty(this, "defaults", { + get() { + return this.#defaults; + }, + }); + } + + this.#initializedPromise = this._readFromStorage(this.#defaults).then( prefs => { - for (const name in this.defaults) { + for (const name in this.#defaults) { const prefValue = prefs?.[name]; // Ignore preferences whose types don't match the default values. - if (typeof prefValue === typeof this.defaults[name]) { - this.prefs[name] = prefValue; + if (typeof prefValue === typeof this.#defaults[name]) { + this.#prefs[name] = prefValue; } } } @@ -76,9 +83,9 @@ class BasePreferences { * have been reset. */ async reset() { - await this._initializedPromise; - this.prefs = Object.create(null); - return this._writeToStorage(this.defaults); + await this.#initializedPromise; + this.#prefs = Object.create(null); + return this._writeToStorage(this.#defaults); } /** @@ -89,8 +96,8 @@ class BasePreferences { * provided that the preference exists and the types match. */ async set(name, value) { - await this._initializedPromise; - const defaultValue = this.defaults[name]; + await this.#initializedPromise; + const defaultValue = this.#defaults[name]; if (defaultValue === undefined) { throw new Error(`Set preference: "${name}" is undefined.`); @@ -113,8 +120,8 @@ class BasePreferences { throw new Error(`Set preference: "${value}" must be an integer.`); } } - this.prefs[name] = value; - return this._writeToStorage(this.prefs); + this.#prefs[name] = value; + return this._writeToStorage(this.#prefs); } /** @@ -124,14 +131,13 @@ class BasePreferences { * containing the value of the preference. */ async get(name) { - await this._initializedPromise; - const defaultValue = this.defaults[name], - prefValue = this.prefs[name]; + await this.#initializedPromise; + const defaultValue = this.#defaults[name]; if (defaultValue === undefined) { throw new Error(`Get preference: "${name}" is undefined.`); } - return prefValue !== undefined ? prefValue : defaultValue; + return this.#prefs[name] ?? defaultValue; } /** @@ -140,12 +146,11 @@ class BasePreferences { * the values of all preferences. */ async getAll() { - await this._initializedPromise; + await this.#initializedPromise; const obj = Object.create(null); - for (const name in this.defaults) { - const prefValue = this.prefs[name]; - obj[name] = prefValue !== undefined ? prefValue : this.defaults[name]; + for (const name in this.#defaults) { + obj[name] = this.#prefs[name] ?? this.#defaults[name]; } return obj; }