From 2f65ccd114ce8bcfa1dcc5707dda8697910e08e8 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:53:09 -0400 Subject: [PATCH 01/10] fix wheel event handler Violation in Chromium by setting passive: true --- src/lib/events.js | 43 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/src/lib/events.js b/src/lib/events.js index 6202ece21ef..3b1d990bd92 100644 --- a/src/lib/events.js +++ b/src/lib/events.js @@ -59,15 +59,9 @@ var Events = { internalEv.emit(event, data); }; - /* - * Add a dummy event handler for 'wheel' event for Safari - * to enable mouse wheel zoom. - * https://github.com/d3/d3/issues/3035 - * https://github.com/plotly/plotly.js/issues/7452 - */ - if(typeof plotObj.addEventListener === 'function') { - plotObj.addEventListener("wheel", () => {}); - } + // Add a dummy event handler for 'wheel' event for Safari + // to enable mouse wheel zoom. + addDummyScrollEventListener(plotObj); return plotObj; }, @@ -140,4 +134,35 @@ var Events = { }; +function addDummyScrollEventListener(plotObj) { + /* + * Add a dummy event handler for 'wheel' event for Safari + * to enable mouse wheel zoom. + * https://github.com/d3/d3/issues/3035 + * https://github.com/plotly/plotly.js/issues/7452 + * + * We set {passive: true} for better performance + * and to avoid a Violation warning in Chromium. + * https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + * https://github.com/plotly/plotly.js/issues/7516 + */ + + // Test whether the passive property is accessed (for compatibility with older browsers) + var supportsPassive = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function() { + supportsPassive = true; + } + }); + window.addEventListener("testPassive", null, opts); + window.removeEventListener("testPassive", null, opts); + } catch (e) {} + + if(typeof plotObj.addEventListener === 'function') { + plotObj.addEventListener("wheel", () => {}, supportsPassive ? { passive: true } : false); + } + +} + module.exports = Events; From 4054a618d998a9781832b69d7b7a081f48eb64a6 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Mon, 11 Aug 2025 11:37:43 -0400 Subject: [PATCH 02/10] simplify by removing handling for very old browsers --- src/lib/events.js | 48 ++++++++++++++--------------------------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/src/lib/events.js b/src/lib/events.js index 3b1d990bd92..725ff59791d 100644 --- a/src/lib/events.js +++ b/src/lib/events.js @@ -59,9 +59,20 @@ var Events = { internalEv.emit(event, data); }; - // Add a dummy event handler for 'wheel' event for Safari - // to enable mouse wheel zoom. - addDummyScrollEventListener(plotObj); + /* + * Add a dummy event handler for 'wheel' event for Safari + * to enable mouse wheel zoom. + * https://github.com/d3/d3/issues/3035 + * https://github.com/plotly/plotly.js/issues/7452 + * + * We set {passive: true} for better performance + * and to avoid a Violation warning in Chromium. + * https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + * https://github.com/plotly/plotly.js/issues/7516 + */ + if(typeof plotObj.addEventListener === 'function') { + plotObj.addEventListener("wheel", () => {}, { passive: true }); + } return plotObj; }, @@ -134,35 +145,4 @@ var Events = { }; -function addDummyScrollEventListener(plotObj) { - /* - * Add a dummy event handler for 'wheel' event for Safari - * to enable mouse wheel zoom. - * https://github.com/d3/d3/issues/3035 - * https://github.com/plotly/plotly.js/issues/7452 - * - * We set {passive: true} for better performance - * and to avoid a Violation warning in Chromium. - * https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md - * https://github.com/plotly/plotly.js/issues/7516 - */ - - // Test whether the passive property is accessed (for compatibility with older browsers) - var supportsPassive = false; - try { - var opts = Object.defineProperty({}, 'passive', { - get: function() { - supportsPassive = true; - } - }); - window.addEventListener("testPassive", null, opts); - window.removeEventListener("testPassive", null, opts); - } catch (e) {} - - if(typeof plotObj.addEventListener === 'function') { - plotObj.addEventListener("wheel", () => {}, supportsPassive ? { passive: true } : false); - } - -} - module.exports = Events; From 040bdc110b6c3950d5e3599ddd3fcbac02bc85a5 Mon Sep 17 00:00:00 2001 From: Emily KL <4672118+emilykl@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:17:31 -0400 Subject: [PATCH 03/10] only show locationmode warning if locationmode is 'country names' --- src/traces/choropleth/defaults.js | 10 ++++++++++ src/traces/choropleth/plot.js | 11 ----------- src/traces/scattergeo/defaults.js | 10 ++++++++++ src/traces/scattergeo/plot.js | 11 ----------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/traces/choropleth/defaults.js b/src/traces/choropleth/defaults.js index b6b1a82e418..af94097d5a0 100644 --- a/src/traces/choropleth/defaults.js +++ b/src/traces/choropleth/defaults.js @@ -4,6 +4,12 @@ var Lib = require('../../lib'); var colorscaleDefaults = require('../../components/colorscale/defaults'); var attributes = require('./attributes'); +const locationmodeBreakingChangeWarning = [ + 'The library used by the *country names* `locationmode` option is changing in the next major version.', + 'Some country names in existing plots may not work in the new version.', + 'To ensure consistent behavior, consider setting `locationmode` to *ISO-3*.', +].join(' '); + module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { function coerce(attr, dflt) { return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); @@ -28,6 +34,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout var locationMode = coerce('locationmode', locationmodeDflt); + if(locationMode === 'country names') { + Lib.warn(locationmodeBreakingChangeWarning); + } + if(locationMode === 'geojson-id') { coerce('featureidkey'); } diff --git a/src/traces/choropleth/plot.js b/src/traces/choropleth/plot.js index bf99852986c..da27bf17d78 100644 --- a/src/traces/choropleth/plot.js +++ b/src/traces/choropleth/plot.js @@ -9,18 +9,7 @@ var findExtremes = require('../../plots/cartesian/autorange').findExtremes; var style = require('./style').style; -const breakingChangeWarning = [ - 'The library used by the *country names* `locationmode` option is changing in an upcoming version.', - 'Country names in existing plots may not work in the new version.' -].join(' '); -let firstPlot = true; - function plot(gd, geo, calcData) { - if(firstPlot) { - firstPlot = false; - Lib.warn(breakingChangeWarning); - } - var choroplethLayer = geo.layers.backplot.select('.choroplethlayer'); Lib.makeTraceGroups(choroplethLayer, calcData, 'trace choropleth').each(function(calcTrace) { diff --git a/src/traces/scattergeo/defaults.js b/src/traces/scattergeo/defaults.js index 6f8adb11d98..f2a1ad9b9d8 100644 --- a/src/traces/scattergeo/defaults.js +++ b/src/traces/scattergeo/defaults.js @@ -10,6 +10,12 @@ var handleFillColorDefaults = require('../scatter/fillcolor_defaults'); var attributes = require('./attributes'); +const locationmodeBreakingChangeWarning = [ + 'The library used by the *country names* `locationmode` option is changing in the next major version.', + 'Some country names in existing plots may not work in the new version.', + 'To ensure consistent behavior, consider setting `locationmode` to *ISO-3*.', +].join(' '); + module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) { function coerce(attr, dflt) { return Lib.coerce(traceIn, traceOut, attributes, attr, dflt); @@ -27,6 +33,10 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout var locationMode = coerce('locationmode', locationmodeDflt); + if(locationMode === 'country names') { + Lib.warn(locationmodeBreakingChangeWarning); + } + if(locationMode === 'geojson-id') { coerce('featureidkey'); } diff --git a/src/traces/scattergeo/plot.js b/src/traces/scattergeo/plot.js index 284bb0093d1..9124900e8b3 100644 --- a/src/traces/scattergeo/plot.js +++ b/src/traces/scattergeo/plot.js @@ -13,18 +13,7 @@ var calcMarkerSize = require('../scatter/calc').calcMarkerSize; var subTypes = require('../scatter/subtypes'); var style = require('./style'); -const breakingChangeWarning = [ - 'The library used by the *country names* `locationmode` option is changing in an upcoming version.', - 'Country names in existing plots may not work in the new version.' -].join(' '); -let firstPlot = true; - function plot(gd, geo, calcData) { - if(firstPlot) { - firstPlot = false; - Lib.warn(breakingChangeWarning); - } - var scatterLayer = geo.layers.frontplot.select('.scatterlayer'); var gTraces = Lib.makeTraceGroups(scatterLayer, calcData, 'trace scattergeo'); From 727f913bfc861187c436f59c31f9a17bb12fca6f Mon Sep 17 00:00:00 2001 From: Davi Barbosa Date: Thu, 14 Aug 2025 23:44:34 -0300 Subject: [PATCH 04/10] Refactor title and subtitle selection in drawMainTitle function to use context-specific selection from the graph div (gd). --- src/plot_api/subroutines.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 85b96ffec5c..7cb735ce338 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -428,8 +428,8 @@ exports.drawMainTitle = function(gd) { }); if(title.text && title.automargin) { - var titleObj = d3.selectAll('.gtitle'); - var titleHeight = Drawing.bBox(d3.selectAll('.g-gtitle').node()).height; + var titleObj = d3.select(gd).selectAll('.gtitle'); + var titleHeight = Drawing.bBox(d3.select(gd).selectAll('.g-gtitle').node()).height; var pushMargin = needsMarginPush(gd, title, titleHeight); if(pushMargin > 0) { applyTitleAutoMargin(gd, y, pushMargin, titleHeight); @@ -455,7 +455,7 @@ exports.drawMainTitle = function(gd) { } // If there is a subtitle - var subtitleObj = d3.selectAll('.gtitle-subtitle'); + var subtitleObj = d3.select(gd).selectAll('.gtitle-subtitle'); if(subtitleObj.node()) { // Get bottom edge of title bounding box var titleBB = titleObj.node().getBBox(); From 0b1d6c9ba03a00bc30ba152fefda5d399ba01553 Mon Sep 17 00:00:00 2001 From: Davi Barbosa Date: Fri, 15 Aug 2025 00:22:44 -0300 Subject: [PATCH 05/10] Update draftlog for PR #7522 --- draftlogs/7522_fix.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/7522_fix.md diff --git a/draftlogs/7522_fix.md b/draftlogs/7522_fix.md new file mode 100644 index 00000000000..11547cb7c8f --- /dev/null +++ b/draftlogs/7522_fix.md @@ -0,0 +1 @@ +- Refactor `drawMainTitle` to use context-specific selections for title and subtitle, avoiding conflicts when multiple plots are present on the same page [[#7522](https://github.com/plotly/plotly.js/pull/7522)] From bc8096798247b5893e6d412e834c2f207382cec1 Mon Sep 17 00:00:00 2001 From: Davi Barbosa Date: Fri, 15 Aug 2025 01:57:07 -0300 Subject: [PATCH 06/10] Add test for title automargins in multiple plots --- test/jasmine/tests/titles_test.js | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/jasmine/tests/titles_test.js b/test/jasmine/tests/titles_test.js index 839cbdd55b3..6137c8adeaf 100644 --- a/test/jasmine/tests/titles_test.js +++ b/test/jasmine/tests/titles_test.js @@ -8,6 +8,7 @@ var Lib = require('../../../src/lib'); var rgb = require('../../../src/components/color').rgb; var createGraphDiv = require('../assets/create_graph_div'); +var createShadowGraphDiv = require('../assets/create_shadow_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var mouseEvent = require('../assets/mouse_event'); @@ -980,6 +981,48 @@ describe('Title automargining', function() { expect(gd._fullLayout._size.h).toBeCloseTo(243, -1); }).then(done, done.fail); }); + + it('computes title automargins independently when multiple plots exist', function(done) { + var gd1 = gd; + var gd2 = createShadowGraphDiv(); + + var dataLocal = [{x: [1, 2], y: [1, 2]}]; + + var layout1 = { + margin: {t: 0, b: 0, l: 0, r: 0}, + height: 300, + width: 400, + title: { + text: 'Large title for plot 1', + font: {size: 36}, + yref: 'paper', + automargin: true + } + }; + + var layout2 = { + margin: {t: 0, b: 0, l: 0, r: 0}, + height: 300, + width: 400, + title: { + text: 'Small', + font: {size: 12}, + yref: 'paper', + automargin: true + } + }; + + Plotly.newPlot(gd1, dataLocal, layout1) + .then(function() { return Plotly.newPlot(gd2, dataLocal, layout2); }) + .then(function() { + // Each graph should compute its own top automargin from its own title bbox + var t1 = gd1._fullLayout._size.t; + var t2 = gd2._fullLayout._size.t; + + expect(t1).toBeGreaterThan(t2); + }) + .then(done, done.fail); + }); }); function expectTitle(expTitle) { From e8434c8cadd5e9333a5587771bbc35d00beff100 Mon Sep 17 00:00:00 2001 From: Davi Barbosa Date: Fri, 15 Aug 2025 18:32:51 -0300 Subject: [PATCH 07/10] Enhance createGraphDiv function to accept a customizable divId parameter and update tests to utilize the new functionality. --- test/jasmine/assets/create_graph_div.js | 4 ++-- test/jasmine/tests/titles_test.js | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/test/jasmine/assets/create_graph_div.js b/test/jasmine/assets/create_graph_div.js index 9791d46018c..3dce4997b92 100644 --- a/test/jasmine/assets/create_graph_div.js +++ b/test/jasmine/assets/create_graph_div.js @@ -1,8 +1,8 @@ 'use strict'; -module.exports = function createGraphDiv() { +module.exports = function createGraphDiv(divId = 'graph') { var gd = document.createElement('div'); - gd.id = 'graph'; + gd.id = divId; document.body.appendChild(gd); // force the graph to be at position 0,0 no matter what diff --git a/test/jasmine/tests/titles_test.js b/test/jasmine/tests/titles_test.js index 6137c8adeaf..68772a00ffc 100644 --- a/test/jasmine/tests/titles_test.js +++ b/test/jasmine/tests/titles_test.js @@ -8,7 +8,6 @@ var Lib = require('../../../src/lib'); var rgb = require('../../../src/components/color').rgb; var createGraphDiv = require('../assets/create_graph_div'); -var createShadowGraphDiv = require('../assets/create_shadow_graph_div'); var destroyGraphDiv = require('../assets/destroy_graph_div'); var mouseEvent = require('../assets/mouse_event'); @@ -984,7 +983,7 @@ describe('Title automargining', function() { it('computes title automargins independently when multiple plots exist', function(done) { var gd1 = gd; - var gd2 = createShadowGraphDiv(); + var gd2 = createGraphDiv('title-automargining-2'); var dataLocal = [{x: [1, 2], y: [1, 2]}]; @@ -1020,6 +1019,9 @@ describe('Title automargining', function() { var t2 = gd2._fullLayout._size.t; expect(t1).toBeGreaterThan(t2); + }).then(function() { + var el = document.getElementById('title-automargining-2'); + if(el) document.body.removeChild(el); }) .then(done, done.fail); }); From 57db13c8a89d9ca6d1023e723fef80521c753714 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Mon, 18 Aug 2025 15:36:51 -0600 Subject: [PATCH 08/10] Update devtools to enable strict mode via query param --- devtools/test_dashboard/index-strict.html | 29 ------------------ devtools/test_dashboard/index.html | 3 ++ devtools/test_dashboard/server.mjs | 37 ++++++++++++++++++----- devtools/test_dashboard/strict.js | 7 +++++ devtools/test_dashboard/style.css | 5 +++ 5 files changed, 45 insertions(+), 36 deletions(-) delete mode 100644 devtools/test_dashboard/index-strict.html create mode 100644 devtools/test_dashboard/strict.js diff --git a/devtools/test_dashboard/index-strict.html b/devtools/test_dashboard/index-strict.html deleted file mode 100644 index 6c309cd211b..00000000000 --- a/devtools/test_dashboard/index-strict.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Plotly.js "strict" Devtools - - - - - -
- - - - - -
- -
-
-
-
-
- - - - - - diff --git a/devtools/test_dashboard/index.html b/devtools/test_dashboard/index.html index c2fc16aa4c5..0669c349b3e 100644 --- a/devtools/test_dashboard/index.html +++ b/devtools/test_dashboard/index.html @@ -21,6 +21,9 @@
+ + + diff --git a/devtools/test_dashboard/server.mjs b/devtools/test_dashboard/server.mjs index 7c2ea17f60f..b0adbd7ece4 100644 --- a/devtools/test_dashboard/server.mjs +++ b/devtools/test_dashboard/server.mjs @@ -62,22 +62,45 @@ console.log('watching esbuild...'); await ctx.watch(); function devServer() { - var server = http.createServer(ecstatic({ + const staticFilesHandler = ecstatic({ root: constants.pathToRoot, cache: 0, gzip: true, cors: true - })); + }); + + const server = http.createServer((req, res) => { + if(strict) { + res.setHeader( + 'Content-Security-Policy', + // Comment/uncomment for testing CSP. Changes require a server restart. + [ + // "default-src 'self'", + "script-src 'self'", + "style-src 'self' 'unsafe-inline'", + // "img-src 'self' data: blob:", + // "font-src 'self' data:", + // "connect-src 'self'", + // "object-src 'none'", + // "base-uri 'self';", + "worker-src blob:", + ].join("; ") + ) + } + + staticFilesHandler(req, res) + }) // Start the server up! server.listen(PORT); + let indexName = 'index'; + if(mathjax3) indexName += '-mathjax3' + else if(mathjax3chtml) indexName += '-mathjax3chtml' + indexName += '.html' + // open up browser window - open('http://localhost:' + PORT + '/devtools/test_dashboard/index' + ( - strict ? '-strict' : - mathjax3 ? '-mathjax3' : - mathjax3chtml ? '-mathjax3chtml' : '' - ) + '.html'); + open(`http://localhost:${PORT}/devtools/test_dashboard/${indexName}${strict ? '?strict=true' : ''}`); } function getMockFiles() { diff --git a/devtools/test_dashboard/strict.js b/devtools/test_dashboard/strict.js new file mode 100644 index 00000000000..56d664265ae --- /dev/null +++ b/devtools/test_dashboard/strict.js @@ -0,0 +1,7 @@ +if ((new URLSearchParams(location.search)).get("strict")) { + const strictDiv = document.createElement("div"); + strictDiv.id = "strict-div"; + strictDiv.textContent = "STRICT MODE"; + document.querySelector("#reload-time").insertAdjacentElement('afterend', strictDiv); + document.querySelector("title").innerText = "Plotly.js 'strict' Devtools"; +} diff --git a/devtools/test_dashboard/style.css b/devtools/test_dashboard/style.css index bea18056312..fb876d2cfc8 100644 --- a/devtools/test_dashboard/style.css +++ b/devtools/test_dashboard/style.css @@ -33,6 +33,11 @@ header span{ font-size: 10px; line-height: 40px; } +#strict-div{ + color: #F00; + font-weight: 600; + display: inline-block; +} #mocks-list{ position: fixed; right: 0px; From 0e55fa142a197e517d018ceae05814116d8221f5 Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Tue, 19 Aug 2025 14:38:01 -0600 Subject: [PATCH 09/10] Update Biome to v2.2.0; migrate config file --- biome.json | 275 +++++++++++++++++++++++----------------------- package-lock.json | 73 ++++++------ package.json | 2 +- 3 files changed, 174 insertions(+), 176 deletions(-) diff --git a/biome.json b/biome.json index 0b977758c7c..055e9d77085 100644 --- a/biome.json +++ b/biome.json @@ -1,140 +1,139 @@ { - "$schema": "https://biomejs.dev/schemas/1.8.3/schema.json", - "organizeImports": { "enabled": true }, - "files": { - "maxSize": 10000000, - "include": [ - "src", - "lib", - "test", - "tasks", - "devtools" - ], - "ignore": [ - "test/plot-schema.json", - "dist", - "stackgl_modules", - "node_modules", - "build", - "tasks/test_amdefine.js", - "tasks/test_requirejs.js", - "test/jasmine/assets/jquery-1.8.3.min.js" - ] - }, - "linter": { - "enabled": true, - "rules": { - "recommended": false, - "complexity": { - "noExtraBooleanCast": "error", - "noMultipleSpacesInRegularExpressionLiterals": "error", - "noUselessCatch": "error", - "noWith": "error", - "useLiteralKeys": "error" - }, - "correctness": { - "noConstAssign": "error", - "noConstantCondition": "error", - "noEmptyCharacterClassInRegex": "error", - "noEmptyPattern": "error", - "noGlobalObjectCalls": "error", - "noInnerDeclarations": "off", - "noInvalidConstructorSuper": "error", - "noInvalidUseBeforeDeclaration": "error", - "noNewSymbol": "error", - "noNonoctalDecimalEscape": "error", - "noPrecisionLoss": "error", - "noSelfAssign": "error", - "noSetterReturn": "error", - "noSwitchDeclarations": "off", - "noUndeclaredVariables": "off", - "noUnreachable": "error", - "noUnreachableSuper": "error", - "noUnsafeFinally": "error", - "noUnsafeOptionalChaining": "error", - "noUnusedLabels": "error", - "noUnusedVariables": "off", - "useIsNan": "error", - "useValidForDirection": "error", - "useYield": "error" - }, - "style": { - "useBlockStatements": "off", - "useSingleVarDeclarator": "off", - "noVar": "off" - }, - "suspicious": { - "noAssignInExpressions": "off", - "noAsyncPromiseExecutor": "error", - "noCatchAssign": "error", - "noClassAssign": "error", - "noCompareNegZero": "error", - "noConsoleLog": "off", - "noControlCharactersInRegex": "error", - "noDebugger": "error", - "noDoubleEquals": "off", - "noDuplicateCase": "error", - "noDuplicateClassMembers": "error", - "noDuplicateObjectKeys": "error", - "noDuplicateParameters": "error", - "noEmptyBlockStatements": "off", - "noFallthroughSwitchClause": "off", - "noFunctionAssign": "error", - "noGlobalAssign": "error", - "noImportAssign": "error", - "noMisleadingCharacterClass": "error", - "noPrototypeBuiltins": "off", - "noRedeclare": "off", - "noShadowRestrictedNames": "off", - "noUnsafeNegation": "error", - "useGetterReturn": "error", - "useValidTypeof": "error" - } - }, - "ignore": [ - "**/stackgl_modules", - "**/node_modules", - "**/dist", - "**/build", - "tasks/test_amdefine.js", - "tasks/test_requirejs.js", - "test/jasmine/assets/jquery-1.8.3.min.js" - ] - }, - "javascript": { - "globals": [ - "Promise", - "Float32Array", - "Uint8ClampedArray", - "Int32Array", - "ArrayBuffer", - "Uint16Array", - "DataView", - "Float64Array", - "Int16Array", - "Uint8Array", - "Int8Array", - "Uint32Array" - ], - "formatter": { - "quoteStyle": "single", - "trailingCommas": "none", - "indentStyle": "space", - "indentWidth": 4, - "lineEnding": "lf", - "lineWidth": 120 - } - }, - "json": { - "linter": { - "enabled": true - }, - "formatter": { - "enabled": true, - "indentStyle": "space", - "indentWidth": 1, - "lineEnding": "lf", - "lineWidth": 80 - } - } + "$schema": "https://biomejs.dev/schemas/2.2.0/schema.json", + "assist": { "actions": { "source": { "organizeImports": "on" } } }, + "files": { + "maxSize": 10000000, + "includes": [ + "**/src/**", + "**/lib/**", + "**/test/**", + "**/tasks/**", + "**/devtools/**", + "!**/test/plot-schema.json", + "!**/dist", + "!**/stackgl_modules", + "!**/node_modules", + "!**/build", + "!**/tasks/test_amdefine.js", + "!**/tasks/test_requirejs.js", + "!**/test/jasmine/assets/jquery-1.8.3.min.js" + ] + }, + "linter": { + "enabled": true, + "rules": { + "recommended": false, + "complexity": { + "noExtraBooleanCast": "error", + "noUselessCatch": "error", + "useLiteralKeys": "error", + "noAdjacentSpacesInRegex": "error" + }, + "correctness": { + "noConstAssign": "error", + "noConstantCondition": "error", + "noEmptyCharacterClassInRegex": "error", + "noEmptyPattern": "error", + "noGlobalObjectCalls": "error", + "noInnerDeclarations": "off", + "noInvalidConstructorSuper": "error", + "noInvalidUseBeforeDeclaration": "error", + "noNonoctalDecimalEscape": "error", + "noPrecisionLoss": "error", + "noSelfAssign": "error", + "noSetterReturn": "error", + "noSwitchDeclarations": "off", + "noUndeclaredVariables": "off", + "noUnreachable": "error", + "noUnreachableSuper": "error", + "noUnsafeFinally": "error", + "noUnsafeOptionalChaining": "error", + "noUnusedLabels": "error", + "noUnusedVariables": "off", + "useIsNan": "error", + "useValidForDirection": "error", + "useYield": "error", + "noInvalidBuiltinInstantiation": "error", + "useValidTypeof": "error" + }, + "style": { + "useBlockStatements": "off", + "useSingleVarDeclarator": "off" + }, + "suspicious": { + "noAssignInExpressions": "off", + "noAsyncPromiseExecutor": "error", + "noCatchAssign": "error", + "noClassAssign": "error", + "noCompareNegZero": "error", + "noControlCharactersInRegex": "error", + "noDebugger": "error", + "noDoubleEquals": "off", + "noDuplicateCase": "error", + "noDuplicateClassMembers": "error", + "noDuplicateObjectKeys": "error", + "noDuplicateParameters": "error", + "noEmptyBlockStatements": "off", + "noFallthroughSwitchClause": "off", + "noFunctionAssign": "error", + "noGlobalAssign": "error", + "noImportAssign": "error", + "noMisleadingCharacterClass": "error", + "noPrototypeBuiltins": "off", + "noRedeclare": "off", + "noShadowRestrictedNames": "off", + "noUnsafeNegation": "error", + "useGetterReturn": "error", + "noWith": "error", + "noVar": "off", + "noConsole": { "level": "off", "options": { "allow": ["log"] } } + } + }, + "includes": [ + "**", + "!**/stackgl_modules", + "!**/node_modules", + "!**/dist", + "!**/build", + "!**/tasks/test_amdefine.js", + "!**/tasks/test_requirejs.js", + "!**/test/jasmine/assets/jquery-1.8.3.min.js" + ] + }, + "javascript": { + "globals": [ + "Promise", + "Float32Array", + "Uint8ClampedArray", + "Int32Array", + "ArrayBuffer", + "Uint16Array", + "DataView", + "Float64Array", + "Int16Array", + "Uint8Array", + "Int8Array", + "Uint32Array" + ], + "formatter": { + "quoteStyle": "single", + "trailingCommas": "none", + "indentStyle": "space", + "indentWidth": 4, + "lineEnding": "lf", + "lineWidth": 120 + } + }, + "json": { + "linter": { + "enabled": true + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 1, + "lineEnding": "lf", + "lineWidth": 80 + } + } } diff --git a/package-lock.json b/package-lock.json index 6e6ea7cf9a9..fd21673815f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "world-calendars": "^1.0.4" }, "devDependencies": { - "@biomejs/biome": "1.8.3", + "@biomejs/biome": "2.2.0", "@plotly/mathjax-v2": "npm:mathjax@2.7.5", "@plotly/mathjax-v3": "npm:mathjax@^3.2.2", "amdefine": "^1.0.1", @@ -185,11 +185,10 @@ } }, "node_modules/@biomejs/biome": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.3.tgz", - "integrity": "sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.2.0.tgz", + "integrity": "sha512-3On3RSYLsX+n9KnoSgfoYlckYBoU6VRM22cw1gB4Y0OuUVSYd/O/2saOJMrA4HFfA1Ff0eacOvMN1yAAvHtzIw==", "dev": true, - "hasInstallScript": true, "license": "MIT OR Apache-2.0", "bin": { "biome": "bin/biome" @@ -202,20 +201,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "1.8.3", - "@biomejs/cli-darwin-x64": "1.8.3", - "@biomejs/cli-linux-arm64": "1.8.3", - "@biomejs/cli-linux-arm64-musl": "1.8.3", - "@biomejs/cli-linux-x64": "1.8.3", - "@biomejs/cli-linux-x64-musl": "1.8.3", - "@biomejs/cli-win32-arm64": "1.8.3", - "@biomejs/cli-win32-x64": "1.8.3" + "@biomejs/cli-darwin-arm64": "2.2.0", + "@biomejs/cli-darwin-x64": "2.2.0", + "@biomejs/cli-linux-arm64": "2.2.0", + "@biomejs/cli-linux-arm64-musl": "2.2.0", + "@biomejs/cli-linux-x64": "2.2.0", + "@biomejs/cli-linux-x64-musl": "2.2.0", + "@biomejs/cli-win32-arm64": "2.2.0", + "@biomejs/cli-win32-x64": "2.2.0" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.3.tgz", - "integrity": "sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.2.0.tgz", + "integrity": "sha512-zKbwUUh+9uFmWfS8IFxmVD6XwqFcENjZvEyfOxHs1epjdH3wyyMQG80FGDsmauPwS2r5kXdEM0v/+dTIA9FXAg==", "cpu": [ "arm64" ], @@ -230,9 +229,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.3.tgz", - "integrity": "sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.2.0.tgz", + "integrity": "sha512-+OmT4dsX2eTfhD5crUOPw3RPhaR+SKVspvGVmSdZ9y9O/AgL8pla6T4hOn1q+VAFBHuHhsdxDRJgFCSC7RaMOw==", "cpu": [ "x64" ], @@ -247,9 +246,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.3.tgz", - "integrity": "sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.2.0.tgz", + "integrity": "sha512-6eoRdF2yW5FnW9Lpeivh7Mayhq0KDdaDMYOJnH9aT02KuSIX5V1HmWJCQQPwIQbhDh68Zrcpl8inRlTEan0SXw==", "cpu": [ "arm64" ], @@ -264,9 +263,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.3.tgz", - "integrity": "sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.2.0.tgz", + "integrity": "sha512-egKpOa+4FL9YO+SMUMLUvf543cprjevNc3CAgDNFLcjknuNMcZ0GLJYa3EGTCR2xIkIUJDVneBV3O9OcIlCEZQ==", "cpu": [ "arm64" ], @@ -281,9 +280,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.3.tgz", - "integrity": "sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.2.0.tgz", + "integrity": "sha512-5UmQx/OZAfJfi25zAnAGHUMuOd+LOsliIt119x2soA2gLggQYrVPA+2kMUxR6Mw5M1deUF/AWWP2qpxgH7Nyfw==", "cpu": [ "x64" ], @@ -298,9 +297,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.3.tgz", - "integrity": "sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.2.0.tgz", + "integrity": "sha512-I5J85yWwUWpgJyC1CcytNSGusu2p9HjDnOPAFG4Y515hwRD0jpR9sT9/T1cKHtuCvEQ/sBvx+6zhz9l9wEJGAg==", "cpu": [ "x64" ], @@ -315,9 +314,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.3.tgz", - "integrity": "sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.2.0.tgz", + "integrity": "sha512-n9a1/f2CwIDmNMNkFs+JI0ZjFnMO0jdOyGNtihgUNFnlmd84yIYY2KMTBmMV58ZlVHjgmY5Y6E1hVTnSRieggA==", "cpu": [ "arm64" ], @@ -332,9 +331,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.3.tgz", - "integrity": "sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.2.0.tgz", + "integrity": "sha512-Nawu5nHjP/zPKTIryh2AavzTc/KEg4um/MxWdXW0A6P/RZOyIpa7+QSjeXwAwX/utJGaCoXRPWtF3m5U/bB3Ww==", "cpu": [ "x64" ], diff --git a/package.json b/package.json index afef26c7980..c52f4034a28 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "world-calendars": "^1.0.4" }, "devDependencies": { - "@biomejs/biome": "1.8.3", + "@biomejs/biome": "2.2.0", "@plotly/mathjax-v2": "npm:mathjax@2.7.5", "@plotly/mathjax-v3": "npm:mathjax@^3.2.2", "amdefine": "^1.0.1", From a77f33dc773915c0e6631141901098ff93cf9a2d Mon Sep 17 00:00:00 2001 From: Cameron DeCoster Date: Tue, 19 Aug 2025 15:51:33 -0600 Subject: [PATCH 10/10] Remove duplicated JSON keys --- test/image/mocks/27.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/image/mocks/27.json b/test/image/mocks/27.json index 3ffbe7bdee8..4e1b19d55a7 100644 --- a/test/image/mocks/27.json +++ b/test/image/mocks/27.json @@ -303,8 +303,6 @@ { "x": 1995.4584324515083, "y": 0.36681307285082176, - "xref": "x", - "yref": "y", "text": "Note: The Gini index is a commonly used measure of inequality.
0 is a perfectly equitable income distribution; 1 is perfectly inequitable.", "font": { "family": "",