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

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"
}
}

View File

@@ -20,14 +20,14 @@ const changelog = fs.readFileSync(changelogPath, 'utf8');
*/
const regex = /^## (\d+\.\d+\.\d+.*?)\n(.+?)(?=\n^## \d+\.\d+\.\d+.*?\n)/gms;
let releaseNotes = [];
const releaseNotes = [];
let match;
// eslint-disable-next-line no-cond-assign
while (match = regex.exec(changelog)) {
releaseNotes.push({
'version': match[1],
'changelog': match[2].trim(),
});
releaseNotes.push({
'version': match[1],
'changelog': match[2].trim(),
});
}
const latest = releaseNotes[0];
@@ -44,5 +44,4 @@ const templatedReleaseNotes = `${header}
${latest.changelog}`;
// eslint-disable-next-line eol-last
process.stdout.write(templatedReleaseNotes.trimEnd());

View File

@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver";
describe("accessibility", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter();
describe("skip links", () => {

View File

@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver";
describe("history", () => {
let { beforeAndAfter, when, get, then } = new MaputnikDriver();
const { beforeAndAfter, when, get, then } = new MaputnikDriver();
beforeAndAfter();
let undoKeyCombo: string;

View File

@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver";
describe("i18n", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter();
describe("language detector", () => {

View File

@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver";
describe("keyboard", () => {
let { beforeAndAfter, given, when, get, then } = new MaputnikDriver();
const { beforeAndAfter, given, when, get, then } = new MaputnikDriver();
beforeAndAfter();
describe("shortcuts", () => {
beforeEach(() => {

View File

@@ -2,7 +2,7 @@ import { v1 as uuid } from "uuid";
import { MaputnikDriver } from "./maputnik-driver";
describe("layers", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter();
beforeEach(() => {
when.setStyle("both");
@@ -101,7 +101,7 @@ describe("layers", () => {
});
describe("background", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "background",
});
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
@@ -117,7 +117,7 @@ describe("layers", () => {
describe("modify", () => {
function createBackground() {
// Setup
let id = uuid();
const id = uuid();
when.selectWithin("add-layer.layer-type", "background");
when.setValue("add-layer.layer-id.input", "background:" + id);
@@ -139,11 +139,11 @@ describe("layers", () => {
describe("layer", () => {
it("expand/collapse");
it("id", () => {
let bgId = createBackground();
const bgId = createBackground();
when.click("layer-list-item:background:" + bgId);
let id = uuid();
const id = uuid();
when.setValue("layer-editor.layer-id.input", "foobar:" + id);
when.click("min-zoom");
@@ -219,7 +219,7 @@ describe("layers", () => {
describe("comments", () => {
let bgId: string;
let comment = "42";
const comment = "42";
beforeEach(() => {
bgId = createBackground();
@@ -320,11 +320,11 @@ describe("layers", () => {
// TODO
it.skip("parse error", () => {
let bgId = createBackground();
const bgId = createBackground();
when.click("layer-list-item:background:" + bgId);
let errorSelector = ".CodeMirror-lint-marker-error";
const errorSelector = ".CodeMirror-lint-marker-error";
then(get.elementByTestId(errorSelector)).shouldNotExist();
when.click(".CodeMirror");
@@ -339,7 +339,7 @@ describe("layers", () => {
describe("fill", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "fill",
layer: "example",
});
@@ -361,7 +361,7 @@ describe("layers", () => {
describe("line", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "line",
layer: "example",
});
@@ -385,7 +385,7 @@ describe("layers", () => {
describe("symbol", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "symbol",
layer: "example",
});
@@ -404,7 +404,7 @@ describe("layers", () => {
describe("raster", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "raster",
layer: "raster",
});
@@ -423,7 +423,7 @@ describe("layers", () => {
describe("circle", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "circle",
layer: "example",
});
@@ -442,7 +442,7 @@ describe("layers", () => {
describe("fill extrusion", () => {
it("add", () => {
let id = when.modal.fillLayers({
const id = when.modal.fillLayers({
type: "fill-extrusion",
layer: "example",
});

View File

@@ -1,11 +1,11 @@
import { MaputnikDriver } from "./maputnik-driver";
describe("map", () => {
let { beforeAndAfter, get, when, then } = new MaputnikDriver();
const { beforeAndAfter, get, when, then } = new MaputnikDriver();
beforeAndAfter();
describe("zoom level", () => {
it("via url", () => {
let zoomLevel = 12.37;
const zoomLevel = 12.37;
when.setStyle("geojson", zoomLevel);
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible();
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldContainText(
@@ -14,7 +14,7 @@ describe("map", () => {
});
it("via map controls", () => {
let zoomLevel = 12.37;
const zoomLevel = 12.37;
when.setStyle("geojson", zoomLevel);
then(get.elementByTestId("maplibre:ctrl-zoom")).shouldBeVisible();
when.clickZoomIn();

View File

@@ -8,8 +8,8 @@ export default class ModalDriver {
fillLayers: (opts: { type: string; layer?: string; id?: string }) => {
// Having logic in test code is an anti pattern.
// This should be splitted to multiple single responsibility functions
let type = opts.type;
let layer = opts.layer;
const type = opts.type;
const layer = opts.layer;
let id;
if (opts.id) {
id = opts.id;

View File

@@ -1,7 +1,7 @@
import { MaputnikDriver } from "./maputnik-driver";
describe("modals", () => {
let { beforeAndAfter, when, get, then } = new MaputnikDriver();
const { beforeAndAfter, when, get, then } = new MaputnikDriver();
beforeAndAfter();
beforeEach(() => {
@@ -25,7 +25,7 @@ describe("modals", () => {
describe("when click open url", () => {
beforeEach(() => {
let styleFileUrl = get.exampleFileUrl();
const styleFileUrl = get.exampleFileUrl();
when.setValue("modal:open.url.input", styleFileUrl);
when.click("modal:open.url.button");
@@ -70,7 +70,7 @@ describe("modals", () => {
it("public source");
it("add new source", () => {
let sourceId = "n1z2v3r";
const sourceId = "n1z2v3r";
when.setValue("modal:sources.add.source_id", sourceId);
when.select("modal:sources.add.source_type", "tile_vector");
when.select("modal:sources.add.scheme_type", "tms");
@@ -84,7 +84,7 @@ describe("modals", () => {
});
it("add new raster source", () => {
let sourceId = "rastertest";
const sourceId = "rastertest";
when.setValue("modal:sources.add.source_id", sourceId);
when.select("modal:sources.add.source_type", "tile_raster");
when.select("modal:sources.add.scheme_type", "xyz");
@@ -159,7 +159,7 @@ describe("modals", () => {
});
});
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.click("modal:settings.name");
then(get.styleFromLocalStorage()).shouldDeepNestedInclude({
@@ -168,7 +168,7 @@ describe("modals", () => {
});
it("maptiler access token", () => {
let apiKey = "testing123";
const apiKey = "testing123";
when.setValue(
"modal:settings.maputnik:openmaptiles_access_token",
apiKey
@@ -182,7 +182,7 @@ describe("modals", () => {
});
it("thunderforest access token", () => {
let apiKey = "testing123";
const apiKey = "testing123";
when.setValue(
"modal:settings.maputnik:thunderforest_access_token",
apiKey
@@ -194,7 +194,7 @@ describe("modals", () => {
});
it("stadia access token", () => {
let apiKey = "testing123";
const apiKey = "testing123";
when.setValue(
"modal:settings.maputnik:stadia_access_token",
apiKey

61
eslint.config.js Normal file
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
}
}
)

View File

@@ -10,7 +10,7 @@ export default {
keySeparator: 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.
return '__STRING_NOT_TRANSLATED__';
}

859
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
"build": "tsc && vite build --base=/maputnik/",
"build-desktop": "tsc && vite build --base=/ && cd desktop && make",
"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",
"cy:open": "cypress open",
"lint-css": "stylelint \"src/styles/*.scss\"",
@@ -93,6 +93,7 @@
},
"devDependencies": {
"@cypress/code-coverage": "^3.13.10",
"@eslint/js": "^9.18.0",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@rollup/plugin-replace": "^6.0.2",
"@shellygo/cypress-test-utils": "^4.1.11",
@@ -121,13 +122,11 @@
"@types/string-hash": "^1.1.3",
"@types/uuid": "^10.0.0",
"@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",
"cors": "^2.8.5",
"cypress": "^14.0.0",
"cypress-plugin-tab": "^1.0.5",
"eslint": "^8.57.0",
"eslint": "^9.18.0",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.1.0",
"eslint-plugin-react-refresh": "^0.4.18",
@@ -141,6 +140,7 @@
"stylelint-config-recommended-scss": "^14.1.0",
"stylelint-scss": "^6.10.1",
"typescript": "^5.7.3",
"typescript-eslint": "^8.21.0",
"uuid": "^11.0.5",
"vite": "^6.0.11",
"vite-plugin-istanbul": "^6.0.2"

View File

@@ -15,7 +15,7 @@ function validate(url: string, t: TFunction): JSX.Element | undefined {
const urlObj = new URL(url);
return urlObj.protocol;
}
catch (err) {
catch (_err) {
return undefined;
}
};

View File

@@ -103,7 +103,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
let should = false;
try {
should = JSON.stringify(this.props) !== JSON.stringify(nextProps) || JSON.stringify(this.state) !== JSON.stringify(nextState);
} catch(e) {
} catch(_e) {
// no biggie, carry on
}
return should;
@@ -161,7 +161,7 @@ class MapMaplibreGlInternal extends React.Component<MapMaplibreGlInternalProps,
map.showCollisionBoxes = mapOpts.showCollisionBoxes!;
map.showOverdrawInspector = mapOpts.showOverdrawInspector!;
let geocoder = this.initGeocoder(map);
const geocoder = this.initGeocoder(map);
const zoomControl = new ZoomControl();
map.addControl(zoomControl, 'top-right');

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 CodeMirror, { MarkerRange } from 'codemirror';
import jsonToAst from 'json-to-ast';
@@ -33,7 +33,7 @@ CodeMirror.registerHelper("lint", "json", (text: string) => {
try {
jsonlint.parse(text);
}
catch(e) {
catch(_e) {
// Do nothing we catch the error above
}
return found;
@@ -55,7 +55,7 @@ CodeMirror.registerHelper("lint", "mgl", (text: string, opts: any, doc: any) =>
try {
parser.parse(text);
}
catch (e) {
catch (_e) {
// ignore errors
}

View File

@@ -1,4 +1,3 @@
// @ts-ignore
import style from './style'
export function initialStyleUrl() {

View File

@@ -22,6 +22,7 @@
"noFallthroughCasesInSwitch": true
},
"include": ["src", "cypress/e2e"],
"exclude": ["dist"],
"references": [{ "path": "./tsconfig.node.json" }],
// TODO: Remove when issue is resolved https://github.com/cypress-io/cypress/issues/27448
"ts-node": {

View File

@@ -18,7 +18,7 @@ export default defineConfig({
values: {
"_token_stack:": "",
},
}) as any,
}),
react(),
istanbul({
cypress: true,