From 046e68d140931100c0947baec32be1f246a5a50b Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Sun, 28 Jun 2026 15:08:33 +0200 Subject: [PATCH] Extend the `unicorn/logical-assignment-operators` rule to if-statements Please see https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/logical-assignment-operators.md and https://eslint.org/docs/latest/rules/logical-assignment-operators#enforceforifstatements --- eslint.config.mjs | 2 +- src/core/annotation.js | 16 ++++++---------- src/core/ccitt_stream.js | 8 +++----- src/core/cff_parser.js | 14 ++++++-------- src/core/colorspace_utils.js | 4 +--- src/core/fonts_utils.js | 5 ++--- src/core/xfa/factory.js | 8 +++----- src/core/xfa/fonts.js | 9 ++------- src/core/xfa/xfa_object.js | 4 +--- src/core/xref.js | 9 +++------ src/display/annotation_layer.js | 4 +--- src/display/editor/stamp.js | 10 ++++------ src/scripting_api/field.js | 18 ++++-------------- src/scripting_api/util.js | 8 ++------ test/driver.js | 4 +--- test/test.mjs | 9 +++------ web/app.js | 8 +++----- web/chromecom.js | 9 ++++----- web/pdf_thumbnail_viewer.js | 4 +--- 19 files changed, 51 insertions(+), 102 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 4c992fe6e..d3a09666f 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -181,7 +181,7 @@ export default [ "unicorn/logical-assignment-operators": [ "error", "always", - { enforceForIfStatements: false }, + { enforceForIfStatements: true }, ], "unicorn/prefer-logical-operator-over-ternary": "error", "unicorn/prefer-modern-dom-apis": "error", diff --git a/src/core/annotation.js b/src/core/annotation.js index 232c21ec5..6948ddf2f 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -3318,13 +3318,11 @@ class ButtonWidgetAnnotation extends WidgetAnnotation { return super.getOperatorList(evaluator, task, intent, annotationStorage); } - if (value === null || value === undefined) { - // There is no default appearance so use the one derived - // from the field value. - value = this.data.checkBox - ? this.data.fieldValue === this.data.exportValue - : this.data.fieldValue === this.data.buttonValue; - } + // There is no default appearance, `value === null || value === undefined`, + // so use the one derived from the field value. + value ??= this.data.checkBox + ? this.data.fieldValue === this.data.exportValue + : this.data.fieldValue === this.data.buttonValue; return this.#getOperatorListForAppearance( evaluator, @@ -4716,9 +4714,7 @@ class PolylineAnnotation extends MarkupAnnotation { const strokeAlpha = dict.get("CA"); let fillColor = getRgbColor(dict.getArray("IC"), null); - if (fillColor) { - fillColor = getPdfColorArray(fillColor); - } + fillColor &&= getPdfColorArray(fillColor); let operator; if (fillColor) { diff --git a/src/core/ccitt_stream.js b/src/core/ccitt_stream.js index 0f50364dc..9ccba4c34 100644 --- a/src/core/ccitt_stream.js +++ b/src/core/ccitt_stream.js @@ -58,11 +58,9 @@ class CCITTFaxStream extends DecodeStream { if (this.eof) { return this.buffer; } - if (!bytes) { - bytes = this.stream.isAsync - ? (await this.stream.asyncGetBytes()) || this.bytes - : this.bytes; - } + bytes ??= this.stream.isAsync + ? (await this.stream.asyncGetBytes()) || this.bytes + : this.bytes; this.buffer = await JBig2CCITTFaxImage.instance.decode( bytes, diff --git a/src/core/cff_parser.js b/src/core/cff_parser.js index 2a78c79e5..3ecfe1248 100644 --- a/src/core/cff_parser.js +++ b/src/core/cff_parser.js @@ -775,14 +775,12 @@ class CFFParser { } else if (localSubrIndex) { localSubrToUse = localSubrIndex; } - if (valid) { - valid = this.parseCharString( - state, - charstring, - localSubrToUse, - globalSubrIndex - ); - } + valid &&= this.parseCharString( + state, + charstring, + localSubrToUse, + globalSubrIndex + ); if (state.width !== null) { const nominalWidth = privateDictToUse.getByName("nominalWidthX"); widths[i] = nominalWidth + state.width; diff --git a/src/core/colorspace_utils.js b/src/core/colorspace_utils.js index 0113f537b..d9cd707d8 100644 --- a/src/core/colorspace_utils.js +++ b/src/core/colorspace_utils.js @@ -243,9 +243,7 @@ class ColorSpaceUtils { break; case "Pattern": baseCS = cs[1] || null; - if (baseCS) { - baseCS = this.#subParse(baseCS, options); - } + baseCS &&= this.#subParse(baseCS, options); return new PatternCS(baseCS); case "I": case "Indexed": diff --git a/src/core/fonts_utils.js b/src/core/fonts_utils.js index a443a4e1a..550ab3cd4 100644 --- a/src/core/fonts_utils.js +++ b/src/core/fonts_utils.js @@ -151,9 +151,8 @@ function type1FontGlyphMapping(properties, builtInEncoding, glyphNames) { glyphId = glyphNames.indexOf(glyphName); if (glyphId === -1) { - if (!glyphsUnicodeMap) { - glyphsUnicodeMap = getGlyphsUnicode(); - } + glyphsUnicodeMap ??= getGlyphsUnicode(); + const standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap); if (standardGlyphName !== glyphName) { glyphId = glyphNames.indexOf(standardGlyphName); diff --git a/src/core/xfa/factory.js b/src/core/xfa/factory.js index 930b8a071..151f4d01a 100644 --- a/src/core/xfa/factory.js +++ b/src/core/xfa/factory.js @@ -160,11 +160,9 @@ class XFAFactory { const { html } = result; const { attributes } = html; if (attributes) { - if (attributes.class) { - attributes.class = attributes.class.filter( - attr => !attr.startsWith("xfa") - ); - } + attributes.class &&= attributes.class.filter( + attr => !attr.startsWith("xfa") + ); attributes.dir = "auto"; } diff --git a/src/core/xfa/fonts.js b/src/core/xfa/fonts.js index 897b4bb40..e14b6442d 100644 --- a/src/core/xfa/fonts.js +++ b/src/core/xfa/fonts.js @@ -31,9 +31,7 @@ class FontFinder { this.addPdfFont(pdfFont); } for (const pdfFont of this.fonts.values()) { - if (!pdfFont.regular) { - pdfFont.regular = pdfFont.italic || pdfFont.bold || pdfFont.bolditalic; - } + pdfFont.regular ||= pdfFont.italic || pdfFont.bold || pdfFont.bolditalic; } if (!reallyMissingFonts || reallyMissingFonts.size === 0) { @@ -72,10 +70,7 @@ class FontFinder { property += "italic"; } } - - if (!property) { - property = "regular"; - } + property ||= "regular"; font[property] = pdfFont; } diff --git a/src/core/xfa/xfa_object.js b/src/core/xfa/xfa_object.js index 9938fceb3..9a3ac1ac7 100644 --- a/src/core/xfa/xfa_object.js +++ b/src/core/xfa/xfa_object.js @@ -518,9 +518,7 @@ class XFAObject { true /* = dotDotAllowed */, false /* = useCache */ ); - if (proto) { - proto = proto[0]; - } + proto &&= proto[0]; } if (!proto) { diff --git a/src/core/xref.js b/src/core/xref.js index 0cfedc40f..e2b69a48d 100644 --- a/src/core/xref.js +++ b/src/core/xref.js @@ -740,9 +740,7 @@ class XRef { if (isCmd(obj, "xref")) { // Parse end-of-file XRef dict = this.processXRefTable(parser); - if (!this.topDict) { - this.topDict = dict; - } + this.topDict ||= dict; // Recursively get other XRefs 'XRefStm', if any obj = dict.get("XRefStm"); @@ -762,9 +760,8 @@ class XRef { throw new FormatError("Invalid XRef stream"); } dict = this.processXRefStream(obj); - if (!this.topDict) { - this.topDict = dict; - } + this.topDict ||= dict; + if (!dict) { throw new FormatError("Failed to read XRef stream"); } diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index a44c9cfc7..bb04e2d2d 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -1187,10 +1187,8 @@ class LinkAnnotationElement extends AnnotationElement { if (data.overlaidText) { link.title = data.overlaidText; } + link.onclick ||= () => false; - if (!link.onclick) { - link.onclick = () => false; - } this.#setInternalLink(); } diff --git a/src/display/editor/stamp.js b/src/display/editor/stamp.js index e9fe98d5e..c8bb07c40 100644 --- a/src/display/editor/stamp.js +++ b/src/display/editor/stamp.js @@ -488,12 +488,10 @@ class StampEditor extends AnnotationEditor { } copyCanvas(maxDataDimension, maxPreviewDimension, createImageData = false) { - if (!maxDataDimension) { - // TODO: get this value from Firefox - // (https://bugzilla.mozilla.org/show_bug.cgi?id=1908184) - // It's the maximum dimension that the AI can handle. - maxDataDimension = 224; - } + // TODO: get this value from Firefox + // (https://bugzilla.mozilla.org/show_bug.cgi?id=1908184) + // It's the maximum dimension that the AI can handle. + maxDataDimension ||= 224; const { width: bitmapWidth, height: bitmapHeight } = this.#bitmap; const outputScale = new OutputScale(); diff --git a/src/scripting_api/field.js b/src/scripting_api/field.js index 0834bc6bb..4f0994fd2 100644 --- a/src/scripting_api/field.js +++ b/src/scripting_api/field.js @@ -334,17 +334,11 @@ class Field extends PDFObject { } buttonGetCaption(nFace = 0) { - if (this._buttonCaption) { - return this._buttonCaption[nFace]; - } - return ""; + return this._buttonCaption ? this._buttonCaption[nFace] : ""; } buttonGetIcon(nFace = 0) { - if (this._buttonIcon) { - return this._buttonIcon[nFace]; - } - return null; + return this._buttonIcon ? this._buttonIcon[nFace] : null; } buttonImportIcon(cPath = null, nPave = 0) { @@ -352,9 +346,7 @@ class Field extends PDFObject { } buttonSetCaption(cCaption, nFace = 0) { - if (!this._buttonCaption) { - this._buttonCaption = ["", "", ""]; - } + this._buttonCaption ??= ["", "", ""]; this._buttonCaption[nFace] = cCaption; // TODO: send to the annotation layer // Right now the button is drawn on the canvas using its appearance so @@ -363,9 +355,7 @@ class Field extends PDFObject { } buttonSetIcon(oIcon, nFace = 0) { - if (!this._buttonIcon) { - this._buttonIcon = [null, null, null]; - } + this._buttonIcon ??= [null, null, null]; this._buttonIcon[nFace] = oIcon; } diff --git a/src/scripting_api/util.js b/src/scripting_api/util.js index 7aeb79737..4102b464a 100644 --- a/src/scripting_api/util.js +++ b/src/scripting_api/util.js @@ -119,9 +119,7 @@ class Util extends PDFObject { } cFlags = flags; - if (nWidth) { - nWidth = parseInt(nWidth); - } + nWidth &&= parseInt(nWidth); let intPart = Math.trunc(arg); @@ -136,9 +134,7 @@ class Util extends PDFObject { return hex; } - if (nPrecision) { - nPrecision = parseInt(nPrecision.substring(1)); - } + nPrecision &&= parseInt(nPrecision.substring(1)); nDecSep = nDecSep ? nDecSep.substring(1) : "0"; const separators = { diff --git a/test/driver.js b/test/driver.js index 473f1ef81..7ba6d6a8c 100644 --- a/test/driver.js +++ b/test/driver.js @@ -968,9 +968,7 @@ class Driver { if (task.type === "other" || task.enableXfa) { return; } - if (!task._prefetchedLoadingTask) { - task._prefetchedLoadingTask = getDocument(this._getDocumentOptions(task)); - } + task._prefetchedLoadingTask ??= getDocument(this._getDocumentOptions(task)); } _cleanup() { diff --git a/test/test.mjs b/test/test.mjs index a2a1a733b..b38ead755 100644 --- a/test/test.mjs +++ b/test/test.mjs @@ -801,9 +801,8 @@ async function handleWsBinaryResult(data) { if (!taskResults) { return; } - if (!taskResults[round]) { - taskResults[round] = []; - } + taskResults[round] ||= []; + if (taskResults[round][page - 1]) { console.error( `Results for ${browser}:${id}:${round}:${page - 1} were already submitted` @@ -1010,9 +1009,7 @@ async function startBrowser({ protocolTimeout: 0.75 * /* jasmine.DEFAULT_TIMEOUT_INTERVAL = */ 30000, }; - if (!tempDir) { - tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "pdfjs-")); - } + tempDir ||= fs.mkdtempSync(path.join(os.tmpdir(), "pdfjs-")); const printFile = path.join(tempDir, "print.pdf"); if (browserName === "chrome") { diff --git a/web/app.js b/web/app.js index a4bb42c9e..104bd2cca 100644 --- a/web/app.js +++ b/web/app.js @@ -2068,11 +2068,9 @@ const PDFViewerApplication = { ); this.secondaryToolbar?.setPageNumber(this.pdfViewer.currentPageNumber); - if (!this.pdfViewer.currentScaleValue) { - // Scale was not initialized: invalid bookmark or scale was not specified. - // Setting the default one. - this.pdfViewer.currentScaleValue = DEFAULT_SCALE_VALUE; - } + // Scale was not initialized: invalid bookmark or scale was not specified. + // Setting the default one. + this.pdfViewer.currentScaleValue ||= DEFAULT_SCALE_VALUE; }, /** diff --git a/web/chromecom.js b/web/chromecom.js index 1ff578556..5d91756a2 100644 --- a/web/chromecom.js +++ b/web/chromecom.js @@ -272,11 +272,10 @@ let port; // 4. Page: Invoke callback. function setReferer(url, callback) { dnrRequestId ??= crypto.getRandomValues(new Uint32Array(1))[0] % 0x80000000; - if (!port) { - // The background page will accept the port, and keep adding the Referer - // request header to requests to |url| until the port is disconnected. - port = chrome.runtime.connect({ name: "chromecom-referrer" }); - } + // The background page will accept the port, and keep adding the Referer + // request header to requests to |url| until the port is disconnected. + port ??= chrome.runtime.connect({ name: "chromecom-referrer" }); + port.onDisconnect.addListener(onDisconnect); port.onMessage.addListener(onMessage); // Initiate the information exchange. diff --git a/web/pdf_thumbnail_viewer.js b/web/pdf_thumbnail_viewer.js index b31e8d87d..478f9abe0 100644 --- a/web/pdf_thumbnail_viewer.js +++ b/web/pdf_thumbnail_viewer.js @@ -1854,9 +1854,7 @@ class PDFThumbnailViewer { break; } } - if (!nextThumbnail) { - nextThumbnail = firstWithDifferentY; - } + nextThumbnail ??= firstWithDifferentY; } if (nextThumbnail) { this.#focusThumbnailElement(nextThumbnail, navigateCheckboxes);