From e6dba6ee340ffc006634678f30a56e329b5e532e Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sat, 25 Apr 2026 12:09:18 +0200 Subject: [PATCH] Enable the `radix` ESLint rule Many `parseInt` call-sites already provide the `radix` argument, and this rule helps improve consistency in the code-base; see https://eslint.org/docs/latest/rules/radix *Please note:* The rule is disabled in `src/scripting_api/util.js` for now, since it's not obvious at a glance (at least to me) what the correct `radix` argument should be there. --- eslint.config.mjs | 1 + extensions/chromium/options/options.js | 2 +- extensions/chromium/telemetry.js | 2 +- src/core/primitives.js | 4 ++-- src/core/xfa/factory.js | 2 +- src/core/xfa/xhtml.js | 4 ++-- src/core/xref.js | 2 +- src/display/annotation_layer.js | 4 ++-- src/display/display_utils.js | 10 +++++----- src/scripting_api/util.js | 1 + test/chromium/test-telemetry.js | 2 +- test/integration/scripting_spec.mjs | 2 +- test/integration/test_utils.mjs | 2 +- web/app.js | 12 ++++++------ web/caret_browsing.js | 2 +- web/pdf_thumbnail_viewer.js | 3 ++- web/signature_manager.js | 2 +- 17 files changed, 30 insertions(+), 27 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 2f4461b8b..082f27774 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -269,6 +269,7 @@ export default [ "prefer-object-has-own": "error", "prefer-promise-reject-errors": "error", "prefer-spread": "error", + radix: "error", "wrap-iife": ["error", "any"], yoda: ["error", "never", { exceptRange: true }], diff --git a/extensions/chromium/options/options.js b/extensions/chromium/options/options.js index 3867a11b9..a4c31a545 100644 --- a/extensions/chromium/options/options.js +++ b/extensions/chromium/options/options.js @@ -168,7 +168,7 @@ function renderEnumPref(shortDescription, prefName) { var select = wrapper.querySelector("select"); select.onchange = function () { var pref = {}; - pref[prefName] = parseInt(this.value); + pref[prefName] = parseInt(this.value, 10); storageArea.set(pref); }; wrapper.querySelector("span").textContent = shortDescription; diff --git a/extensions/chromium/telemetry.js b/extensions/chromium/telemetry.js index b0cb34ef4..cf944012f 100644 --- a/extensions/chromium/telemetry.js +++ b/extensions/chromium/telemetry.js @@ -96,7 +96,7 @@ limitations under the License. chrome.storage.local.get(localStorage, items => { Object.assign(localStorage, items); - var lastTime = parseInt(localStorage.telemetryLastTime) || 0; + var lastTime = parseInt(localStorage.telemetryLastTime, 10) || 0; var wasUpdated = didUpdateSinceLastCheck(); if (!wasUpdated && Date.now() - lastTime < MINIMUM_TIME_BETWEEN_PING) { return; diff --git a/src/core/primitives.js b/src/core/primitives.js index 7d40a7d90..eb5cb0193 100644 --- a/src/core/primitives.js +++ b/src/core/primitives.js @@ -316,8 +316,8 @@ class Ref { // eslint-disable-next-line no-restricted-syntax return (RefCache[str] = new Ref( - parseInt(m[1]), - !m[2] ? 0 : parseInt(m[2]) + parseInt(m[1], 10), + !m[2] ? 0 : parseInt(m[2], 10) )); } diff --git a/src/core/xfa/factory.js b/src/core/xfa/factory.js index 5dacfbb10..930b8a071 100644 --- a/src/core/xfa/factory.js +++ b/src/core/xfa/factory.js @@ -74,7 +74,7 @@ class XFAFactory { this.pages = await this._createPagesHelper(); this.dims = this.pages.children.map(c => { const { width, height } = c.attributes.style; - return [0, 0, parseInt(width), parseInt(height)]; + return [0, 0, parseInt(width, 10), parseInt(height, 10)]; }); } catch (e) { warn(`XFA - an error occurred during layout: ${e}`); diff --git a/src/core/xfa/xhtml.js b/src/core/xfa/xhtml.js index 47a0056d0..5998829f9 100644 --- a/src/core/xfa/xhtml.js +++ b/src/core/xfa/xhtml.js @@ -81,11 +81,11 @@ const StyleMapping = new Map([ ["kerning-mode", value => (value === "none" ? "none" : "normal")], [ "xfa-font-horizontal-scale", - value => `scaleX(${Math.max(0, parseInt(value) / 100).toFixed(2)})`, + value => `scaleX(${Math.max(0, parseInt(value, 10) / 100).toFixed(2)})`, ], [ "xfa-font-vertical-scale", - value => `scaleY(${Math.max(0, parseInt(value) / 100).toFixed(2)})`, + value => `scaleY(${Math.max(0, parseInt(value, 10) / 100).toFixed(2)})`, ], ["xfa-spacerun", ""], ["xfa-tab-stops", ""], diff --git a/src/core/xref.js b/src/core/xref.js index 6ff5a1e52..0cfedc40f 100644 --- a/src/core/xref.js +++ b/src/core/xref.js @@ -687,7 +687,7 @@ class XRef { if (!entry) { continue; } - const ref = Ref.get(parseInt(num), entry.gen); + const ref = Ref.get(parseInt(num, 10), entry.gen); let obj; try { diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index 550c2fe20..8206d3f7b 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -3024,7 +3024,7 @@ class PopupElement { this.#setPosition(); this.#container.hidden = false; this.#container.style.zIndex = - parseInt(this.#container.style.zIndex) + 1000; + parseInt(this.#container.style.zIndex, 10) + 1000; } else if (this.#pinned) { this.#container.classList.add("focused"); } @@ -3040,7 +3040,7 @@ class PopupElement { } this.#container.hidden = true; this.#container.style.zIndex = - parseInt(this.#container.style.zIndex) - 1000; + parseInt(this.#container.style.zIndex, 10) - 1000; } forceHide() { diff --git a/src/display/display_utils.js b/src/display/display_utils.js index df43b09d7..37360a0ac 100644 --- a/src/display/display_utils.js +++ b/src/display/display_utils.js @@ -569,7 +569,7 @@ class PDFDateString { */ function getXfaPageViewport(xfaPage, { scale = 1, rotation = 0 }) { const { width, height } = xfaPage.attributes.style; - const viewBox = [0, 0, parseInt(width), parseInt(height)]; + const viewBox = [0, 0, parseInt(width, 10), parseInt(height, 10)]; return new PageViewport({ viewBox, @@ -596,7 +596,7 @@ function getRGBA(color) { const [r, g, b] = color .slice(/* "rgb(".length */ 4, -1) // Strip out "rgb(" and ")". .split(",") - .map(x => parseInt(x)); + .map(x => parseInt(x, 10)); return [r, g, b, 1]; } @@ -605,9 +605,9 @@ function getRGBA(color) { .slice(/* "rgba(".length */ 5, -1) // Strip out "rgba(" and ")". .split(","); return [ - parseInt(parts[0]), - parseInt(parts[1]), - parseInt(parts[2]), + parseInt(parts[0], 10), + parseInt(parts[1], 10), + parseInt(parts[2], 10), parseFloat(parts[3]), ]; } diff --git a/src/scripting_api/util.js b/src/scripting_api/util.js index 91229b0d7..5d576e01c 100644 --- a/src/scripting_api/util.js +++ b/src/scripting_api/util.js @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/* eslint-disable radix */ import { PDFObject } from "./pdf_object.js"; diff --git a/test/chromium/test-telemetry.js b/test/chromium/test-telemetry.js index 48f9d301d..795d7c733 100755 --- a/test/chromium/test-telemetry.js +++ b/test/chromium/test-telemetry.js @@ -155,7 +155,7 @@ function updateBrowser(window) { window.navigator.userAgent = window.navigator.userAgent.replace( /Chrome\/(\d+)/, function (_, v) { - return "Chrome/" + (parseInt(v) + 1); + return "Chrome/" + (parseInt(v, 10) + 1); } ); } diff --git a/test/integration/scripting_spec.mjs b/test/integration/scripting_spec.mjs index 6dcb3aecc..5314cf687 100644 --- a/test/integration/scripting_spec.mjs +++ b/test/integration/scripting_spec.mjs @@ -1389,7 +1389,7 @@ describe("Interaction", () => { (sel, b, a) => { const el = document.querySelector(sel); const rotation = - parseInt(el.getAttribute("data-main-rotation")) || 0; + parseInt(el.getAttribute("data-main-rotation"), 10) || 0; return rotation === (360 + ((360 - (b + a)) % 360)) % 360; }, {}, diff --git a/test/integration/test_utils.mjs b/test/integration/test_utils.mjs index 401f23582..b0c16f856 100644 --- a/test/integration/test_utils.mjs +++ b/test/integration/test_utils.mjs @@ -532,7 +532,7 @@ function getEditors(page, kind) { const elements = document.querySelectorAll(`.${aKind}Editor`); const results = []; for (const { id } of elements) { - results.push(parseInt(id.split("_").at(-1))); + results.push(parseInt(id.split("_").at(-1), 10)); } results.sort(); return results; diff --git a/web/app.js b/web/app.js index 4589b5f37..bd230a3ca 100644 --- a/web/app.js +++ b/web/app.js @@ -366,7 +366,7 @@ const PDFViewerApplication = { // Set some specific preferences for tests. if (typeof PDFJSDev !== "undefined" && PDFJSDev.test("TESTING")) { Object.assign(opts, { - capCanvasAreaFactor: x => parseInt(x), + capCanvasAreaFactor: x => parseInt(x, 10), docBaseUrl: x => x, enableAltText: x => x === "true", enableAutoLinking: x => x === "true", @@ -379,15 +379,15 @@ const PDFViewerApplication = { enableSplitMerge: x => x === "true", enableUpdatedAddImage: x => x === "true", highlightEditorColors: x => x, - imagesRightClickMinSize: x => parseInt(x), - maxCanvasPixels: x => parseInt(x), - spreadModeOnLoad: x => parseInt(x), + imagesRightClickMinSize: x => parseInt(x, 10), + maxCanvasPixels: x => parseInt(x, 10), + spreadModeOnLoad: x => parseInt(x, 10), supportsCaretBrowsingMode: x => x === "true", - viewerCssTheme: x => parseInt(x), + viewerCssTheme: x => parseInt(x, 10), forcePageColors: x => x === "true", pageColorsBackground: x => x, pageColorsForeground: x => x, - sidebarViewOnLoad: x => parseInt(x), + sidebarViewOnLoad: x => parseInt(x, 10), }); } diff --git a/web/caret_browsing.js b/web/caret_browsing.js index fbbc9c959..c5c9cc40e 100644 --- a/web/caret_browsing.js +++ b/web/caret_browsing.js @@ -237,7 +237,7 @@ class CaretBrowsingMode { #getNodeOnNextPage(textLayer, isUp) { while (true) { const page = textLayer.closest(".page"); - const pageNumber = parseInt(page.getAttribute("data-page-number")); + const pageNumber = parseInt(page.getAttribute("data-page-number"), 10); const nextPage = isUp ? pageNumber - 1 : pageNumber + 1; textLayer = this.#viewerContainer.querySelector( `.page[data-page-number="${nextPage}"] .textLayer` diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js index 1c005d69d..98e980bff 100644 --- a/web/pdf_thumbnail_viewer.js +++ b/web/pdf_thumbnail_viewer.js @@ -287,7 +287,8 @@ class PDFThumbnailViewer { parseInt( e.target .closest(".thumbnailImageContainer") - ?.parentElement.getAttribute("page-number") + ?.parentElement.getAttribute("page-number"), + 10 ) ?? -1, hasSelectedPages: !!this.#selectedPages?.size, canDeletePages: this.#canDelete(), diff --git a/web/signature_manager.js b/web/signature_manager.js index 935866101..749d1a48d 100644 --- a/web/signature_manager.js +++ b/web/signature_manager.js @@ -410,7 +410,7 @@ class SignatureManager { this.#drawCurves = { width: drawWidth, height: drawHeight, - thickness: parseInt(this.#drawThickness.value), + thickness: parseInt(this.#drawThickness.value, 10), curves: [], }; this.#disableButtons(true);