Refactor: Apply ESLint v9 formatting to all JS files#12299
Refactor: Apply ESLint v9 formatting to all JS files#12299harshgupta2125 wants to merge 11 commits intointernetarchive:masterfrom
Conversation
- Added Biome to handle all JS files for much faster linting. - Kept ESLint strictly for .vue files to avoid breaking anything. - Auto-formatted 158 JS files to match our current style rules. - Put it all in one single commit to make git-blame tracking easier.
for more information, see https://pre-commit.ci
There was a problem hiding this comment.
Pull request overview
This PR introduces a hybrid JS linting setup by adding Biome for .js/.mjs/.cjs files while restricting ESLint to Vue (.vue) to speed up linting and avoid template-parsing regressions.
Changes:
- Added Biome configuration + dependency for fast JS linting/formatting.
- Updated ESLint config with overrides intended to prevent conflicting formatting rules on JS files.
- Applied large-scale auto-formatting across JS/config/test files to match the new formatter output.
Reviewed changes
Copilot reviewed 152 out of 158 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| webpack.config.js | Formatting changes consistent with new JS formatter output. |
| webpack.config.css.js | Formatting changes consistent with new JS formatter output. |
| vue.config.js | Formatting changes consistent with new JS formatter output. |
| tests/unit/js/utils.test.js | Formatting/import ordering updates. |
| tests/unit/js/signup.test.js | Formatting updates. |
| tests/unit/js/setup.js | Formatting update (blank line). |
| tests/unit/js/search.test.js | Formatting updates + minor refactors for line wrapping. |
| tests/unit/js/sample-html/utils-test-data.js | Formatting updates (semicolons). |
| tests/unit/js/sample-html/lists-test-data.js | Formatting updates / line wrapping. |
| tests/unit/js/sample-html/dropper-test-data.js | Formatting updates (semicolons). |
| tests/unit/js/sample-html/checkIns-test-data.js | Formatting updates. |
| tests/unit/js/python.test.js | Formatting/import ordering updates. |
| tests/unit/js/jsdef.test.js | Formatting updates + callback style tweak. |
| tests/unit/js/jquery.repeat.test.js | Formatting/import ordering updates. |
| tests/unit/js/idValidation.test.js | Formatting/import ordering updates. |
| tests/unit/js/html-test-data.js | Formatting updates (semicolons). |
| tests/unit/js/editionsEditPage.test.js | Formatting updates + callback style tweak. |
| tests/unit/js/editionEditPageClassification.test.js | Formatting updates. |
| tests/unit/js/autocomplete.test.js | Formatting updates. |
| tests/unit/js/SelectionManager.test.js | Formatting update (removed blank line). |
| tests/unit/js/SearchUtils.test.js | Formatting updates. |
| tests/unit/js/SearchBar.test.js | Formatting updates + line wrapping. |
| tests/unit/js/Browser.test.js | Formatting/import ordering updates. |
| stories/Button.stories.js | Formatting updates (commas/semicolons/wrapping). |
| stories/.storybook/preview.js | Formatting updates (quotes/semicolons). |
| stories/.storybook/main.js | Formatting updates (JSON→JS style + trailing commas). |
| static/bookmarklets/import_webbook.js | Wrapped long window.open call for formatter compliance. |
| scripts/solr_restarter/index.js | Formatting updates; no intended logic changes. |
| scripts/gh_scripts/new_pr_labeler.mjs | Formatting updates + quote style changes. |
| package.json | Added @biomejs/biome devDependency. |
| openlibrary/plugins/openlibrary/js/waitlist.js | Formatting update (chaining). |
| openlibrary/plugins/openlibrary/js/utils.js | Formatting updates + changed own-property check. |
| openlibrary/plugins/openlibrary/js/template.js | Formatting updates + arrow function conversions. |
| openlibrary/plugins/openlibrary/js/team.js | Formatting updates / line wrapping. |
| openlibrary/plugins/openlibrary/js/tabs.js | Formatting update (arrow callback). |
| openlibrary/plugins/openlibrary/js/stats/index.js | Formatting updates (semicolons/wrapping). |
| openlibrary/plugins/openlibrary/js/star-ratings/index.js | Formatting updates + arrow callback conversions. |
| openlibrary/plugins/openlibrary/js/service-worker.js | Formatting/import ordering updates. |
| openlibrary/plugins/openlibrary/js/service-worker-matchers.js | Formatting updates + array formatting. |
| openlibrary/plugins/openlibrary/js/service-worker-init.js | Formatting updates + promise chain wrapping. |
| openlibrary/plugins/openlibrary/js/search.js | Formatting updates + wrapping long chains/objects. |
| openlibrary/plugins/openlibrary/js/return-form/index.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/private-button.js | Formatting updates + wrapped constructor call. |
| openlibrary/plugins/openlibrary/js/patron_exports.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/password-toggle.js | Formatting updates + wrapped assignment. |
| openlibrary/plugins/openlibrary/js/partner_ol_lib.js | Formatting updates + wrapped ternaries. |
| openlibrary/plugins/openlibrary/js/ol.js | Formatting updates + wrapped jQuery handlers. |
| openlibrary/plugins/openlibrary/js/ol.analytics.js | Formatting updates + arrow callback conversions. |
| openlibrary/plugins/openlibrary/js/offline-banner.js | Formatting update (removed blank line). |
| openlibrary/plugins/openlibrary/js/nonjquery_utils.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/native-dialog/index.js | Formatting updates + wrapped conditionals. |
| openlibrary/plugins/openlibrary/js/my-books/store/index.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/my-books/index.js | Formatting updates + wrapped long calls. |
| openlibrary/plugins/openlibrary/js/my-books/CreateListForm.js | Formatting updates + wrapped long calls. |
| openlibrary/plugins/openlibrary/js/merge.js | Formatting updates + callback conversions. |
| openlibrary/plugins/openlibrary/js/merge-request-table/index.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/merge-request-table/MergeRequestTable/TableHeader.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/merge-request-table/MergeRequestTable.js | Formatting updates + wrapped listeners. |
| openlibrary/plugins/openlibrary/js/merge-request-table/MergeRequestService.js | Formatting updates + wrapped function signature. |
| openlibrary/plugins/openlibrary/js/markdown-editor/index.js | Formatting updates + method chaining wrap. |
| openlibrary/plugins/openlibrary/js/lists/ListViewBody.js | Formatting updates + callback conversions. |
| openlibrary/plugins/openlibrary/js/lists/ListService.js | Formatting update (removed trailing blank line). |
| openlibrary/plugins/openlibrary/js/librarian-dashboard/index.js | Formatting updates + wrapped listener/options. |
| openlibrary/plugins/openlibrary/js/lazy-thing-preview.js | Formatting updates + wrapped fetch calls. |
| openlibrary/plugins/openlibrary/js/lazy-carousel.js | Formatting updates + wrapped observer/callbacks. |
| openlibrary/plugins/openlibrary/js/jsdef.js | Formatting updates + small expression simplifications. |
| openlibrary/plugins/openlibrary/js/jquery.repeat.js | Formatting updates + minor wrapping. |
| openlibrary/plugins/openlibrary/js/isbnOverride.js | Formatting updates + expanded object methods. |
| openlibrary/plugins/openlibrary/js/interstitial.js | Formatting updates + semicolons. |
| openlibrary/plugins/openlibrary/js/ile/utils/ol.js | Formatting updates + wrapped uniqBy usage. |
| openlibrary/plugins/openlibrary/js/ile/index.js | Formatting updates + TS directive adjustment. |
| openlibrary/plugins/openlibrary/js/idValidation.js | Formatting updates + wrapped expressions/returns. |
| openlibrary/plugins/openlibrary/js/ia_thirdparty_logins.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/i18n.js | Formatting updates + arrow callback. |
| openlibrary/plugins/openlibrary/js/graphs/options.js | Formatting updates + trailing commas. |
| openlibrary/plugins/openlibrary/js/graphs/index.js | Import order formatting update. |
| openlibrary/plugins/openlibrary/js/goodreads_import.js | Formatting updates + callback conversions. |
| openlibrary/plugins/openlibrary/js/go-back-links.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/fulltext-search-suggestion.js | Formatting updates + wrapped error/DOM operations. |
| openlibrary/plugins/openlibrary/js/following.js | Formatting updates + wrapped ternary. |
| openlibrary/plugins/openlibrary/js/editions-table/index.js | Formatting updates + wrapped options. |
| openlibrary/plugins/openlibrary/js/edition-nav-bar/index.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/edition-nav-bar/EditionNavBar.js | Formatting updates + wrapped conditions. |
| openlibrary/plugins/openlibrary/js/dropper/index.js | Formatting updates + wrapped debounce handlers. |
| openlibrary/plugins/openlibrary/js/dropper/Dropper.js | Formatting updates + wrapped args. |
| openlibrary/plugins/openlibrary/js/dialog.js | Formatting updates + wrapped configuration objects. |
| openlibrary/plugins/openlibrary/js/covers.js | Formatting updates + wrapped clipboard/paste logic. |
| openlibrary/plugins/openlibrary/js/compact-title/index.js | Formatting updates + wrapped animation callbacks. |
| openlibrary/plugins/openlibrary/js/clampers.js | Formatting updates + wrapped ternaries. |
| openlibrary/plugins/openlibrary/js/carousel/index.js | Formatting updates (but contains a this/arrow-function issue). |
| openlibrary/plugins/openlibrary/js/carousel/Carousel.js | Formatting updates + wrapped responsive options. |
| openlibrary/plugins/openlibrary/js/bulk-tagger/models/Tag.js | Formatting updates (but contains a property-name typo bug). |
| openlibrary/plugins/openlibrary/js/bulk-tagger/index.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/bulk-tagger/BulkTagger/SortedMenuOptionContainer.js | Formatting updates. |
| openlibrary/plugins/openlibrary/js/bulk-tagger/BulkTagger/MenuOption.js | Formatting updates + wrapped class manipulation. |
| openlibrary/plugins/openlibrary/js/book-page-lists.js | Formatting updates + wrapped IntersectionObserver usage. |
| openlibrary/plugins/openlibrary/js/banner/index.js | Formatting updates + wrapped JSON payload. |
| openlibrary/plugins/openlibrary/js/affiliate-links.js | Formatting updates + wrapped error handling. |
| openlibrary/plugins/openlibrary/js/admin.js | Formatting updates + callback conversions. |
| openlibrary/plugins/openlibrary/js/add_provider.js | Formatting updates + wrapped arrays/templates. |
| openlibrary/plugins/openlibrary/js/add-book.js | Formatting updates + wrapped conditions/calls. |
| openlibrary/plugins/openlibrary/js/Toast.js | Formatting updates + chaining. |
| openlibrary/plugins/openlibrary/js/SearchUtils.js | Formatting updates + wrapped arrow function. |
| openlibrary/plugins/openlibrary/js/SearchPage.js | Import order formatting update. |
| openlibrary/plugins/openlibrary/js/Browser.js | Formatting update (arrow callback). |
| openlibrary/components/vite.config.mjs | Formatting/import ordering updates + wrapped loops. |
| openlibrary/components/vite-lit.config.mjs | Formatting/import ordering updates. |
| openlibrary/components/rollupInputCore.js | Import order formatting update. |
| openlibrary/components/lit/index.js | Export order formatting update. |
| openlibrary/components/lit/OlPagination.js | Formatting updates + line wrapping. |
| openlibrary/components/lit/OLReadMore.js | Formatting updates. |
| openlibrary/components/lit/OLChipGroup.js | Formatting updates. |
| openlibrary/components/lit/OLChip.js | Formatting updates + wrapped dispatch. |
| openlibrary/components/dev/vite.config.js | Formatting updates. |
| openlibrary/components/dev/serve-component.js | Formatting updates. |
| openlibrary/components/configs.js | Formatting updates + wrapped const assignment/loop. |
| openlibrary/components/ObservationForm/Utils.js | Formatting updates + wrapped conditional. |
| openlibrary/components/ObservationForm/ObservationService.js | Formatting updates + headers/body trailing commas. |
| openlibrary/components/LibraryExplorer/utils/lcc.js | Formatting updates + wrapped regex config. |
| openlibrary/components/LibraryExplorer/utils.js | Formatting updates + wrapped function signature/ternary. |
| openlibrary/components/IdentifiersInput/utils/utils.js | Formatting updates + wrapped error messages. |
| openlibrary/components/BulkSearch/utils/searchUtils.js | Formatting updates + wrapped regex replace and guards. |
| openlibrary/components/BarcodeScanner/utils/classes.js | Formatting/import ordering updates + wrapped conditionals. |
| conf/svgo.config.js | Formatting update (trailing commas / indentation). |
| biome.json | Added Biome config for JS lint/format rules. |
| .eslintrc.json | Added overrides intended to disable formatting rules on JS files. |
.eslintrc.json
Outdated
| "overrides": [ | ||
| { | ||
| "files": ["*.js", "*.mjs", "*.cjs"], | ||
| "rules": { | ||
| "semi": "off", | ||
| "quotes": "off", | ||
| "indent": "off", | ||
| "no-extra-semi": "off", | ||
| "no-mixed-spaces-and-tabs": "off", | ||
| "no-trailing-spaces": "off", | ||
| "keyword-spacing": "off", | ||
| "key-spacing": "off" | ||
| } | ||
| } | ||
| ] |
There was a problem hiding this comment.
"files": [".js", ".mjs", ".cjs"] only matches JS files in the repo root, so ESLint formatting rules will still apply to JS files in subdirectories (where most JS lives). Use a recursive glob (e.g., "**/.js") or a single pattern like "**/*.{js,mjs,cjs}" so the hybrid-linter setup actually prevents rule conflicts across the whole project.
| } | ||
| // Iterate over the params object and update/add each parameter | ||
| for (const key in params) { | ||
| if (Object.hasOwn(params, key)) { |
There was a problem hiding this comment.
Object.hasOwn is a relatively new built-in and can break in older browsers/environments without the right polyfills. To preserve broad compatibility, prefer Object.prototype.hasOwnProperty.call(params, key) (or keep params.hasOwnProperty(key) if params is always a plain object).
| if (Object.hasOwn(params, key)) { | |
| if (Object.prototype.hasOwnProperty.call(params, key)) { |
| elemSlides.forEach((slide) => { | ||
| const $slide = $(slide); | ||
| if ($slide.attr('aria-describedby') !== undefined) { | ||
| $slide.attr('id', $(this).attr('aria-describedby')); |
There was a problem hiding this comment.
Inside the arrow callback, "this" is not the slide element, so $(this).attr('aria-describedby') will be undefined and IDs won't be set correctly. Use $slide (or slide) to read aria-describedby, e.g. set id from $slide.attr('aria-describedby') (or slide.getAttribute('aria-describedby')).
| $slide.attr('id', $(this).attr('aria-describedby')); | |
| $slide.attr('id', $slide.attr('aria-describedby')); |
| } else { | ||
| if (lowerA.tagType < lowerB.tagType) { | ||
| return -1; | ||
| } else if (lowerA.tagType > lowerB.tagtype) { |
There was a problem hiding this comment.
lowerB.tagtype is a typo (should be lowerB.tagType). As written, the comparison will be against undefined, causing incorrect ordering when tagName matches and tagType differs.
| } else if (lowerA.tagType > lowerB.tagtype) { | |
| } else if (lowerA.tagType > lowerB.tagType) { |
| alert('No image found in clipboard'); | ||
| } catch (error) {} | ||
| } |
There was a problem hiding this comment.
The catch block swallows clipboard/read errors silently, which makes failures hard to diagnose (and can leave the UI in a confusing state). At minimum, log the error (or surface a user-visible message) so users know why paste failed and developers can debug in production.
| .attr('href', 'javascript:;') | ||
| .on('click', () => $.fn.colorbox.close()); |
There was a problem hiding this comment.
Setting href="javascript:;" is discouraged because it can conflict with CSP and is generally considered an unsafe pattern. Prefer using a element for the closer, or set href="#" and call preventDefault in the click handler.
| .attr('href', 'javascript:;') | |
| .on('click', () => $.fn.colorbox.close()); | |
| .attr('href', '#') | |
| .on('click', (e) => { | |
| e.preventDefault(); | |
| $.fn.colorbox.close(); | |
| }); |
| navigator.serviceWorker | ||
| .register('/sw.js') | ||
| .then(() => {}) | ||
| .catch((error) => { | ||
| // eslint-disable-next-line no-console | ||
| console.error(`Service worker registration failed: ${error}`); | ||
| }); |
There was a problem hiding this comment.
The empty .then(() => {}) adds noise without changing behavior. Consider removing it (or replace it with a meaningful success action/log if needed).
- Updated ESLint glob patterns to properly target subdirectories. - Reverted Object.hasOwn to Object.prototype.hasOwnProperty for browser compatibility. - Fixed jQuery 'this' context in carousel arrow function. - Fixed tagType typo in bulk-tagger. - Resolved empty catch blocks and unsafe href attributes.
| return -1; | ||
| } else if (lowerA.tagType > lowerB.tagType) { | ||
| return 1; |
There was a problem hiding this comment.
lowerB.tagtype is a typo and will always be undefined, which breaks tag ordering when tag names match (and can cause inconsistent sort results). Change it to lowerB.tagType so the comparison is correct.
| this._store = { | ||
| droppers: [], | ||
| showcases: [], | ||
| userkey: '', |
There was a problem hiding this comment.
The store initializes userkey, but the accessor uses userKey. This makes getUserKey() return undefined until setUserKey() runs, and creates two different keys on the store object. Rename the initial property to userKey to match the getters/setters.
| userkey: '', | |
| userKey: '', |
| * @returns {string} | ||
| */ | ||
| getUserKey() { | ||
| return this._store.userKey; |
There was a problem hiding this comment.
The store initializes userkey, but the accessor uses userKey. This makes getUserKey() return undefined until setUserKey() runs, and creates two different keys on the store object. Rename the initial property to userKey to match the getters/setters.
.eslintrc.json
Outdated
| "overrides": [ | ||
| { | ||
| "files": ["**/*.js", "**/*.mjs", "**/*.cjs"], | ||
| "rules": { | ||
| "semi": "off", | ||
| "quotes": "off", | ||
| "indent": "off", | ||
| "no-extra-semi": "off", | ||
| "no-mixed-spaces-and-tabs": "off", | ||
| "no-trailing-spaces": "off", | ||
| "keyword-spacing": "off", | ||
| "key-spacing": "off" | ||
| } |
There was a problem hiding this comment.
The PR description says “Kept ESLint strictly for .vue files”, but this override only disables a handful of formatting rules for JS—it does not prevent ESLint from linting JS (e.g., no-undef, no-unused-vars, etc.) if the lint command still targets *.js. To align behavior with the description, update the lint invocation/ignore config to run ESLint only on **/*.vue (or add an .eslintignore that excludes *.js/*.mjs/*.cjs).
| */ | ||
| function renderRetryLink() { | ||
| return '<span class="affiliate-links-section__retry">Failed to fetch affiliate links. <a href="javascript:;">Retry?</a></span>' | ||
| return '<span class="affiliate-links-section__retry">Failed to fetch affiliate links. <a href="javascript:;">Retry?</a></span>'; |
There was a problem hiding this comment.
Using href="javascript:;" is discouraged (CSP-hostile and can become an injection sink). Prefer rendering a <button type="button">Retry?</button> or an <a href="#"> with preventDefault() in the click handler.
| return '<span class="affiliate-links-section__retry">Failed to fetch affiliate links. <a href="javascript:;">Retry?</a></span>'; | |
| return '<span class="affiliate-links-section__retry">Failed to fetch affiliate links. <button type="button">Retry?</button></span>'; |
| */ | ||
| function renderRetryLink() { | ||
| return '<span class="fulltext-suggestions__retry">Failed to fetch fulltext search suggestions. <a href="javascript:;">Retry?</a></span>' | ||
| return '<span class="fulltext-suggestions__retry">Failed to fetch fulltext search suggestions. <a href="javascript:;">Retry?</a></span>'; |
There was a problem hiding this comment.
Same issue as elsewhere: href="javascript:;" should be avoided. Use a <button> element (or href="#" + preventDefault) and keep behavior in JS.
| button.addEventListener('click', (event) => { | ||
| event.preventDefault(); | ||
| const toast = new FadingToast( | ||
| 'This patron has not enabled following', |
There was a problem hiding this comment.
This toast message is user-facing and should be translatable. Wrap the string in the project’s i18n/translation helper rather than hard-coding English.
| 'This patron has not enabled following', | |
| window.gettext('This patron has not enabled following'), |
RayBB
left a comment
There was a problem hiding this comment.
Thanks for putting this together. It looks really promising, and I think it’s a great start.
My main concern is still how we’ll exclude the files we do not want this to run on.
It also seems like this change is a bit larger than expected, although that may not be a big issue if we’re confident the settings match our current ESLint setup as closely as possible.
Are there any ESLint settings we currently rely on that you have not been able to match in Biome?
Also, please make sure to address all of the feedback from GitHub Copilot directly in your response.
|
Thanks for the encouragement! Your concerns are totally valid, so here is a quick breakdown of how I addressed them:
We aren't losing any non-formatting ESLint rules for JS.
|
500edaa to
67781f2
Compare
RayBB
left a comment
There was a problem hiding this comment.
We want the rule to be enabled for all those files, not just applying it one time. Otherwise they'll get out of sync again soon. Do you see a way to do that?
It seems it should be something like:
// eslint.config.js
export default [
{
// 1. Global settings or recommended configs
rules: {
"no-console": "error",
}
},
{
// 2. Specific override for certain files
files: ["**/tests/**/*.js", "**/scripts/*.js"],
rules: {
"no-console": "off", // Rule is disabled only for these files
},
},
];for more information, see https://pre-commit.ci
|
I added the override block at the bottom for the 101 locked files exactly as you suggested. I also ran --fix across the rest of the codebase and we are officially down to 0 linting errors. It should be totally clean and ready for a fresh review whenever you have a minute! |
Closes #12289
Refactor: Apply ESLint v9 formatting to all JS files
Summary
.js,.mjs, and.cjsfiles to strictly use the project's official ESLint v9 configuration.Technical
tagTypetypo,userKeyproperty name, CSP-safe links, i18n implementation)..git-blame-ignore-revsto preserve a cleangit blamehistory.Testing
npm installto ensure your local packages are up to date.npm run lint:jsto verify the codebase passes the new ESLint v9 checks.Screenshot
NA
Stakeholders
@RayBB