diff --git a/.eslintrc.json b/.eslintrc.json index 67faf781..f1489420 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -16,7 +16,8 @@ }, "plugins": [ "no-unsanitized", - "header" + "header", + "jsdoc" ], "ignorePatterns": [ "/ext/lib/" @@ -87,6 +88,41 @@ "no-unsanitized/method": "error", "no-unsanitized/property": "error", + "jsdoc/check-access": "error", + "jsdoc/check-alignment": "error", + "jsdoc/check-line-alignment": "error", + "jsdoc/check-param-names": "error", + "jsdoc/check-property-names": "error", + "jsdoc/check-tag-names": "error", + "jsdoc/check-types": "error", + "jsdoc/check-values": "error", + "jsdoc/empty-tags": "error", + "jsdoc/implements-on-classes": "error", + "jsdoc/multiline-blocks": "error", + "jsdoc/newline-after-description": ["error", "never"], + "jsdoc/no-bad-blocks": "error", + "jsdoc/no-multi-asterisks": "error", + "jsdoc/require-asterisk-prefix": "error", + "jsdoc/require-hyphen-before-param-description": ["error", "never"], + "jsdoc/require-jsdoc": "off", + "jsdoc/require-param": "error", + "jsdoc/require-param-description": "error", + "jsdoc/require-param-name": "error", + "jsdoc/require-param-type": "error", + "jsdoc/require-property": "error", + "jsdoc/require-property-description": "error", + "jsdoc/require-property-name": "error", + "jsdoc/require-property-type": "error", + "jsdoc/require-returns": "error", + "jsdoc/require-returns-check": "error", + "jsdoc/require-returns-description": "error", + "jsdoc/require-returns-type": "error", + "jsdoc/require-throws": "error", + "jsdoc/require-yields": "error", + "jsdoc/require-yields-check": "error", + "jsdoc/tag-lines": "error", + "jsdoc/valid-types": "error", + "header/header": ["error", "block", [ "", {"pattern": " \\* Copyright \\(C\\) (\\d+-)?2022 Yomichan Authors"}, diff --git a/dev/patch-dependencies.js b/dev/patch-dependencies.js index 7052fd08..0de9bf0c 100644 --- a/dev/patch-dependencies.js +++ b/dev/patch-dependencies.js @@ -20,8 +20,8 @@ const assert = require('assert'); /** * This function patches the following bug: - * * https://github.com/jsdom/jsdom/issues/3211 - * * https://github.com/dperini/nwsapi/issues/48 + * - https://github.com/jsdom/jsdom/issues/3211 + * - https://github.com/dperini/nwsapi/issues/48 */ function patchNwsapi() { const nwsapiPath = require.resolve('nwsapi'); diff --git a/ext/js/app/frontend.js b/ext/js/app/frontend.js index 634408d9..f3b925c3 100644 --- a/ext/js/app/frontend.js +++ b/ext/js/app/frontend.js @@ -27,7 +27,7 @@ class Frontend { /** * Creates a new instance. - * @param {object} details + * @param {object} details Details about how to set up the instance. * @param {string} details.pageType The type of page, one of 'web', 'popup', or 'search'. * @param {PopupFactory} details.popupFactory A PopupFactory instance to use for generating popups. * @param {number} details.depth The nesting depth value of the popup. diff --git a/ext/js/app/popup-factory.js b/ext/js/app/popup-factory.js index bef687ff..112fa963 100644 --- a/ext/js/app/popup-factory.js +++ b/ext/js/app/popup-factory.js @@ -63,7 +63,7 @@ class PopupFactory { /** * Gets or creates a popup based on a set of parameters - * @param {object} details + * @param {object} details Details about how to acquire the popup. * @param {?number} [details.frameId] The ID of the frame that should host the popup. * @param {?string} [details.id] A specific ID used to find an existing popup, or to assign to the new popup. * @param {?string} [details.parentPopupId] The ID of the parent popup. diff --git a/ext/js/app/popup-proxy.js b/ext/js/app/popup-proxy.js index 2bf81d0a..77d87520 100644 --- a/ext/js/app/popup-proxy.js +++ b/ext/js/app/popup-proxy.js @@ -22,7 +22,7 @@ class PopupProxy extends EventDispatcher { /** * Creates a new instance. - * @param {object} details + * @param {object} details Details about how to set up the instance. * @param {string} details.id The ID of the popup. * @param {number} details.depth The depth of the popup. * @param {number} details.frameId The ID of the host frame. @@ -66,10 +66,10 @@ class PopupProxy extends EventDispatcher { /** * Attempts to set the parent popup. - * @param {Popup} value - * @throws Throws an error, since this class doesn't support a direct parent. + * @param {Popup} _value The parent to assign. + * @throws {Error} Throws an error, since this class doesn't support a direct parent. */ - set parent(value) { + set parent(_value) { throw new Error('Not supported on PopupProxy'); } @@ -84,10 +84,10 @@ class PopupProxy extends EventDispatcher { /** * Attempts to set the child popup. - * @param {Popup} value - * @throws Throws an error, since this class doesn't support children. + * @param {Popup} _child The child to assign. + * @throws {Error} Throws an error, since this class doesn't support children. */ - set child(value) { + set child(_child) { throw new Error('Not supported on PopupProxy'); } @@ -233,7 +233,6 @@ class PopupProxy extends EventDispatcher { /** * Returns whether or not the popup is currently visible, synchronously. - * @returns {boolean} `true` if the popup is visible, `false` otherwise. * @throws An exception is thrown for `PopupProxy` since it cannot synchronously detect visibility. */ isVisibleSync() { diff --git a/ext/js/app/popup-window.js b/ext/js/app/popup-window.js index 6a63a9cb..19753906 100644 --- a/ext/js/app/popup-window.js +++ b/ext/js/app/popup-window.js @@ -21,7 +21,7 @@ class PopupWindow extends EventDispatcher { /** * Creates a new instance. - * @param {object} details + * @param {object} details Details about how to set up the instance. * @param {string} details.id The ID of the popup. * @param {number} details.depth The depth of the popup. * @param {number} details.frameId The ID of the host frame. @@ -53,10 +53,10 @@ class PopupWindow extends EventDispatcher { /** * The parent of the popup, which is always `null` for `PopupWindow` instances, * since any potential parent popups are in a different frame. - * @param {Popup} value - * @type {Popup} + * @param {Popup} _value The parent to assign. + * @throws {Error} Throws an error, since this class doesn't support children. */ - set parent(value) { + set parent(_value) { throw new Error('Not supported on PopupWindow'); } @@ -71,10 +71,10 @@ class PopupWindow extends EventDispatcher { /** * Attempts to set the child popup. - * @param {Popup} value + * @param {Popup} _value The child to assign. * @throws Throws an error, since this class doesn't support children. */ - set child(value) { + set child(_value) { throw new Error('Not supported on PopupWindow'); } @@ -168,7 +168,7 @@ class PopupWindow extends EventDispatcher { /** * Shows and updates the positioning and content of the popup. - * @param {Popup.ContentDetails} details Settings for the outer popup. + * @param {Popup.ContentDetails} _details Settings for the outer popup. * @param {Display.ContentDetails} displayDetails The details parameter passed to `Display.setContent`. * @returns {Promise} */ @@ -180,6 +180,7 @@ class PopupWindow extends EventDispatcher { /** * Sets the custom styles for the popup content. * @param {string} css The CSS rules. + * @returns {Promise} */ setCustomCss(css) { return this._invoke(false, 'Display.setCustomCss', {id: this._id, css}); @@ -187,6 +188,7 @@ class PopupWindow extends EventDispatcher { /** * Stops the audio auto-play timer, if one has started. + * @returns {Promise} */ clearAutoPlayTimer() { return this._invoke(false, 'Display.clearAutoPlayTimer', {id: this._id}); @@ -194,7 +196,7 @@ class PopupWindow extends EventDispatcher { /** * Sets the scaling factor of the popup content. - * @param {number} scale The scaling factor. + * @param {number} _scale The scaling factor. */ setContentScale(_scale) { // NOP @@ -202,7 +204,6 @@ class PopupWindow extends EventDispatcher { /** * Returns whether or not the popup is currently visible, synchronously. - * @returns {boolean} `true` if the popup is visible, `false` otherwise. * @throws An exception is thrown for `PopupWindow` since it cannot synchronously detect visibility. */ isVisibleSync() { diff --git a/ext/js/app/popup.js b/ext/js/app/popup.js index e3ac4dc3..9ca2165d 100644 --- a/ext/js/app/popup.js +++ b/ext/js/app/popup.js @@ -66,7 +66,7 @@ class Popup extends EventDispatcher { /** * Creates a new instance. - * @param {object} details + * @param {object} details The details used to construct the new instance. * @param {string} details.id The ID of the popup. * @param {number} details.depth The depth of the popup. * @param {number} details.frameId The ID of the host frame. @@ -673,9 +673,11 @@ class Popup extends EventDispatcher { } /** - * @param {Rect[]} sourceRects - * @param {string} writingMode - * @returns {SizeRect} + * Computes the position where the popup should be placed relative to the source content. + * @param {Rect[]} sourceRects The rectangles of the source content. + * @param {string} writingMode The CSS writing mode of the source text. + * @param {Rect} viewport The viewport that the popup can be placed within. + * @returns {SizeRect} The calculated rectangle for where to position the popup. */ _getPosition(sourceRects, writingMode, viewport) { const scale = this._contentScale; @@ -720,7 +722,15 @@ class Popup extends EventDispatcher { } /** - * @returns {SizeRect} + * Computes the position where the popup should be placed for horizontal text. + * @param {Rect} sourceRect The rectangle of the source content. + * @param {number} frameWidth The preferred width of the frame. + * @param {number} frameHeight The preferred height of the frame. + * @param {Rect} viewport The viewport that the frame can be placed within. + * @param {number} horizontalOffset The horizontal offset from the source rect that the popup will be placed. + * @param {number} verticalOffset The vertical offset from the source rect that the popup will be placed. + * @param {boolean} preferBelow Whether or not the popup is preferred to be placed below the source content. + * @returns {SizeRect} The calculated rectangle for where to position the popup. */ _getPositionForHorizontalText(sourceRect, frameWidth, frameHeight, viewport, horizontalOffset, verticalOffset, preferBelow) { const [left, width, after] = this._getConstrainedPosition( @@ -743,7 +753,15 @@ class Popup extends EventDispatcher { } /** - * @returns {SizeRect} + * Computes the position where the popup should be placed for vertical text. + * @param {Rect} sourceRect The rectangle of the source content. + * @param {number} frameWidth The preferred width of the frame. + * @param {number} frameHeight The preferred height of the frame. + * @param {Rect} viewport The viewport that the frame can be placed within. + * @param {number} horizontalOffset The horizontal offset from the source rect that the popup will be placed. + * @param {number} verticalOffset The vertical offset from the source rect that the popup will be placed. + * @param {boolean} preferRight Whether or not the popup is preferred to be placed to the right of the source content. + * @returns {SizeRect} The calculated rectangle for where to position the popup. */ _getPositionForVerticalText(sourceRect, frameWidth, frameHeight, viewport, horizontalOffset, verticalOffset, preferRight) { const [left, width, after] = this._getConstrainedPositionBinary( @@ -824,6 +842,11 @@ class Popup extends EventDispatcher { return [position, size, after]; } + /** + * Gets the visual viewport. + * @param {boolean} useVisualViewport Whether or not the `window.visualViewport` should be used. + * @returns {Rect} The rectangle of the visual viewport. + */ _getViewport(useVisualViewport) { const visualViewport = window.visualViewport; if (visualViewport !== null && typeof visualViewport === 'object') { @@ -887,8 +910,9 @@ class Popup extends EventDispatcher { } /** - * @param {Rect[]} sourceRects - * @returns {Rect} + * Computes the bounding rectangle for a set of rectangles. + * @param {Rect[]} sourceRects An array of rectangles. + * @returns {Rect} The bounding rectangle for all of the source rectangles. */ _getBoundingSourceRect(sourceRects) { switch (sourceRects.length) { @@ -907,10 +931,11 @@ class Popup extends EventDispatcher { } /** - * @param {SizeRect} sizeRect - * @param {Rect[]} sourceRects - * @param {number} ignoreIndex - * @returns {boolean} + * Checks whether or not a rectangle is overlapping any other rectangles. + * @param {SizeRect} sizeRect The rectangles to check for overlaps. + * @param {Rect[]} sourceRects The list of rectangles to compare against. + * @param {number} ignoreIndex The index of an item in `sourceRects` to ignore. + * @returns {boolean} `true` if `sizeRect` overlaps any one of `sourceRects`, excluding `sourceRects[ignoreIndex]`; `false` otherwise. */ _isOverlapping(sizeRect, sourceRects, ignoreIndex) { const {left, top} = sizeRect; diff --git a/ext/js/app/theme-controller.js b/ext/js/app/theme-controller.js index 4ee82c52..6a95e2d7 100644 --- a/ext/js/app/theme-controller.js +++ b/ext/js/app/theme-controller.js @@ -174,7 +174,7 @@ class ThemeController { /** * Adds the value of a CSS color to an accumulation target. - * @param {[number, number, number]} target The target color buffer to accumulate into. + * @param {number[]} target The target color buffer to accumulate into, as an array of [r, g, b]. * @param {string|*} cssColor The CSS color value to add to the target. If this value is not a string, * the target will not be modified. */ @@ -196,7 +196,7 @@ class ThemeController { /** * Decomposes a CSS color string into its RGBA values. * @param {string} cssColor The color value to decompose. This value is expected to be in the form RGB(r, g, b) or RGBA(r, g, b, a). - * @returns {?[number, number, number, number]} The color and alpha values. The color component values range from [0, 255], and the alpha ranges from [0, 1]. + * @returns {?number[]} The color and alpha values as [r, g, b, a]. The color component values range from [0, 255], and the alpha ranges from [0, 1]. */ _getColorInfo(cssColor) { const m = /^\s*rgba?\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)\s*$/.exec(cssColor); diff --git a/ext/js/background/profile-conditions-util.js b/ext/js/background/profile-conditions-util.js index fd2991f8..e9bd7a19 100644 --- a/ext/js/background/profile-conditions-util.js +++ b/ext/js/background/profile-conditions-util.js @@ -23,6 +23,20 @@ * Utility class to help processing profile conditions. */ class ProfileConditionsUtil { + /** + * A group of conditions. + * @typedef {object} ProfileConditionGroup + * @property {ProfileCondition[]} conditions The list of conditions for this group. + */ + + /** + * A single condition. + * @typedef {object} ProfileCondition + * @property {string} type The type of the condition. + * @property {string} operator The condition operator. + * @property {string} value The value to compare against. + */ + /** * Creates a new instance. */ @@ -78,20 +92,9 @@ class ProfileConditionsUtil { /** * Creates a new JSON schema descriptor for the given set of condition groups. - * @param conditionGroups An array of condition groups in the following format: - * conditionGroups = [ - * { - * conditions: [ - * { - * type: (condition type: string), - * operator: (condition sub-type: string), - * value: (value to compare against: string) - * }, - * ... - * ] - * }, - * ... - * ] + * @param {ProfileConditionGroup[]} conditionGroups An array of condition groups. + * For a profile match, all of the items must return successfully in at least one of the groups. + * @returns {JsonSchema} A new `JsonSchema` object. */ createSchema(conditionGroups) { const anyOf = []; @@ -125,8 +128,8 @@ class ProfileConditionsUtil { /** * Creates a normalized version of the context object to test, * assigning dependent fields as needed. - * @param context A context object which is used during schema validation. - * @returns A normalized context object. + * @param {object} context A context object which is used during schema validation. + * @returns {object} A normalized context object. */ normalizeContext(context) { const normalizedContext = Object.assign({}, context); diff --git a/ext/js/comm/clipboard-reader.js b/ext/js/comm/clipboard-reader.js index 7a4744ca..aaf4dcd8 100644 --- a/ext/js/comm/clipboard-reader.js +++ b/ext/js/comm/clipboard-reader.js @@ -25,9 +25,10 @@ class ClipboardReader { /** * Creates a new instances of a clipboard reader. - * @param document The Document object to be used, or null for no support. - * @param pasteTargetSelector The selector for the paste target element. - * @param imagePasteTargetSelector The selector for the image paste target element. + * @param {object} details Details about how to set up the instance. + * @param {?Document} details.document The Document object to be used, or null for no support. + * @param {?string} details.pasteTargetSelector The selector for the paste target element. + * @param {?string} details.imagePasteTargetSelector The selector for the image paste target element. */ constructor({document=null, pasteTargetSelector=null, imagePasteTargetSelector=null}) { this._document = document; @@ -40,6 +41,7 @@ class ClipboardReader { /** * Gets the browser being used. + * @type {?string} */ get browser() { return this._browser; @@ -54,8 +56,8 @@ class ClipboardReader { /** * Gets the text in the clipboard. - * @returns A string containing the clipboard text. - * @throws Error if not supported. + * @returns {string} A string containing the clipboard text. + * @throws {Error} Error if not supported. */ async getText() { /* @@ -103,8 +105,8 @@ class ClipboardReader { /** * Gets the first image in the clipboard. - * @returns A string containing a data URL of the image file, or null if no image was found. - * @throws Error if not supported. + * @returns {string} A string containing a data URL of the image file, or null if no image was found. + * @throws {Error} Error if not supported. */ async getImage() { // See browser-specific notes in getText diff --git a/ext/js/comm/frame-ancestry-handler.js b/ext/js/comm/frame-ancestry-handler.js index cff31ce0..56daafe9 100644 --- a/ext/js/comm/frame-ancestry-handler.js +++ b/ext/js/comm/frame-ancestry-handler.js @@ -24,7 +24,7 @@ class FrameAncestryHandler { /** * Creates a new instance. - * @param frameId The frame ID of the current frame the instance is instantiated in. + * @param {number} frameId The frame ID of the current frame the instance is instantiated in. */ constructor(frameId) { this._frameId = frameId; @@ -37,6 +37,7 @@ class FrameAncestryHandler { /** * Gets the frame ID that the instance is instantiated in. + * @type {number} */ get frameId() { return this._frameId; @@ -53,7 +54,7 @@ class FrameAncestryHandler { /** * Returns whether or not this frame is the root frame in the tab. - * @returns `true` if it is the root, otherwise `false`. + * @returns {boolean} `true` if it is the root, otherwise `false`. */ isRootFrame() { return (window === window.parent); @@ -63,8 +64,7 @@ class FrameAncestryHandler { * Gets the frame ancestry information for the current frame. If the frame is the * root frame, an empty array is returned. Otherwise, an array of frame IDs is returned, * starting from the nearest ancestor. - * @param timeout The maximum time to wait to receive a response to frame information requests. - * @returns An array of frame IDs corresponding to the ancestors of the current frame. + * @returns {number[]} An array of frame IDs corresponding to the ancestors of the current frame. */ async getFrameAncestryInfo() { if (this._getFrameAncestryInfoPromise === null) { @@ -77,8 +77,8 @@ class FrameAncestryHandler { * Gets the frame element of a child frame given a frame ID. * For this function to work, the `getFrameAncestryInfo` function needs to have * been invoked previously. - * @param frameId The frame ID of the child frame to get. - * @returns The element corresponding to the frame with ID `frameId`, otherwise `null`. + * @param {number} frameId The frame ID of the child frame to get. + * @returns {HTMLElement} The element corresponding to the frame with ID `frameId`, otherwise `null`. */ getChildFrameElement(frameId) { const frameInfo = this._childFrameMap.get(frameId); diff --git a/ext/js/comm/mecab.js b/ext/js/comm/mecab.js index 9be8b75f..24364588 100644 --- a/ext/js/comm/mecab.js +++ b/ext/js/comm/mecab.js @@ -20,6 +20,21 @@ * used to parse text into individual terms. */ class Mecab { + /** + * The resulting data from an invocation of `parseText`. + * @typedef {object} ParseResult + * @property {string} name The dictionary name for the parsed result. + * @property {ParseTerm[]} lines The resulting parsed terms. + */ + + /** + * A fragment of the parsed text. + * @typedef {object} ParseFragment + * @property {string} term The term. + * @property {string} reading The reading of the term. + * @property {string} source The source text. + */ + /** * Creates a new instance of the class. */ @@ -37,6 +52,7 @@ class Mecab { /** * Returns whether or not the component is enabled. + * @returns {boolean} Whether or not the object is enabled. */ isEnabled() { return this._enabled; @@ -44,7 +60,7 @@ class Mecab { /** * Changes whether or not the component connection is enabled. - * @param enabled A boolean indicating whether or not the component should be enabled. + * @param {boolean} enabled A boolean indicating whether or not the component should be enabled. */ setEnabled(enabled) { this._enabled = !!enabled; @@ -64,7 +80,7 @@ class Mecab { /** * Returns whether or not the connection to the native application is active. - * @returns `true` if the connection is active, `false` otherwise. + * @returns {boolean} `true` if the connection is active, `false` otherwise. */ isConnected() { return (this._port !== null); @@ -72,7 +88,7 @@ class Mecab { /** * Returns whether or not any invocation is currently active. - * @returns `true` if an invocation is active, `false` otherwise. + * @returns {boolean} `true` if an invocation is active, `false` otherwise. */ isActive() { return (this._invocations.size > 0); @@ -80,7 +96,7 @@ class Mecab { /** * Gets the local API version being used. - * @returns An integer representing the API version that Yomichan uses. + * @returns {number} An integer representing the API version that Yomichan uses. */ getLocalVersion() { return this._version; @@ -88,7 +104,7 @@ class Mecab { /** * Gets the version of the MeCab component. - * @returns The version of the MeCab component, or `null` if the component was not found. + * @returns {?number} The version of the MeCab component, or `null` if the component was not found. */ async getVersion() { try { @@ -115,8 +131,8 @@ class Mecab { * ... * ] * ``` - * @param text The string to parse. - * @returns A collection of parsing results of the text. + * @param {string} text The string to parse. + * @returns {ParseResult[]} A collection of parsing results of the text. */ async parseText(text) { await this._setupPort(); diff --git a/ext/js/core.js b/ext/js/core.js index 517642a2..9b5734f2 100644 --- a/ext/js/core.js +++ b/ext/js/core.js @@ -250,7 +250,7 @@ function generateId(length) { /** * Creates an unresolved promise that can be resolved later, outside the promise's executor function. - * @returns {{promise: Promise, resolve: function, reject: function}} An object `{promise, resolve, reject}`, containing the promise and the resolve/reject functions. + * @returns {{promise: Promise, resolve: Function, reject: Function}} An object `{promise, resolve, reject}`, containing the promise and the resolve/reject functions. */ function deferPromise() { let resolve; @@ -349,15 +349,15 @@ function promiseAnimationFrame(timeout=null) { /** * Invokes a standard message handler. This function is used to react and respond * to communication messages within the extension. - * @param {object} details - * @param {function} details.handler A handler function which is passed `params` and `...extraArgs` as arguments. + * @param {object} details Details about how to handle messages. + * @param {Function} details.handler A handler function which is passed `params` and `...extraArgs` as arguments. * @param {boolean|string} details.async Whether or not the handler is async or not. Values include `false`, `true`, or `'dynamic'`. * When the value is `'dynamic'`, the handler should return an object of the format `{async: boolean, result: any}`. * @param {object} params Information which was passed with the original message. - * @param {function} callback A callback function which is invoked after the handler has completed. The value passed + * @param {Function} callback A callback function which is invoked after the handler has completed. The value passed * to the function is in the format: - * * `{result: any}` if the handler invoked successfully. - * * `{error: object}` if the handler thew an error. The error is serialized. + * - `{result: any}` if the handler invoked successfully. + * - `{error: object}` if the handler thew an error. The error is serialized. * @param {...*} extraArgs Additional arguments which are passed to the `handler` function. * @returns {boolean} `true` if the function is invoked asynchronously, `false` otherwise. */ @@ -413,7 +413,7 @@ class EventDispatcher { /** * Adds a single event listener to a specific event. * @param {string} eventName The string representing the event's name. - * @param {function} callback The event listener callback to add. + * @param {Function} callback The event listener callback to add. */ on(eventName, callback) { let callbacks = this._eventMap.get(eventName); @@ -427,7 +427,7 @@ class EventDispatcher { /** * Removes a single event listener from a specific event. * @param {string} eventName The string representing the event's name. - * @param {function} callback The event listener callback to add. + * @param {Function} callback The event listener callback to add. * @returns {boolean} `true` if the callback was removed, `false` otherwise. */ off(eventName, callback) { @@ -482,6 +482,7 @@ class EventListenerCollection { * @param {string} type The type of event listener, which can be 'addEventListener', 'addListener', or 'on'. * @param {object} object The object to add the event listener to. * @param {...*} args The argument array passed to the object's event listener adding function. + * @returns {void} * @throws An error if type is not an expected value. */ addGeneric(type, object, ...args) { @@ -539,8 +540,6 @@ class EventListenerCollection { case 'off': object.off(...args); break; - default: - throw new Error(`Unknown remove function: ${removeFunctionName}`); } } this._eventListeners = []; diff --git a/ext/js/data/anki-util.js b/ext/js/data/anki-util.js index faccbc84..bb375230 100644 --- a/ext/js/data/anki-util.js +++ b/ext/js/data/anki-util.js @@ -22,8 +22,8 @@ class AnkiUtil { /** * Gets the root deck name of a full deck name. If the deck is a root deck, * the same name is returned. Nested decks are separated using '::'. - * @param deckName A string of the deck name. - * @returns A string corresponding to the name of the root deck. + * @param {string} deckName A string of the deck name. + * @returns {string} A string corresponding to the name of the root deck. */ static getRootDeckName(deckName) { const index = deckName.indexOf('::'); @@ -32,8 +32,8 @@ class AnkiUtil { /** * Checks whether or not any marker is contained in a string. - * @param string A string to check. - * @return `true` if the text contains an Anki field marker, `false` otherwise. + * @param {string} string A string to check. + * @returns {boolean} `true` if the text contains an Anki field marker, `false` otherwise. */ static stringContainsAnyFieldMarker(string) { const result = this._markerPattern.test(string); @@ -43,8 +43,8 @@ class AnkiUtil { /** * Gets a list of all markers that are contained in a string. - * @param string A string to check. - * @return An array of marker strings. + * @param {string} string A string to check. + * @returns {string[]} An array of marker strings. */ static getFieldMarkers(string) { const pattern = this._markerPattern; @@ -57,26 +57,10 @@ class AnkiUtil { return markers; } - /** - * Checks whether an object of key-value pairs has a value which contains a specific marker. - * @param fieldsObject An object with key-value pairs, where the value corresponds to the field value. - * @param marker The marker string to check for, excluding brackets. - * @returns `true` if any of the fields contains the marker, `false` otherwise. - */ - static fieldsObjectContainsMarker(fieldsObject, marker) { - marker = `{${marker}}`; - for (const [, fieldValue] of fieldsObject) { - if (fieldValue.includes(marker)) { - return true; - } - } - return false; - } - /** * Returns a regular expression which can be used to find markers in a string. - * @param global Whether or not the regular expression should have the global flag. - * @returns A new `RegExp` instance. + * @param {boolean} global Whether or not the regular expression should have the global flag. + * @returns {RegExp} A new `RegExp` instance. */ static cloneFieldMarkerPattern(global) { return new RegExp(this._markerPattern.source, global ? 'g' : ''); @@ -84,8 +68,8 @@ class AnkiUtil { /** * Checks whether or not a note object is valid. - * @param note A note object to check. - * @return `true` if the note is valid, `false` otherwise. + * @param {*} note A note object to check. + * @returns {boolean} `true` if the note is valid, `false` otherwise. */ static isNoteDataValid(note) { if (!isObject(note)) { return false; } diff --git a/ext/js/data/sandbox/anki-note-data-creator.js b/ext/js/data/sandbox/anki-note-data-creator.js index 96f97896..e1c32193 100644 --- a/ext/js/data/sandbox/anki-note-data-creator.js +++ b/ext/js/data/sandbox/anki-note-data-creator.js @@ -26,7 +26,7 @@ class AnkiNoteDataCreator { /** * Creates a new instance. - * @param japaneseUtil An instance of `JapaneseUtil`. + * @param {JapaneseUtil} japaneseUtil An instance of `JapaneseUtil`. */ constructor(japaneseUtil) { this._japaneseUtil = japaneseUtil; @@ -34,8 +34,16 @@ class AnkiNoteDataCreator { /** * Creates a compatibility representation of the specified data. - * @param marker The marker that is being used for template rendering. - * @returns An object used for rendering Anki templates. + * @param {string} marker The marker that is being used for template rendering. + * @param {object} details Information which is used to generate the data. + * @param {Translation.DictionaryEntry} details.dictionaryEntry The dictionary entry. + * @param {string} details.resultOutputMode The result output mode. + * @param {string} details.mode The mode being used to generate the Anki data. + * @param {string} details.glossaryLayoutMode The glossary layout mode. + * @param {boolean} details.compactTags Whether or not compact tags mode is enabled. + * @param {{documentTitle: string, query: string, fullQuery: string}} details.context Contextual information about the source of the dictionary entry. + * @param {object} details.media Media data. + * @returns {object} An object used for rendering Anki templates. */ create(marker, { dictionaryEntry, @@ -83,8 +91,8 @@ class AnkiNoteDataCreator { /** * Creates a deferred-evaluation value. - * @param getter The function to invoke to get the return value. - * @returns An object which can be passed into `getCachedValue`. + * @param {Function} getter The function to invoke to get the return value. + * @returns {{getter: Function, hasValue: false, value: undefined}} An object which can be passed into `getCachedValue`. */ createCachedValue(getter) { return {getter, hasValue: false, value: void 0}; @@ -92,8 +100,8 @@ class AnkiNoteDataCreator { /** * Gets the value of a cached object. - * @param item An object that was returned from `createCachedValue`. - * @returns The result of evaluating the getter, which is cached after the first invocation. + * @param {{getter: Function, hasValue: boolean, value: *}} item An object that was returned from `createCachedValue`. + * @returns {*} The result of evaluating the getter, which is cached after the first invocation. */ getCachedValue(item) { if (item.hasValue) { return item.value; } diff --git a/ext/js/data/sandbox/string-util.js b/ext/js/data/sandbox/string-util.js index 5c395be7..de6933cd 100644 --- a/ext/js/data/sandbox/string-util.js +++ b/ext/js/data/sandbox/string-util.js @@ -21,8 +21,8 @@ class StringUtil { /** * Decodes the contents of an ArrayBuffer using UTF8. - * @param arrayBuffer The input ArrayBuffer. - * @returns A UTF8-decoded string. + * @param {ArrayBuffer} arrayBuffer The input ArrayBuffer. + * @returns {string} A UTF8-decoded string. */ static arrayBufferUtf8Decode(arrayBuffer) { try { @@ -34,8 +34,8 @@ class StringUtil { /** * Converts the contents of an ArrayBuffer to a base64 string. - * @param arrayBuffer The input ArrayBuffer. - * @returns A base64 string representing the binary content. + * @param {ArrayBuffer} arrayBuffer The input ArrayBuffer. + * @returns {string} A base64 string representing the binary content. */ static arrayBufferToBase64(arrayBuffer) { return btoa(this.arrayBufferToBinaryString(arrayBuffer)); @@ -43,8 +43,8 @@ class StringUtil { /** * Converts the contents of an ArrayBuffer to a binary string. - * @param arrayBuffer The input ArrayBuffer. - * @returns A string representing the binary content. + * @param {ArrayBuffer} arrayBuffer The input ArrayBuffer. + * @returns {string} A string representing the binary content. */ static arrayBufferToBinaryString(arrayBuffer) { const bytes = new Uint8Array(arrayBuffer); @@ -61,8 +61,8 @@ class StringUtil { /** * Converts a base64 string to an ArrayBuffer. - * @param content The binary content string encoded in base64. - * @returns A new `ArrayBuffer` object corresponding to the specified content. + * @param {string} content The binary content string encoded in base64. + * @returns {ArrayBuffer} A new `ArrayBuffer` object corresponding to the specified content. */ static base64ToArrayBuffer(content) { const binaryContent = atob(content); diff --git a/ext/js/display/display.js b/ext/js/display/display.js index 82364233..aad54e1c 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -39,6 +39,49 @@ class Display extends EventDispatcher { /** * Information about how popup content should be shown, specifically related to the inner popup content. * @typedef {object} ContentDetails + * @property {boolean} focus Whether or not the frame should be `focus()`'d. + * @property {HistoryParams} params An object containing key-value pairs representing the URL search params. + * @property {?HistoryState} state The semi-persistent state assigned to the navigation entry. + * @property {?HistoryContent} content The non-persistent content assigned to the navigation entry. + * @property {'clear'|'overwrite'|'new'} historyMode How the navigation history should be modified. + */ + + /** + * An object containing key-value pairs representing the URL search params. + * @typedef {object} HistoryParams + * @property {'terms'|'kanji'|'unloaded'|'clear'} [type] The type of content that is being shown. + * @property {string} [query] The search query. + * @property {'on'|'off'} [wildcards] Whether or not wildcards can be used for the search query. + * @property {string} [offset] The start position of the `query` string as an index into the `full` query string. + * @property {string} [full] The full search text. If absent, `query` is the full search text. + * @property {'true'|'false'} [full-visible] Whether or not the full search query should be forced to be visible. + * @property {'true'|'false'} [lookup] Whether or not the query should be looked up. If it is not looked up, + * the content should be provided. + */ + + /** + * The semi-persistent state assigned to the navigation entry. + * @typedef {object} HistoryState + * @property {'queryParser'} [cause] What was the cause of the navigation. + * @property {object} [sentence] The sentence context. + * @property {string} sentence.text The full string. + * @property {number} sentence.offset The offset from the start of `text` to the full search query. + * @property {number} [focusEntry] The index of the dictionary entry to focus. + * @property {number} [scrollX] The horizontal scroll position. + * @property {number} [scrollY] The vertical scroll position. + * @property {object} [optionsContext] The options context which should be used for lookups. + * @property {string} [url] The originating URL of the content. + * @property {string} [documentTitle] The originating document title of the content. + */ + + /** + * The non-persistent content assigned to the navigation entry. + * @typedef {object} HistoryContent + * @property {boolean} [animate] Whether or not any CSS animations should occur. + * @property {object[]} [dictionaryEntries] An array of dictionary entries to display as content. + * @property {object} [contentOrigin] The identifying information for the frame the content originated from. + * @property {number} [contentOrigin.tabId] The tab id. + * @property {number} [contentOrigin.frameId] The frame id within the tab. */ constructor(tabId, frameId, pageType, japaneseUtil, documentFocusController, hotkeyHandler) { @@ -348,7 +391,7 @@ class Display extends EventDispatcher { /** * Updates the content of the display. - * @param {ContentDetails} details + * @param {ContentDetails} details Information about the content to show. */ setContent(details) { const {focus, params, state, content} = details; diff --git a/ext/js/dom/document-util.js b/ext/js/dom/document-util.js index 10d91551..f5cf194b 100644 --- a/ext/js/dom/document-util.js +++ b/ext/js/dom/document-util.js @@ -68,27 +68,27 @@ class DocumentUtil { /** * Extract a sentence from a document. - * @param source The text source object, either `TextSourceRange` or `TextSourceElement`. - * @param layoutAwareScan Whether or not layout-aware scan mode should be used. - * @param extent The length of the sentence to extract. - * @param terminateAtNewlines Whether or not a sentence should be terminated at newline characters. - * @param terminatorMap A mapping of characters that terminate a sentence. + * @param {TextSourceRange|TextSourceElement} source The text source object, either `TextSourceRange` or `TextSourceElement`. + * @param {boolean} layoutAwareScan Whether or not layout-aware scan mode should be used. + * @param {number} extent The length of the sentence to extract. + * @param {boolean} terminateAtNewlines Whether or not a sentence should be terminated at newline characters. + * @param {Map} terminatorMap A mapping of characters that terminate a sentence. * Format: * ```js * new Map([ [character: string, [includeCharacterAtStart: boolean, includeCharacterAtEnd: boolean]], ... ]) * ``` - * @param forwardQuoteMap A mapping of quote characters that delimit a sentence. + * @param {Map} forwardQuoteMap A mapping of quote characters that delimit a sentence. * Format: * ```js * new Map([ [character: string, [otherCharacter: string, includeCharacterAtStart: boolean]], ... ]) * ``` - * @param backwardQuoteMap A mapping of quote characters that delimit a sentence, + * @param {Map} backwardQuoteMap A mapping of quote characters that delimit a sentence, * which is the inverse of forwardQuoteMap. * Format: * ```js * new Map([ [character: string, [otherCharacter: string, includeCharacterAtEnd: boolean]], ... ]) * ``` - * @returns The sentence and the offset to the original source: `{sentence: string, offset: integer}`. + * @returns {{sentence: string, offset: number}} The sentence and the offset to the original source. */ extractSentence(source, layoutAwareScan, extent, terminateAtNewlines, terminatorMap, forwardQuoteMap, backwardQuoteMap) { // Scan text diff --git a/ext/js/dom/dom-text-scanner.js b/ext/js/dom/dom-text-scanner.js index fff08825..83b16028 100644 --- a/ext/js/dom/dom-text-scanner.js +++ b/ext/js/dom/dom-text-scanner.js @@ -21,9 +21,12 @@ class DOMTextScanner { /** * Creates a new instance of a DOMTextScanner. - * @param node The DOM Node to start at. - * @param offset The character offset in to start at when node is a text node. + * @param {Node} node The DOM Node to start at. + * @param {number} offset The character offset in to start at when node is a text node. * Use 0 for non-text nodes. + * @param {boolean} forcePreserveWhitespace Whether or not whitespace should be forced to be preserved, + * regardless of CSS styling. + * @param {boolean} generateLayoutContent Whether or not newlines should be added based on CSS styling. */ constructor(node, offset, forcePreserveWhitespace=false, generateLayoutContent=true) { const ruby = DOMTextScanner.getParentRubyElement(node); @@ -393,6 +396,7 @@ class DOMTextScanner { /** * Gets seek information about an element. + * @param {Element} element The element to check. * @returns {{enterable: boolean, newlines: number}} The seek information. * The `enterable` value indicates whether the content of this node should be entered. * The `newlines` value corresponds to the number of newline characters that should be added. @@ -443,6 +447,8 @@ class DOMTextScanner { /** * Gets attributes for the specified character. * @param {string} character A string containing a single character. + * @param {boolean} preserveNewlines Whether or not newlines should be preserved. + * @param {boolean} preserveWhitespace Whether or not whitespace should be preserved. * @returns {number} An integer representing the attributes of the character. * 0: Character should be ignored. * 1: Character is collapsible whitespace. diff --git a/ext/js/dom/sandbox/css-style-applier.js b/ext/js/dom/sandbox/css-style-applier.js index a6938d92..6c45f13e 100644 --- a/ext/js/dom/sandbox/css-style-applier.js +++ b/ext/js/dom/sandbox/css-style-applier.js @@ -36,8 +36,9 @@ class CssStyleApplier { /** * Creates a new instance of the class. - * @param styleDataUrl The local URL to the JSON file continaing the style rules. + * @param {string} styleDataUrl The local URL to the JSON file continaing the style rules. * The style rules should be of the format: + * ``` * [ * { * selectors: [(selector:string)...], @@ -46,6 +47,7 @@ class CssStyleApplier { * ] * }... * ] + * ``` */ constructor(styleDataUrl) { this._styleDataUrl = styleDataUrl; @@ -84,7 +86,7 @@ class CssStyleApplier { /** * Applies CSS styles directly to the "style" attribute using the "class" attribute. * This only works for elements with a single class. - * @param elements An iterable collection of HTMLElement objects. + * @param {Iterable} elements An iterable collection of HTMLElement objects. */ applyClassStyles(elements) { const elementStyles = []; diff --git a/ext/js/dom/selector-observer.js b/ext/js/dom/selector-observer.js index c2065103..071c3971 100644 --- a/ext/js/dom/selector-observer.js +++ b/ext/js/dom/selector-observer.js @@ -19,19 +19,41 @@ * Class which is used to observe elements matching a selector in specific element. */ class SelectorObserver { + /** + * @function OnAddedCallback + * @param {Element} element The element which was added. + * @returns {*} Custom data which is assigned to element and passed to callbacks. + */ + + /** + * @function OnRemovedCallback + * @param {Element} element The element which was removed. + * @param {*} data The custom data corresponding to the element. + */ + + /** + * @function OnChildrenUpdatedCallback + * @param {Element} element The element which had its children updated. + * @param {*} data The custom data corresponding to the element. + */ + + /** + * @function IsStaleCallback + * @param {Element} element The element which had its children updated. + * @param {*} data The custom data corresponding to the element. + * @returns {boolean} Whether or not the data is stale for the element. + */ + /** * Creates a new instance. - * @param selector A string CSS selector used to find elements. - * @param ignoreSelector A string CSS selector used to filter elements, or null for no filtering. - * @param onAdded A function which is invoked for each element that is added that matches the selector. - * The signature is (element) => data. - * @param onRemoved A function which is invoked for each element that is removed, or null. - * The signature is (element, data) => void. - * @param onChildrenUpdated A function which is invoked for each element which has its children updated, or null. - * The signature is (element, data) => void. - * @param isStale A function which checks if the data is stale for a given element, or null. + * @param {object} details The configuration for the object. + * @param {string} details.selector A string CSS selector used to find elements. + * @param {?string} details.ignoreSelector A string CSS selector used to filter elements, or `null` for no filtering. + * @param {OnAddedCallback} details.onAdded A function which is invoked for each element that is added that matches the selector. + * @param {?OnRemovedCallback} details.onRemoved A function which is invoked for each element that is removed, or `null`. + * @param {?OnChildrenUpdatedCallback} details.onChildrenUpdated A function which is invoked for each element which has its children updated, or `null`. + * @param {?IsStaleCallback} details.isStale A function which checks if the data is stale for a given element, or `null`. * If the element is stale, it will be removed and potentially re-added. - * The signature is (element, data) => bool. */ constructor({selector, ignoreSelector=null, onAdded=null, onRemoved=null, onChildrenUpdated=null, isStale=null}) { this._selector = selector; @@ -49,7 +71,7 @@ class SelectorObserver { /** * Returns whether or not an element is currently being observed. - * @returns True if an element is being observed, false otherwise. + * @returns {boolean} `true` if an element is being observed, `false` otherwise. */ get isObserving() { return this._observingElement !== null; @@ -57,10 +79,10 @@ class SelectorObserver { /** * Starts DOM mutation observing the target element. - * @param element The element to observe changes in. - * @param attributes A boolean for whether or not attribute changes should be observed. - * @throws An error if element is null. - * @throws An error if an element is already being observed. + * @param {Element} element The element to observe changes in. + * @param {boolean} [attributes] A boolean for whether or not attribute changes should be observed. + * @throws {Error} An error if element is null. + * @throws {Error} An error if an element is already being observed. */ observe(element, attributes=false) { if (element === null) { diff --git a/ext/js/general/cache-map.js b/ext/js/general/cache-map.js index f993cc26..fccb7cdd 100644 --- a/ext/js/general/cache-map.js +++ b/ext/js/general/cache-map.js @@ -21,7 +21,7 @@ class CacheMap { /** * Creates a new CacheMap. - * @param maxSize The maximum number of entries able to be stored in the cache. + * @param {number} maxSize The maximum number of entries able to be stored in the cache. */ constructor(maxSize) { if (!( @@ -42,6 +42,7 @@ class CacheMap { /** * Returns the number of items in the cache. + * @type {number} */ get size() { return this._map.size; @@ -49,6 +50,7 @@ class CacheMap { /** * Returns the maximum number of items that can be added to the cache. + * @type {number} */ get maxSize() { return this._maxSize; @@ -56,8 +58,8 @@ class CacheMap { /** * Returns whether or not an element exists at the given key. - * @param key The key of the element. - * @returns `true` if an element with the specified key exists, `false` otherwise. + * @param {*} key The key of the element. + * @returns {boolean} `true` if an element with the specified key exists, `false` otherwise. */ has(key) { return this._map.has(key); @@ -65,8 +67,8 @@ class CacheMap { /** * Gets an element at the given key, if it exists. Otherwise, returns undefined. - * @param key The key of the element. - * @returns The existing value at the key, if any; `undefined` otherwise. + * @param {*} key The key of the element. + * @returns {*} The existing value at the key, if any; `undefined` otherwise. */ get(key) { const node = this._map.get(key); @@ -77,8 +79,8 @@ class CacheMap { /** * Sets a value at a given key. - * @param key The key of the element. - * @param value The value to store in the cache. + * @param {*} key The key of the element. + * @param {*} value The value to store in the cache. */ set(key, value) { let node = this._map.get(key); diff --git a/ext/js/general/object-property-accessor.js b/ext/js/general/object-property-accessor.js index 516ad72f..ea410ac3 100644 --- a/ext/js/general/object-property-accessor.js +++ b/ext/js/general/object-property-accessor.js @@ -21,8 +21,7 @@ class ObjectPropertyAccessor { /** * Create a new accessor for a specific object. - * @param target The object which the getter and mutation methods are applied to. - * @returns A new ObjectPropertyAccessor instance. + * @param {object} target The object which the getter and mutation methods are applied to. */ constructor(target) { this._target = target; @@ -30,11 +29,11 @@ class ObjectPropertyAccessor { /** * Gets the value at the specified path. - * @param pathArray The path to the property on the target object. - * @param pathLength How many parts of the pathArray to use. + * @param {(string|number)[]} pathArray The path to the property on the target object. + * @param {number} [pathLength] How many parts of the pathArray to use. * This parameter is optional and defaults to the length of pathArray. - * @returns The value found at the path. - * @throws An error is thrown if pathArray is not valid for the target object. + * @returns {*} The value found at the path. + * @throws {Error} An error is thrown if pathArray is not valid for the target object. */ get(pathArray, pathLength) { let target = this._target; @@ -51,9 +50,9 @@ class ObjectPropertyAccessor { /** * Sets the value at the specified path. - * @param pathArray The path to the property on the target object. - * @param value The value to assign to the property. - * @throws An error is thrown if pathArray is not valid for the target object. + * @param {(string|number)[]} pathArray The path to the property on the target object. + * @param {*} value The value to assign to the property. + * @throws {Error} An error is thrown if pathArray is not valid for the target object. */ set(pathArray, value) { const ii = pathArray.length - 1; @@ -70,8 +69,8 @@ class ObjectPropertyAccessor { /** * Deletes the property of the target object at the specified path. - * @param pathArray The path to the property on the target object. - * @throws An error is thrown if pathArray is not valid for the target object. + * @param {(string|number)[]}pathArray The path to the property on the target object. + * @throws {Error} An error is thrown if pathArray is not valid for the target object. */ delete(pathArray) { const ii = pathArray.length - 1; @@ -92,8 +91,8 @@ class ObjectPropertyAccessor { /** * Swaps two properties of an object or array. - * @param pathArray1 The path to the first property on the target object. - * @param pathArray2 The path to the second property on the target object. + * @param {(string|number)[]} pathArray1 The path to the first property on the target object. + * @param {(string|number)[]} pathArray2 The path to the second property on the target object. * @throws An error is thrown if pathArray1 or pathArray2 is not valid for the target object, * or if the swap cannot be performed. */ @@ -129,8 +128,9 @@ class ObjectPropertyAccessor { /** * Converts a path string to a path array. - * @param pathArray The path array to convert. - * @returns A string representation of pathArray. + * @param {(string|number)[]} pathArray The path array to convert. + * @returns {string} A string representation of `pathArray`. + * @throws {Error} An error is thrown if any item of `pathArray` is not a string or an integer. */ static getPathString(pathArray) { const regexShort = /^[a-zA-Z_][a-zA-Z0-9_]*$/; @@ -166,8 +166,9 @@ class ObjectPropertyAccessor { /** * Converts a path array to a path string. For the most part, the format of this string * matches Javascript's notation for property access. - * @param pathString The path string to convert. - * @returns An array representation of pathString. + * @param {string} pathString The path string to convert. + * @returns {(string | number)[]} An array representation of `pathString`. + * @throws {Error} An error is thrown if `pathString` is malformed. */ static getPathArray(pathString) { const pathArray = []; @@ -286,11 +287,11 @@ class ObjectPropertyAccessor { /** * Checks whether an object or array has the specified property. - * @param object The object to test. - * @param property The property to check for existence. + * @param {*} object The object to test. + * @param {string|number} property The property to check for existence. * This value should be a string if the object is a non-array object. * For arrays, it should be an integer. - * @returns true if the property exists, otherwise false. + * @returns {boolean} `true` if the property exists, otherwise `false`. */ static hasProperty(object, property) { switch (typeof property) { @@ -315,9 +316,9 @@ class ObjectPropertyAccessor { /** * Checks whether a property is valid for the given object - * @param object The object to test. - * @param property The property to check for existence. - * @returns true if the property is correct for the given object type, otherwise false. + * @param {object} object The object to test. + * @param {string|number} property The property to check for existence. + * @returns {boolean} `true` if the property is correct for the given object type, otherwise `false`. * For arrays, this means that the property should be a positive integer. * For non-array objects, the property should be a string. */ diff --git a/ext/js/general/regex-util.js b/ext/js/general/regex-util.js index d74a2f1e..6fa1a220 100644 --- a/ext/js/general/regex-util.js +++ b/ext/js/general/regex-util.js @@ -22,12 +22,12 @@ class RegexUtil { /** * Applies string.replace using a regular expression and replacement string as arguments. * A source map of the changes is also maintained. - * @param text A string of the text to replace. - * @param sourceMap An instance of `TextSourceMap` which corresponds to `text`. - * @param pattern A regular expression to use as the replacement. - * @param replacement A replacement string that follows the format of the standard + * @param {string} text A string of the text to replace. + * @param {TextSourceMap} sourceMap An instance of `TextSourceMap` which corresponds to `text`. + * @param {RegExp} pattern A regular expression to use as the replacement. + * @param {string} replacement A replacement string that follows the format of the standard * JavaScript regular expression replacement string. - * @return A new string with the pattern replacements applied and the source map updated. + * @returns {string} A new string with the pattern replacements applied and the source map updated. */ static applyTextReplacement(text, sourceMap, pattern, replacement) { const isGlobal = pattern.global; @@ -57,10 +57,10 @@ class RegexUtil { /** * Applies the replacement string for a given regular expression match. - * @param replacement The replacement string that follows the format of the standard + * @param {string} replacement The replacement string that follows the format of the standard * JavaScript regular expression replacement string. - * @param match A match object returned from RegExp.match. - * @return A new string with the pattern replacement applied. + * @param {object} match A match object returned from RegExp.match. + * @returns {string} A new string with the pattern replacement applied. */ static applyMatchReplacement(replacement, match) { const pattern = this._matchReplacementPattern; diff --git a/ext/js/input/hotkey-handler.js b/ext/js/input/hotkey-handler.js index 33a449e3..dc0f6d3e 100644 --- a/ext/js/input/hotkey-handler.js +++ b/ext/js/input/hotkey-handler.js @@ -23,6 +23,16 @@ * Class which handles hotkey events and actions. */ class HotkeyHandler extends EventDispatcher { + /** + * Information describing a hotkey. + * @typedef {object} HotkeyDefinition + * @property {string} action A string indicating which action to perform. + * @property {string} key A keyboard key code indicating which key needs to be pressed. + * @property {string[]} modifiers An array of keyboard modifiers which also need to be pressed. Supports: `'alt', 'ctrl', 'shift', 'meta'`. + * @property {string[]} scopes An array of scopes for which the hotkey is valid. If this array does not contain `this.scope`, the hotkey will not be registered. + * @property {boolean} enabled A boolean indicating whether the hotkey is currently enabled. + */ + /** * Creates a new instance of the class. */ @@ -49,7 +59,7 @@ class HotkeyHandler extends EventDispatcher { /** * Registers a set of actions that this hotkey handler supports. - * @param actions An array of `[name, handler]` entries, where `name` is a string and `handler` is a function. + * @param {*[][]} actions An array of `[name, handler]` entries, where `name` is a string and `handler` is a function. */ registerActions(actions) { for (const [name, handler] of actions) { @@ -59,13 +69,8 @@ class HotkeyHandler extends EventDispatcher { /** * Registers a set of hotkeys for a given scope. - * @param scope The scope that the hotkey definitions must be for in order to be activated. - * @param hotkeys An array of hotkey definitions of the format `{action, key, modifiers, scopes, enabled}`. - * * `action` - a string indicating which action to perform. - * * `key` - a keyboard key code indicating which key needs to be pressed. - * * `modifiers` - an array of keyboard modifiers which also need to be pressed. Supports: `'alt', 'ctrl', 'shift', 'meta'`. - * * `scopes` - an array of scopes for which the hotkey is valid. If this array does not contain `this.scope`, the hotkey will not be registered. - * * `enabled` - a boolean indicating whether the hotkey is currently enabled. + * @param {string} scope The scope that the hotkey definitions must be for in order to be activated. + * @param {HotkeyDefinition[]} hotkeys An array of hotkey definitions. */ registerHotkeys(scope, hotkeys) { let registrations = this._hotkeyRegistrations.get(scope); @@ -79,6 +84,7 @@ class HotkeyHandler extends EventDispatcher { /** * Removes all registered hotkeys for a given scope. + * @param {string} scope The scope that the hotkey definitions were registered in. */ clearHotkeys(scope) { const registrations = this._hotkeyRegistrations.get(scope); @@ -91,7 +97,8 @@ class HotkeyHandler extends EventDispatcher { /** * Assigns a set of hotkeys for a given scope. This is an optimized shorthand for calling * `clearHotkeys`, then calling `registerHotkeys`. - * @see registerHotkeys for argument information. + * @param {string} scope The scope that the hotkey definitions must be for in order to be activated. + * @param {HotkeyDefinition[]} hotkeys An array of hotkey definitions. */ setHotkeys(scope, hotkeys) { let registrations = this._hotkeyRegistrations.get(scope); @@ -107,8 +114,9 @@ class HotkeyHandler extends EventDispatcher { /** * Adds a single event listener to a specific event. - * @param eventName The string representing the event's name. - * @param callback The event listener callback to add. + * @param {string} eventName The string representing the event's name. + * @param {Function} callback The event listener callback to add. + * @returns {void} */ on(eventName, callback) { const result = super.on(eventName, callback); @@ -119,9 +127,9 @@ class HotkeyHandler extends EventDispatcher { /** * Removes a single event listener from a specific event. - * @param eventName The string representing the event's name. - * @param callback The event listener callback to add. - * @returns `true` if the callback was removed, `false` otherwise. + * @param {string} eventName The string representing the event's name. + * @param {Function} callback The event listener callback to add. + * @returns {boolean} `true` if the callback was removed, `false` otherwise. */ off(eventName, callback) { const result = super.off(eventName, callback); @@ -132,9 +140,9 @@ class HotkeyHandler extends EventDispatcher { /** * Attempts to simulate an action for a given combination of key and modifiers. - * @param key A keyboard key code indicating which key needs to be pressed. - * @param modifiers An array of keyboard modifiers which also need to be pressed. Supports: `'alt', 'ctrl', 'shift', 'meta'`. - * @returns `true` if an action was performed, `false` otherwise. + * @param {string} key A keyboard key code indicating which key needs to be pressed. + * @param {string[]} modifiers An array of keyboard modifiers which also need to be pressed. Supports: `'alt', 'ctrl', 'shift', 'meta'`. + * @returns {boolean} `true` if an action was performed, `false` otherwise. */ simulate(key, modifiers) { const hotkeyInfo = this._hotkeys.get(key); diff --git a/ext/js/input/hotkey-util.js b/ext/js/input/hotkey-util.js index 4dd9447a..35802106 100644 --- a/ext/js/input/hotkey-util.js +++ b/ext/js/input/hotkey-util.js @@ -21,6 +21,7 @@ class HotkeyUtil { /** * Creates a new instance. + * @param {?string} os The operating system for this instance. */ constructor(os=null) { this._os = os; @@ -41,6 +42,7 @@ class HotkeyUtil { /** * Gets the operating system for this instance. * The operating system is used to display system-localized modifier key names. + * @type {?string} */ get os() { return this._os; @@ -48,7 +50,7 @@ class HotkeyUtil { /** * Sets the operating system for this instance. - * @param value The value to assign. + * @param {?string} value The value to assign. * Valid values are: win, mac, linux, openbsd, cros, android. */ set os(value) { @@ -59,10 +61,10 @@ class HotkeyUtil { /** * Gets a display string for a key and a set of modifiers. - * @param key The key code string, or `null` for no key. - * @param modifiers An array of modifiers. + * @param {?string} key The key code string, or `null` for no key. + * @param {string[]} modifiers An array of modifiers. * Valid values are: ctrl, alt, shift, meta, or mouseN, where N is an integer. - * @returns A user-friendly string for the combination of key and modifiers. + * @returns {string} A user-friendly string for the combination of key and modifiers. */ getInputDisplayValue(key, modifiers) { const separator = this._inputSeparator; @@ -85,9 +87,9 @@ class HotkeyUtil { /** * Gets a display string for a single modifier. - * @param modifier A string representing a modifier. + * @param {string} modifier A string representing a modifier. * Valid values are: ctrl, alt, shift, meta, or mouseN, where N is an integer. - * @returns A user-friendly string for the modifier. + * @returns {string} A user-friendly string for the modifier. */ getModifierDisplayValue(modifier) { const match = this._mouseInputNamePattern.exec(modifier); @@ -101,8 +103,8 @@ class HotkeyUtil { /** * Gets a display string for a key. - * @param key The key code string, or `null` for no key. - * @returns A user-friendly string for the combination of key and modifiers, or `null` if key was already `null`. + * @param {?string} key The key code string, or `null` for no key. + * @returns {?string} A user-friendly string for the combination of key and modifiers, or `null` if key was already `null`. */ getKeyDisplayValue(key) { if (typeof key === 'string' && key.length === 4 && key.startsWith('Key')) { @@ -113,9 +115,9 @@ class HotkeyUtil { /** * Gets a display string for a single modifier. - * @param modifier A string representing a modifier. + * @param {string} modifier A string representing a modifier. * Valid values are: ctrl, alt, shift, meta, or mouseN, where N is an integer. - * @returns `'mouse'` if the modifier represents a mouse button, `'key'` otherwise. + * @returns {'mouse'|'key'} `'mouse'` if the modifier represents a mouse button, `'key'` otherwise. */ getModifierType(modifier) { return (this._mouseInputNamePattern.test(modifier) ? 'mouse' : 'key'); @@ -123,8 +125,8 @@ class HotkeyUtil { /** * Converts an extension command string into a standard input. - * @param command An extension command string. - * @returns An object `{key, modifiers}`, where key is a string (or `null`) representing the key, and modifiers is an array of modifier keys. + * @param {string} command An extension command string. + * @returns {{key: ?string, modifiers: string[]}} An object `{key, modifiers}`, where key is a string (or `null`) representing the key, and modifiers is an array of modifier keys. */ convertCommandToInput(command) { let key = null; @@ -142,10 +144,10 @@ class HotkeyUtil { /** * Gets a command string for a specified input. - * @param key The key code string, or `null` for no key. - * @param modifiers An array of modifier keys. + * @param {?string} key The key code string, or `null` for no key. + * @param {string[]} modifiers An array of modifier keys. * Valid values are: ctrl, alt, shift, meta. - * @returns An extension command string representing the input. + * @returns {string} An extension command string representing the input. */ convertInputToCommand(key, modifiers) { const separator = '+'; @@ -168,9 +170,9 @@ class HotkeyUtil { /** * Sorts an array of modifiers. - * @param modifiers An array of modifiers. + * @param {string[]} modifiers An array of modifiers. * Valid values are: ctrl, alt, shift, meta. - * @returns A sorted array of modifiers. The array instance is the same as the input array. + * @returns {string[]} A sorted array of modifiers. The array instance is the same as the input array. */ sortModifiers(modifiers) { const pattern = this._mouseInputNamePattern; diff --git a/ext/js/language/dictionary-importer-media-loader.js b/ext/js/language/dictionary-importer-media-loader.js index 69a27f71..ce03ab20 100644 --- a/ext/js/language/dictionary-importer-media-loader.js +++ b/ext/js/language/dictionary-importer-media-loader.js @@ -21,9 +21,12 @@ class DictionaryImporterMediaLoader { /** * Attempts to load an image using an ArrayBuffer and a media type to return details about it. - * @param content The binary content for the image, encoded as an ArrayBuffer. - * @param mediaType The media type for the image content. - * @returns A Promise which resolves with {content, width, height} on success, otherwise an error is thrown. + * @param {ArrayBuffer} content The binary content for the image, encoded as an ArrayBuffer. + * @param {string} mediaType The media type for the image content. + * @param {Transferable[]} [transfer] An optional array of data that should be transferred in `postMessage` calls. + * When the resulting promise resolves, this array will contain the `content` object. + * @returns {Promise<{content: ArrayBuffer, width: number, height: number}>} Details about the requested image content. + * @throws {Error} An error can be thrown if the image fails to load. */ getImageDetails(content, mediaType, transfer) { return new Promise((resolve, reject) => { diff --git a/ext/js/language/dictionary-worker-media-loader.js b/ext/js/language/dictionary-worker-media-loader.js index fc7ecd17..7e30b333 100644 --- a/ext/js/language/dictionary-worker-media-loader.js +++ b/ext/js/language/dictionary-worker-media-loader.js @@ -29,7 +29,7 @@ class DictionaryWorkerMediaLoader { /** * Handles a response message posted to the worker thread. - * @param params Details of the response. + * @param {{id: string, error: object|undefined, result: any|undefined}} params Details of the response. */ handleMessage(params) { const {id} = params; @@ -46,9 +46,10 @@ class DictionaryWorkerMediaLoader { /** * Attempts to load an image using an ArrayBuffer and a media type to return details about it. - * @param content The binary content for the image, encoded as an ArrayBuffer. - * @param mediaType The media type for the image content. - * @returns A Promise which resolves with {content, width, height} on success, otherwise an error is thrown. + * @param {ArrayBuffer} content The binary content for the image, encoded as an ArrayBuffer. + * @param {string} mediaType The media type for the image content. + * @returns {Promise<{content: ArrayBuffer, width: number, height: number}>} Details about the requested image content. + * @throws {Error} An error can be thrown if the image fails to load. */ getImageDetails(content, mediaType) { return new Promise((resolve, reject) => { diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js index fafd1bfb..73f27ff9 100644 --- a/ext/js/language/translator.js +++ b/ext/js/language/translator.js @@ -25,6 +25,16 @@ * Class which finds term and kanji dictionary entries for text. */ class Translator { + /** + * Information about how popup content should be shown, specifically related to the outer popup frame. + * @typedef {object} TermFrequency + * @property {string} term The term. + * @property {string} reading The reading of the term. + * @property {string} dictionary The name of the dictionary that the term frequency originates from. + * @property {boolean} hasReading Whether or not a reading was specified. + * @property {number|string} frequency The frequency value for the term. + */ + /** * Creates a new Translator instance. * @param {object} details The details for the class. diff --git a/ext/js/media/media-util.js b/ext/js/media/media-util.js index 78668471..582b13a2 100644 --- a/ext/js/media/media-util.js +++ b/ext/js/media/media-util.js @@ -22,8 +22,8 @@ class MediaUtil { /** * Gets the file extension of a file path. URL search queries and hash * fragments are not handled. - * @param path The path to the file. - * @returns The file extension, including the '.', or an empty string + * @param {string} path The path to the file. + * @returns {string} The file extension, including the '.', or an empty string * if there is no file extension. */ static getFileNameExtension(path) { @@ -33,9 +33,9 @@ class MediaUtil { /** * Gets an image file's media type using a file path. - * @param path The path to the file. - * @returns The media type string if it can be determined from the file path, - * otherwise null. + * @param {string} path The path to the file. + * @returns {?string} The media type string if it can be determined from the file path, + * otherwise `null`. */ static getImageMediaTypeFromFileName(path) { switch (this.getFileNameExtension(path).toLowerCase()) { @@ -70,9 +70,9 @@ class MediaUtil { /** * Gets the file extension for a corresponding media type. - * @param mediaType The media type to use. - * @returns A file extension including the dot for the media type, - * otherwise null. + * @param {string} mediaType The media type to use. + * @returns {?string} A file extension including the dot for the media type, + * otherwise `null`. */ static getFileExtensionFromImageMediaType(mediaType) { switch (mediaType) { @@ -101,9 +101,9 @@ class MediaUtil { /** * Gets the file extension for a corresponding media type. - * @param mediaType The media type to use. - * @returns A file extension including the dot for the media type, - * otherwise null. + * @param {string} mediaType The media type to use. + * @returns {string} A file extension including the dot for the media type, + * otherwise `null`. */ static getFileExtensionFromAudioMediaType(mediaType) { switch (mediaType) { diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 45dda06c..c5276f58 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -53,6 +53,7 @@ class AnkiTemplateRenderer { /** * Gets the generic TemplateRenderer instance. + * @type {TemplateRenderer} */ get templateRenderer() { return this._templateRenderer; diff --git a/ext/js/yomichan.js b/ext/js/yomichan.js index 4ec9db9c..9bc9cc5f 100644 --- a/ext/js/yomichan.js +++ b/ext/js/yomichan.js @@ -150,16 +150,17 @@ class Yomichan extends EventDispatcher { /** * Checks whether or not a URL is an extension URL. * @param {string} url The URL to check. - * @returns true if the URL is an extension URL, false otherwise. + * @returns {boolean} `true` if the URL is an extension URL, `false` otherwise. */ isExtensionUrl(url) { return this._extensionUrlBase !== null && url.startsWith(this._extensionUrlBase); } /** - * Runs chrome.runtime.sendMessage() with additional exception handling events. - * @param {...*} args The arguments to be passed to chrome.runtime.sendMessage(). - * @returns {void} The result of the chrome.runtime.sendMessage() call. + * Runs `chrome.runtime.sendMessage()` with additional exception handling events. + * @param {...*} args The arguments to be passed to `chrome.runtime.sendMessage()`. + * @returns {void} The result of the `chrome.runtime.sendMessage()` call. + * @throws {Error} Errors thrown by `chrome.runtime.sendMessage()` are re-thrown. */ sendMessage(...args) { try { @@ -171,9 +172,10 @@ class Yomichan extends EventDispatcher { } /** - * Runs chrome.runtime.connect() with additional exception handling events. - * @param {...*} args The arguments to be passed to chrome.runtime.connect(). + * Runs `chrome.runtime.connect()` with additional exception handling events. + * @param {...*} args The arguments to be passed to `chrome.runtime.connect()`. * @returns {Port} The resulting port. + * @throws {Error} Errors thrown by `chrome.runtime.connect()` are re-thrown. */ connect(...args) { try { diff --git a/package-lock.json b/package-lock.json index a09eb187..b7b5cda1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "css": "^3.0.0", "eslint": "^8.15.0", "eslint-plugin-header": "^3.1.1", + "eslint-plugin-jsdoc": "^39.2.9", "eslint-plugin-no-unsanitized": "^4.0.1", "fake-indexeddb": "^3.1.7", "html-validate": "^7.1.0", @@ -197,6 +198,20 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.29.0.tgz", + "integrity": "sha512-4yKy5t+/joLihG+ei6CCU6sc08sjUdEdXCQ2U+9h9VP13EiqHQ4YMgDC18ys/AsLdJDBX3KRx/AWY6PR7hn52Q==", + "dev": true, + "dependencies": { + "comment-parser": "1.3.1", + "esquery": "^1.4.0", + "jsdoc-type-pratt-parser": "~3.0.1" + }, + "engines": { + "node": "^14 || ^16 || ^17 || ^18" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz", @@ -1801,6 +1816,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", @@ -3145,6 +3169,42 @@ "eslint": ">=7.7.0" } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "39.2.9", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.2.9.tgz", + "integrity": "sha512-gaPYJT94rWlWyQcisQyyEJHtLaaJqN4baFlLCEr/LcXVibS9wzQTL2dskqk327ggwqQopR+Xecu2Lng1IJ9Ypw==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.29.0", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.4.0", + "semver": "^7.3.7", + "spdx-expression-parse": "^3.0.1" + }, + "engines": { + "node": "^14 || ^16 || ^17 || ^18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/eslint-plugin-no-unsanitized": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz", @@ -5404,6 +5464,15 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.0.1.tgz", + "integrity": "sha512-vqMCdAFVIiFhVgBYE/X8naf3L/7qiJsaYWTfUJZZZ124dR3OUz9HrmaMUGpYIYAN4VSuodf6gIZY0e8ktPw9cg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsdom": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", @@ -10348,6 +10417,17 @@ "async": "~0.2.9" } }, + "@es-joy/jsdoccomment": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.29.0.tgz", + "integrity": "sha512-4yKy5t+/joLihG+ei6CCU6sc08sjUdEdXCQ2U+9h9VP13EiqHQ4YMgDC18ys/AsLdJDBX3KRx/AWY6PR7hn52Q==", + "dev": true, + "requires": { + "comment-parser": "1.3.1", + "esquery": "^1.4.0", + "jsdoc-type-pratt-parser": "~3.0.1" + } + }, "@eslint/eslintrc": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz", @@ -11683,6 +11763,12 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true + }, "common-tags": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", @@ -12810,6 +12896,32 @@ "dev": true, "requires": {} }, + "eslint-plugin-jsdoc": { + "version": "39.2.9", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.2.9.tgz", + "integrity": "sha512-gaPYJT94rWlWyQcisQyyEJHtLaaJqN4baFlLCEr/LcXVibS9wzQTL2dskqk327ggwqQopR+Xecu2Lng1IJ9Ypw==", + "dev": true, + "requires": { + "@es-joy/jsdoccomment": "~0.29.0", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.4.0", + "semver": "^7.3.7", + "spdx-expression-parse": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "eslint-plugin-no-unsanitized": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz", @@ -14501,6 +14613,12 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "dev": true }, + "jsdoc-type-pratt-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.0.1.tgz", + "integrity": "sha512-vqMCdAFVIiFhVgBYE/X8naf3L/7qiJsaYWTfUJZZZ124dR3OUz9HrmaMUGpYIYAN4VSuodf6gIZY0e8ktPw9cg==", + "dev": true + }, "jsdom": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-19.0.0.tgz", diff --git a/package.json b/package.json index 1bc7e388..532d4a51 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "css": "^3.0.0", "eslint": "^8.15.0", "eslint-plugin-header": "^3.1.1", + "eslint-plugin-jsdoc": "^39.2.9", "eslint-plugin-no-unsanitized": "^4.0.1", "fake-indexeddb": "^3.1.7", "html-validate": "^7.1.0", diff --git a/test/test-jsdom.js b/test/test-jsdom.js index c97a3d97..a56a579e 100644 --- a/test/test-jsdom.js +++ b/test/test-jsdom.js @@ -20,8 +20,8 @@ const {testMain} = require('../dev/util'); /** * This function tests the following bug: - * * https://github.com/jsdom/jsdom/issues/3211 - * * https://github.com/dperini/nwsapi/issues/48 + * - https://github.com/jsdom/jsdom/issues/3211 + * - https://github.com/dperini/nwsapi/issues/48 */ function testJSDOMSelectorBug() { // nwsapi is used by JSDOM