Upgrade eslint (#1014)

It's apparently forced now to use the eslint.config.js instead of
.eslintrc

It got more strict with requiring the underscore on unused vars like
`catch(_err)` , but that was all

Closes #1012
Closes #995
Closes #992

## Launch Checklist

<!-- Thanks for the PR! Feel free to add or remove items from the
checklist. -->


 - [ ] Briefly describe the changes in this PR.
 - [ ] Link to related issues.
- [ ] Include before/after visuals or gifs if this PR includes visual
changes.
 - [ ] Write tests for all new functionality.
 - [ ] Add an entry to `CHANGELOG.md` under the `## main` section.
This commit is contained in:
Birk Skyum
2025-01-21 16:21:30 +01:00
committed by GitHub
parent b429bb16d7
commit cd7d607f13
20 changed files with 467 additions and 598 deletions
-46
View File
@@ -1,46 +0,0 @@
{
"root": true,
"env": {
"browser": true,
"es2020": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
],
"ignorePatterns": [
"dist"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"settings": {
"react": { "version": "16.4" }
},
"plugins": [
"@typescript-eslint",
"react-refresh"],
"rules": {
"react-refresh/only-export-components": [
"warn",
{ "allowConstantExport": true }
],
"@typescript-eslint/no-unused-vars": [
"warn",
{ "argsIgnorePattern": "^_" }
],
"no-unused-vars": "off",
"react/prop-types": ["off"],
// Disable no-undef. It's covered by @typescript-eslint
"no-undef": "off",
"indent": ["error", 2],
"no-var": ["error"]
},
"globals": {
"global": "readonly"
}
}
+5 -6
View File
@@ -20,14 +20,14 @@ const changelog = fs.readFileSync(changelogPath, 'utf8');
*/ */
const regex = /^## (\d+\.\d+\.\d+.*?)\n(.+?)(?=\n^## \d+\.\d+\.\d+.*?\n)/gms; const regex = /^## (\d+\.\d+\.\d+.*?)\n(.+?)(?=\n^## \d+\.\d+\.\d+.*?\n)/gms;
let releaseNotes = []; const releaseNotes = [];
let match; let match;
// eslint-disable-next-line no-cond-assign // eslint-disable-next-line no-cond-assign
while (match = regex.exec(changelog)) { while (match = regex.exec(changelog)) {
releaseNotes.push({ releaseNotes.push({
'version': match[1], 'version': match[1],
'changelog': match[2].trim(), 'changelog': match[2].trim(),
}); });
} }
const latest = releaseNotes[0]; const latest = releaseNotes[0];
@@ -44,5 +44,4 @@ const templatedReleaseNotes = `${header}
${latest.changelog}`; ${latest.changelog}`;
// eslint-disable-next-line eol-last
process.stdout.write(templatedReleaseNotes.trimEnd()); process.stdout.write(templatedReleaseNotes.trimEnd());
+1 -1
View File
@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("accessibility", () => { describe("accessibility", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver(); const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
describe("skip links", () => { describe("skip links", () => {
+1 -1
View File
@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("history", () => { describe("history", () => {
let { beforeAndAfter, when, get, then } = new MaputnikDriver(); const { beforeAndAfter, when, get, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
let undoKeyCombo: string; let undoKeyCombo: string;
+1 -1
View File
@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("i18n", () => { describe("i18n", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver(); const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
describe("language detector", () => { describe("language detector", () => {
+1 -1
View File
@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("keyboard", () => { describe("keyboard", () => {
let { beforeAndAfter, given, when, get, then } = new MaputnikDriver(); const { beforeAndAfter, given, when, get, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
describe("shortcuts", () => { describe("shortcuts", () => {
beforeEach(() => { beforeEach(() => {
+14 -14
View File
@@ -2,7 +2,7 @@ import { v1 as uuid } from "uuid";
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("layers", () => { describe("layers", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver(); const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
beforeEach(() => { beforeEach(() => {
when.setStyle("both"); when.setStyle("both");
@@ -101,7 +101,7 @@ describe("layers", () => {
}); });
describe("background", () => { describe("background", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "background", type: "background",
}); });
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
@@ -117,7 +117,7 @@ describe("layers", () => {
describe("modify", () => { describe("modify", () => {
function createBackground() { function createBackground() {
// Setup // Setup
let id = uuid(); const id = uuid();
when.selectWithin("add-layer.layer-type", "background"); when.selectWithin("add-layer.layer-type", "background");
when.setValue("add-layer.layer-id.input", "background:" + id); when.setValue("add-layer.layer-id.input", "background:" + id);
@@ -139,11 +139,11 @@ describe("layers", () => {
describe("layer", () => { describe("layer", () => {
it("expand/collapse"); it("expand/collapse");
it("id", () => { it("id", () => {
let bgId = createBackground(); const bgId = createBackground();
when.click("layer-list-item:background:" + bgId); when.click("layer-list-item:background:" + bgId);
let id = uuid(); const id = uuid();
when.setValue("layer-editor.layer-id.input", "foobar:" + id); when.setValue("layer-editor.layer-id.input", "foobar:" + id);
when.click("min-zoom"); when.click("min-zoom");
@@ -219,7 +219,7 @@ describe("layers", () => {
describe("comments", () => { describe("comments", () => {
let bgId: string; let bgId: string;
let comment = "42"; const comment = "42";
beforeEach(() => { beforeEach(() => {
bgId = createBackground(); bgId = createBackground();
@@ -320,11 +320,11 @@ describe("layers", () => {
// TODO // TODO
it.skip("parse error", () => { it.skip("parse error", () => {
let bgId = createBackground(); const bgId = createBackground();
when.click("layer-list-item:background:" + bgId); when.click("layer-list-item:background:" + bgId);
let errorSelector = ".CodeMirror-lint-marker-error"; const errorSelector = ".CodeMirror-lint-marker-error";
then(get.elementByTestId(errorSelector)).shouldNotExist(); then(get.elementByTestId(errorSelector)).shouldNotExist();
when.click(".CodeMirror"); when.click(".CodeMirror");
@@ -339,7 +339,7 @@ describe("layers", () => {
describe("fill", () => { describe("fill", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "fill", type: "fill",
layer: "example", layer: "example",
}); });
@@ -361,7 +361,7 @@ describe("layers", () => {
describe("line", () => { describe("line", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "line", type: "line",
layer: "example", layer: "example",
}); });
@@ -385,7 +385,7 @@ describe("layers", () => {
describe("symbol", () => { describe("symbol", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "symbol", type: "symbol",
layer: "example", layer: "example",
}); });
@@ -404,7 +404,7 @@ describe("layers", () => {
describe("raster", () => { describe("raster", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "raster", type: "raster",
layer: "raster", layer: "raster",
}); });
@@ -423,7 +423,7 @@ describe("layers", () => {
describe("circle", () => { describe("circle", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "circle", type: "circle",
layer: "example", layer: "example",
}); });
@@ -442,7 +442,7 @@ describe("layers", () => {
describe("fill extrusion", () => { describe("fill extrusion", () => {
it("add", () => { it("add", () => {
let id = when.modal.fillLayers({ const id = when.modal.fillLayers({
type: "fill-extrusion", type: "fill-extrusion",
layer: "example", layer: "example",
}); });
+3 -3
View File
@@ -1,11 +1,11 @@
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("map", () => { describe("map", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver(); const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
describe("zoom level", () => { describe("zoom level", () => {
it("via url", () => { it("via url", () => {
let zoomLevel = 12.37; const zoomLevel = 12.37;
when.setStyle("geojson", zoomLevel); when.setStyle("geojson", zoomLevel);
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible(); then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible();
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldContainText( then(get.elementByTestId("maplibre:ctrl-zoom")).shouldContainText(
@@ -14,7 +14,7 @@ describe("map", () => {
}); });
it("via map controls", () => { it("via map controls", () => {
let zoomLevel = 12.37; const zoomLevel = 12.37;
when.setStyle("geojson", zoomLevel); when.setStyle("geojson", zoomLevel);
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible(); then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible();
when.clickZoomIn(); when.clickZoomIn();
+2 -2
View File
@@ -8,8 +8,8 @@ export default class ModalDriver {
fillLayers: (opts: { type: string; layer?: string; id?: string }) => { fillLayers: (opts: { type: string; layer?: string; id?: string }) => {
// Having logic in test code is an anti pattern. // Having logic in test code is an anti pattern.
// This should be splitted to multiple single responsibility functions // This should be splitted to multiple single responsibility functions
let type = opts.type; const type = opts.type;
let layer = opts.layer; const layer = opts.layer;
let id; let id;
if (opts.id) { if (opts.id) {
id = opts.id; id = opts.id;
+8 -8
View File
@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver"; import { MaputnikDriver } from "./maputnik-driver";
describe("modals", () => { describe("modals", () => {
let { beforeAndAfter, when, get, then } = new MaputnikDriver(); const { beforeAndAfter, when, get, then } = new MaputnikDriver();
beforeAndAfter(); beforeAndAfter();
beforeEach(() => { beforeEach(() => {
@@ -25,7 +25,7 @@ describe("modals", () => {
describe("when click open url", () => { describe("when click open url", () => {
beforeEach(() => { beforeEach(() => {
let styleFileUrl = get.exampleFileUrl(); const styleFileUrl = get.exampleFileUrl();
when.setValue("modal:open.url.input", styleFileUrl); when.setValue("modal:open.url.input", styleFileUrl);
when.click("modal:open.url.button"); when.click("modal:open.url.button");
@@ -70,7 +70,7 @@ describe("modals", () => {
it("public source"); it("public source");
it("add new source", () => { it("add new source", () => {
let sourceId = "n1z2v3r"; const sourceId = "n1z2v3r";
when.setValue("modal:sources.add.source_id", sourceId); when.setValue("modal:sources.add.source_id", sourceId);
when.select("modal:sources.add.source_type", "tile_vector"); when.select("modal:sources.add.source_type", "tile_vector");
when.select("modal:sources.add.scheme_type", "tms"); when.select("modal:sources.add.scheme_type", "tms");
@@ -84,7 +84,7 @@ describe("modals", () => {
}); });
it("add new raster source", () => { it("add new raster source", () => {
let sourceId = "rastertest"; const sourceId = "rastertest";
when.setValue("modal:sources.add.source_id", sourceId); when.setValue("modal:sources.add.source_id", sourceId);
when.select("modal:sources.add.source_type", "tile_raster"); when.select("modal:sources.add.source_type", "tile_raster");
when.select("modal:sources.add.scheme_type", "xyz"); when.select("modal:sources.add.scheme_type", "xyz");
@@ -159,7 +159,7 @@ describe("modals", () => {
}); });
}); });
it("glyphs url", () => { it("glyphs url", () => {
let glyphsUrl = "http://example.com/{fontstack}/{range}.pbf"; const glyphsUrl = "http://example.com/{fontstack}/{range}.pbf";
when.setValue("modal:settings.glyphs", glyphsUrl); when.setValue("modal:settings.glyphs", glyphsUrl);
when.click("modal:settings.name"); when.click("modal:settings.name");
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({ then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
@@ -168,7 +168,7 @@ describe("modals", () => {
}); });
it("maptiler access token", () => { it("maptiler access token", () => {
let apiKey = "testing123"; const apiKey = "testing123";
when.setValue( when.setValue(
"modal:settings.maputnik:openmaptiles_access_token", "modal:settings.maputnik:openmaptiles_access_token",
apiKey apiKey
@@ -182,7 +182,7 @@ describe("modals", () => {
}); });
it("thunderforest access token", () => { it("thunderforest access token", () => {
let apiKey = "testing123"; const apiKey = "testing123";
when.setValue( when.setValue(
"modal:settings.maputnik:thunderforest_access_token", "modal:settings.maputnik:thunderforest_access_token",
apiKey apiKey
@@ -194,7 +194,7 @@ describe("modals", () => {
}); });
it("stadia access token", () => { it("stadia access token", () => {
let apiKey = "testing123"; const apiKey = "testing123";
when.setValue( when.setValue(
"modal:settings.maputnik:stadia_access_token", "modal:settings.maputnik:stadia_access_token",
apiKey apiKey
+61
View File
@@ -0,0 +1,61 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactHooksPlugin from 'eslint-plugin-react-hooks';
import reactRefreshPlugin from 'eslint-plugin-react-refresh';
export default tseslint.config({
extends: [
eslint.configs.recommended,
tseslint.configs.recommended,
],
files: ['**/*.{js,jsx,ts,tsx}'],
ignores: [
"dist/**/*",
],
languageOptions: {
ecmaVersion: 2024,
sourceType: 'module',
globals: {
global: 'readonly'
}
},
settings: {
react: { version: '18.2' }
},
plugins: {
'react': reactPlugin,
'react-hooks': reactHooksPlugin,
'react-refresh': reactRefreshPlugin
},
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true }
],
"@typescript-eslint/no-explicit-any": "off",
'@typescript-eslint/no-unused-vars': [
'warn',
{
varsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
argsIgnorePattern: '^_'
}
],
'no-unused-vars': 'off',
'react/prop-types': 'off',
'no-undef': 'off',
'indent': ['error', 2],
'no-var': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
},
linterOptions: {
reportUnusedDisableDirectives: true,
noInlineConfig: false
}
}
)
+1 -1
View File
@@ -10,7 +10,7 @@ export default {
keySeparator: false, keySeparator: false,
namespaceSeparator: false, namespaceSeparator: false,
defaultValue: (locale, ns, key) => { defaultValue: (_locale, _ns, _key) => {
// The default value is a string that indicates that the string is not translated. // The default value is a string that indicates that the string is not translated.
return '__STRING_NOT_TRANSLATED__'; return '__STRING_NOT_TRANSLATED__';
} }
+357 -502
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -9,7 +9,7 @@
"build": "tsc && vite build --base=/maputnik/", "build": "tsc && vite build --base=/maputnik/",
"build-desktop": "tsc && vite build --base=/ && cd desktop && make", "build-desktop": "tsc && vite build --base=/ && cd desktop && make",
"i18n:refresh": "i18next 'src/**/*.{ts,tsx,js,jsx}'", "i18n:refresh": "i18next 'src/**/*.{ts,tsx,js,jsx}'",
"lint": "eslint ./src ./cypress --ext ts,tsx,js,jsx --report-unused-disable-directives --max-warnings 0", "lint": "eslint",
"test": "cypress run", "test": "cypress run",
"cy:open": "cypress open", "cy:open": "cypress open",
"lint-css": "stylelint \"src/styles/*.scss\"", "lint-css": "stylelint \"src/styles/*.scss\"",
@@ -93,6 +93,7 @@
}, },
"devDependencies": { "devDependencies": {
"@cypress/code-coverage": "^3.13.10", "@cypress/code-coverage": "^3.13.10",
"@eslint/js": "^9.18.0",
"@istanbuljs/nyc-config-typescript": "^1.0.2", "@istanbuljs/nyc-config-typescript": "^1.0.2",
"@rollup/plugin-replace": "^6.0.2", "@rollup/plugin-replace": "^6.0.2",
"@shellygo/cypress-test-utils": "^4.1.11", "@shellygo/cypress-test-utils": "^4.1.11",
@@ -121,13 +122,11 @@
"@types/string-hash": "^1.1.3", "@types/string-hash": "^1.1.3",
"@types/uuid": "^10.0.0", "@types/uuid": "^10.0.0",
"@types/wicg-file-system-access": "^2023.10.5", "@types/wicg-file-system-access": "^2023.10.5",
"@typescript-eslint/eslint-plugin": "^7.3.1",
"@typescript-eslint/parser": "^7.3.1",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
"cors": "^2.8.5", "cors": "^2.8.5",
"cypress": "^14.0.0", "cypress": "^14.0.0",
"cypress-plugin-tab": "^1.0.5", "cypress-plugin-tab": "^1.0.5",
"eslint": "^8.57.0", "eslint": "^9.18.0",
"eslint-plugin-react": "^7.37.4", "eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0", "eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.18", "eslint-plugin-react-refresh": "^0.4.18",
@@ -141,6 +140,7 @@
"stylelint-config-recommended-scss": "^14.1.0", "stylelint-config-recommended-scss": "^14.1.0",
"stylelint-scss": "^6.10.1", "stylelint-scss": "^6.10.1",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"typescript-eslint": "^8.21.0",
"uuid": "^11.0.5", "uuid": "^11.0.5",
"vite": "^6.0.11", "vite": "^6.0.11",
"vite-plugin-istanbul": "^6.0.2" "vite-plugin-istanbul": "^6.0.2"
+1 -1
View File
@@ -15,7 +15,7 @@ function validate(url: string, t: TFunction): JSX.Element | undefined {
const urlObj = new URL(url); const urlObj = new URL(url);
return urlObj.protocol; return urlObj.protocol;
} }
catch (err) { catch (_err) {
return undefined; return undefined;
} }
}; };
+2 -2
View File
@@ -103,7 +103,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
let should = false; let should = false;
try { try {
should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState); should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState);
} catch(e) { } catch(_e) {
// no biggie, carry on // no biggie, carry on
} }
return should; return should;
@@ -161,7 +161,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
map.showCollisionBoxes = mapOpts.showCollisionBoxes!; map.showCollisionBoxes = mapOpts.showCollisionBoxes!;
map.showOverdrawInspector = mapOpts.showOverdrawInspector!; map.showOverdrawInspector = mapOpts.showOverdrawInspector!;
let geocoder = this.initGeocoder(map); const geocoder = this.initGeocoder(map);
const zoomControl = new ZoomControl(); const zoomControl = new ZoomControl();
map.addControl(zoomControl, 'top-right'); map.addControl(zoomControl, 'top-right');
+3 -3
View File
@@ -1,4 +1,4 @@
// @ts-ignore - this is a fork of jsonlint // @ts-expect-error - this is a fork of jsonlint
import jsonlint from 'jsonlint'; import jsonlint from 'jsonlint';
import CodeMirror, { MarkerRange } from 'codemirror'; import CodeMirror, { MarkerRange } from 'codemirror';
import jsonToAst from 'json-to-ast'; import jsonToAst from 'json-to-ast';
@@ -33,7 +33,7 @@ CodeMirror.registerHelper("lint", "json", (text: string) => {
try { try {
jsonlint.parse(text); jsonlint.parse(text);
} }
catch(e) { catch(_e) {
// Do nothing we catch the error above // Do nothing we catch the error above
} }
return found; return found;
@@ -55,7 +55,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
try { try {
parser.parse(text); parser.parse(text);
} }
catch (e) { catch (_e) {
// ignore errors // ignore errors
} }
-1
View File
@@ -1,4 +1,3 @@
// @ts-ignore
import style from './style' import style from './style'
export function initialStyleUrl() { export function initialStyleUrl() {
+1
View File
@@ -22,6 +22,7 @@
"noFallthroughCasesInSwitch": true "noFallthroughCasesInSwitch": true
}, },
"include": ["src", "cypress/e2e"], "include": ["src", "cypress/e2e"],
"exclude": ["dist"],
"references": [{ "path": "./tsconfig.node.json" }], "references": [{ "path": "./tsconfig.node.json" }],
// TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448 // TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448
"ts-node": { "ts-node": {
+1 -1
View File
@@ -18,7 +18,7 @@ export default defineConfig({
values: { values: {
"_token_stack:": "", "_token_stack:": "",
}, },
}) as any, }),
react(), react(),
istanbul({ istanbul({
cypress: true, cypress: true,