From 29a4c656d6489264d3e3b627d13611e7b5679cca Mon Sep 17 00:00:00 2001 From: Robert Hurst Date: Tue, 29 Oct 2024 13:39:26 +0200 Subject: [PATCH 01/12] eslint changes --- .eslintrc.js | 17 ----------------- eslint.config.mjs | 13 +++++++++++++ package.json | 7 ++----- 3 files changed, 15 insertions(+), 22 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 eslint.config.mjs diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index ee4e4e4174..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true - }, - overrides: [ - ], - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module' - }, - rules: { - eqeqeq: 'off', - quotes: ['error', 'single' , { 'allowTemplateLiterals': true }] - } -} \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000000..182b27ea7b --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,13 @@ +export default [ + { + files: ['**/*.js', '**/*.mjs'], + ignores: ['public/js/lib/*'], + rules: { + quotes: ['error', 'single', { 'allowTemplateLiterals': true }], + 'prefer-const': ['error', { + 'destructuring': 'any', + 'ignoreReadBeforeAssign': false + }] + } + } +]; \ No newline at end of file diff --git a/package.json b/package.json index 8938ba04c3..ae49437a87 100644 --- a/package.json +++ b/package.json @@ -29,16 +29,13 @@ "simple-statistics": "^7.8.3" }, "devDependencies": { + "@eslint/js": "^9.13.0", "clean-jsdoc-theme": "^4.3.0", "codi-test-framework": "^0.0.33", "cookie-parser": "^1.4.5", "dotenv": "^16.4.5", "esbuild": "^0.19.11", - "eslint": "^8.29.0", - "eslint-config-standard": "^17.0.0", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.6.0", - "eslint-plugin-promise": "^6.1.1", + "eslint": "^8.57.1", "express": "^4.18.3", "uhtml": "^3.1.0" } From ed2cf8b5d7cf9ad172fa3ba4a11579280805fd1e Mon Sep 17 00:00:00 2001 From: Robert Hurst Date: Tue, 29 Oct 2024 14:02:04 +0200 Subject: [PATCH 02/12] Update rules --- eslint.config.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 182b27ea7b..d4b20b5c57 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -6,8 +6,13 @@ export default [ quotes: ['error', 'single', { 'allowTemplateLiterals': true }], 'prefer-const': ['error', { 'destructuring': 'any', - 'ignoreReadBeforeAssign': false - }] + 'ignoreReadBeforeAssign': true + }], + 'max-depth': ['error', + { + 'max': 4 + } + ] } } ]; \ No newline at end of file From f54fb4fe84687179baa2f9dcfdf36da381ff739f Mon Sep 17 00:00:00 2001 From: Robert Hurst Date: Tue, 29 Oct 2024 14:52:59 +0200 Subject: [PATCH 03/12] Update eslint action and config --- .github/workflows/eslint.yml | 29 +++++++++++++++++++++++++++++ eslint.config.mjs | 6 ++++-- 2 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/eslint.yml diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml new file mode 100644 index 0000000000..01b10a8150 --- /dev/null +++ b/.github/workflows/eslint.yml @@ -0,0 +1,29 @@ +name: ESLint + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + eslint: + name: Run ESLint + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run ESLint + run: npx eslint . --max-warnings=0 + # Alternatively, you can use your package.json script if you have one: + # run: npm run lint \ No newline at end of file diff --git a/eslint.config.mjs b/eslint.config.mjs index d4b20b5c57..a99c4f1624 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,7 @@ export default [ { files: ['**/*.js', '**/*.mjs'], - ignores: ['public/js/lib/*'], + ignores: ['public/js/lib/*', 'docs/**/*.js'], rules: { quotes: ['error', 'single', { 'allowTemplateLiterals': true }], 'prefer-const': ['error', { @@ -12,7 +12,9 @@ export default [ { 'max': 4 } - ] + ], + 'complexity': ['error', { 'max': 15 }], + 'no-nested-ternary': 'error' } } ]; \ No newline at end of file From f51bc9d32b7cabe456906f8b2dbe482ef7b01a57 Mon Sep 17 00:00:00 2001 From: Robert Hurst Date: Tue, 29 Oct 2024 15:00:11 +0200 Subject: [PATCH 04/12] update action --- .github/workflows/eslint.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index 01b10a8150..453d4f6b93 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -13,15 +13,12 @@ jobs: steps: - uses: actions/checkout@v4 - - - name: Set up Node.js - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - name: Install dependencies - run: npm ci + run: npm install - name: Run ESLint run: npx eslint . --max-warnings=0 From d64c5cce57b23a79ab665ec2166569ea51cc6791 Mon Sep 17 00:00:00 2001 From: Robert Hurst Date: Tue, 29 Oct 2024 15:02:37 +0200 Subject: [PATCH 05/12] update action --- .github/workflows/eslint.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index 453d4f6b93..7d30697a21 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -21,6 +21,4 @@ jobs: run: npm install - name: Run ESLint - run: npx eslint . --max-warnings=0 - # Alternatively, you can use your package.json script if you have one: - # run: npm run lint \ No newline at end of file + run: npx eslint . --max-warnings=0 \ No newline at end of file From 1111ca52d406643f998c17acfc93013c4b3897c7 Mon Sep 17 00:00:00 2001 From: Robert Hurst Date: Tue, 29 Oct 2024 15:44:31 +0200 Subject: [PATCH 06/12] Fix linting issues --- eslint.config.mjs | 2 +- lib/layer/decorate.mjs | 2 +- lib/layer/featureFields.mjs | 6 +- lib/layer/featureStyle.mjs | 2 +- lib/layer/format/mvt.mjs | 4 +- lib/layer/themes/distributed.mjs | 2 +- lib/layer/themes/graduated.mjs | 6 +- lib/location/create.mjs | 2 +- lib/mapp.mjs | 2 +- lib/plugins/login.mjs | 2 +- lib/ui/Gazetteer.mjs | 2 +- lib/ui/elements/legendIcon.mjs | 2 +- lib/ui/layers/filters.mjs | 2 +- lib/ui/layers/legends/categorized.mjs | 2 +- lib/ui/locations/entries/cloudinary.mjs | 10 ++-- lib/utils/copyToClipboard.mjs | 2 +- lib/utils/csvDownload.mjs | 4 +- lib/utils/dataURLtoBlob.mjs | 4 +- lib/utils/merge.mjs | 2 +- lib/utils/olStyle.mjs | 4 +- lib/utils/polygonIntersectFeatures.mjs | 2 +- lib/utils/svgSymbols.mjs | 6 +- lib/utils/verticeGeoms.mjs | 2 +- mod/provider/mongodb.js | 6 +- mod/query.js | 2 +- mod/user/acl.js | 67 +++++++++++----------- mod/user/cookie.js | 2 +- mod/user/fromACL.js | 2 +- mod/user/saml.js | 2 +- mod/utils/roles.js | 2 +- mod/utils/sqlFilter.js | 2 +- mod/workspace/_workspace.js | 4 +- mod/workspace/cache.js | 4 +- mod/workspace/getTemplate.js | 4 +- mod/workspace/templates/location_update.js | 2 +- mod/workspace/templates/mvt.js | 2 +- mod/workspace/templates/mvt_geom.js | 2 +- public/tests/_base.test.mjs | 4 +- public/tests/layer.test.mjs | 2 +- tests/lib/ui/layers/filters.test.mjs | 2 +- tests/lib/utils/queryParams.test.mjs | 4 +- tests/mod/workspace/_workspace.test.mjs | 2 +- 42 files changed, 95 insertions(+), 96 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index a99c4f1624..6da6e9a3fb 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -13,7 +13,7 @@ export default [ 'max': 4 } ], - 'complexity': ['error', { 'max': 15 }], + // 'complexity': ['error', { 'max': 15 }], 'no-nested-ternary': 'error' } } diff --git a/lib/layer/decorate.mjs b/lib/layer/decorate.mjs index 977a69c619..0dee92429d 100644 --- a/lib/layer/decorate.mjs +++ b/lib/layer/decorate.mjs @@ -236,7 +236,7 @@ async function zoomToExtent(params) { // Zooms to a specific extent. // XMLHttpRequest to layer extent endpoint - let response = await mapp.utils.xhr(`${this.mapview.host}/api/query/layer_extent?` + + const response = await mapp.utils.xhr(`${this.mapview.host}/api/query/layer_extent?` + mapp.utils.paramString({ // build query string for the url locale: this.mapview.locale.key, layer: this.key, diff --git a/lib/layer/featureFields.mjs b/lib/layer/featureFields.mjs index 866af75856..abac8a6c14 100644 --- a/lib/layer/featureFields.mjs +++ b/lib/layer/featureFields.mjs @@ -84,9 +84,9 @@ The jenks distribution method requires the stats.jenks utility method to calcula @param {layer} layer A decorated mapp layer object. */ function jenks(layer) { - let theme = layer.style.theme; + const theme = layer.style.theme; - let n = Math.min(layer.featureFields[theme.field].values.length, theme.categories.length); + const n = Math.min(layer.featureFields[theme.field].values.length, theme.categories.length); // Parse array values as float. layer.featureFields[theme.field].values = layer.featureFields[theme.field].values.map(parseFloat); @@ -113,7 +113,7 @@ The count distribution method counts values in the `featureFields.values[]` arra @param {layer} layer A decorated mapp layer object. */ function count(layer) { - let theme = layer.style.theme; + const theme = layer.style.theme; layer.featureFields[theme.field].values.forEach(val => { diff --git a/lib/layer/featureStyle.mjs b/lib/layer/featureStyle.mjs index 4901fb5ed4..96ab042d2a 100644 --- a/lib/layer/featureStyle.mjs +++ b/lib/layer/featureStyle.mjs @@ -144,7 +144,7 @@ export default function featureStyle(layer) { if (!layer.style.cluster) return; - let clusterScale = parseFloat(layer.style.cluster.clusterScale) + const clusterScale = parseFloat(layer.style.cluster.clusterScale) // Spread cluster style into feature.style. feature.style = { diff --git a/lib/layer/format/mvt.mjs b/lib/layer/format/mvt.mjs index b6aa30ab84..e317944253 100644 --- a/lib/layer/format/mvt.mjs +++ b/lib/layer/format/mvt.mjs @@ -262,10 +262,10 @@ function changeEndLoad(layer) { const bounds = layer.mapview.getBounds() // Assign current viewport if queryparam is truthy. - let viewport = [bounds.west, bounds.south, bounds.east, bounds.north, layer.mapview.srid]; + const viewport = [bounds.west, bounds.south, bounds.east, bounds.north, layer.mapview.srid]; // Assign current viewport if queryparam is truthy. - let z = layer.mapview.Map.getView().getZoom(); + const z = layer.mapview.Map.getView().getZoom(); layer.xhr = new XMLHttpRequest() diff --git a/lib/layer/themes/distributed.mjs b/lib/layer/themes/distributed.mjs index ffcf28376c..1c04b91893 100644 --- a/lib/layer/themes/distributed.mjs +++ b/lib/layer/themes/distributed.mjs @@ -25,7 +25,7 @@ export default function(theme, feature) { theme.index = 0 } - let field = theme.field || 'id' + const field = theme.field || 'id' // Get feature identifier for theme. const val = feature.properties[field] diff --git a/lib/layer/themes/graduated.mjs b/lib/layer/themes/graduated.mjs index 7c55464c8d..a87b555607 100644 --- a/lib/layer/themes/graduated.mjs +++ b/lib/layer/themes/graduated.mjs @@ -20,7 +20,7 @@ export default function (theme, feature) { // The graduated theme requires feature.properties. if (!feature.properties) return; - let catValue = Array.isArray(feature.properties.features) ? + const catValue = Array.isArray(feature.properties.features) ? // Reduce array of features to sum catValue feature.properties.features.reduce((total, F) => total + Number(F.getProperties()[theme.field]), 0) : @@ -35,9 +35,9 @@ export default function (theme, feature) { 'greater_than': val => cat => val >= cat.value } - let index = theme.categories.findIndex(graduated_breaks[theme.graduated_breaks](catValue)) + const index = theme.categories.findIndex(graduated_breaks[theme.graduated_breaks](catValue)) - let cat = theme.categories.at(index) + const cat = theme.categories.at(index) // Spread cat style to retain scale property feature.style = { diff --git a/lib/location/create.mjs b/lib/location/create.mjs index e08d784c71..3c660cda2b 100644 --- a/lib/location/create.mjs +++ b/lib/location/create.mjs @@ -80,7 +80,7 @@ export default async function createLocation(feature, interaction, layer) { setTimeout(checkFeature, 1000); function checkFeature() { - let found = layer.features?.find(F => F.properties?.id === location.id); + const found = layer.features?.find(F => F.properties?.id === location.id); if (found) { layer.source.un('tileloadend', concatFeatures); } else { diff --git a/lib/mapp.mjs b/lib/mapp.mjs index ee87300e1b..5672f7e261 100644 --- a/lib/mapp.mjs +++ b/lib/mapp.mjs @@ -57,7 +57,7 @@ if (window.ol === undefined) { } else { - let olVersion = parseFloat(ol?.util.VERSION) + const olVersion = parseFloat(ol?.util.VERSION) console.log(`OpenLayers version ${olVersion}`) diff --git a/lib/plugins/login.mjs b/lib/plugins/login.mjs index 46c242174d..71fad68643 100644 --- a/lib/plugins/login.mjs +++ b/lib/plugins/login.mjs @@ -25,6 +25,6 @@ export function login(plugin, mapview) { btnColumn.appendChild(mapp.utils.html.node` + href=${mapp.user ? '?logout=true' : '?login=true'}>
`); } \ No newline at end of file diff --git a/lib/ui/Gazetteer.mjs b/lib/ui/Gazetteer.mjs index 0821770836..0922a327ac 100644 --- a/lib/ui/Gazetteer.mjs +++ b/lib/ui/Gazetteer.mjs @@ -42,7 +42,7 @@ export default gazetteer => { if (!e.target.value.length) return; // Get possible coordinates from input. - let ll = e.target.value.split(',').map(parseFloat) + const ll = e.target.value.split(',').map(parseFloat) // Check whether coordinates are valid float values. if (ll.length === 2 && ll.every(n => typeof n === 'number' && !isNaN(n) && isFinite(n))) { diff --git a/lib/ui/elements/legendIcon.mjs b/lib/ui/elements/legendIcon.mjs index 95e9436691..d101be39ee 100644 --- a/lib/ui/elements/legendIcon.mjs +++ b/lib/ui/elements/legendIcon.mjs @@ -72,7 +72,7 @@ function createIconFromArray(style) { }); }; - let legendScale = style.icon[0].legendScale || 1; + const legendScale = style.icon[0].legendScale || 1; style.icon.forEach((icon) => { diff --git a/lib/ui/layers/filters.mjs b/lib/ui/layers/filters.mjs index e9cf14a227..4f6b43ec5f 100644 --- a/lib/ui/layers/filters.mjs +++ b/lib/ui/layers/filters.mjs @@ -522,7 +522,7 @@ async function filter_in(layer, filter) { const pattern = e.target.value; - let filtered = filter[filter.type].filter(val => + const filtered = filter[filter.type].filter(val => // val may not be string. val.toString().toLowerCase().startsWith(pattern.toLowerCase())) diff --git a/lib/ui/layers/legends/categorized.mjs b/lib/ui/layers/legends/categorized.mjs index 743ebeb285..e01ba357c6 100644 --- a/lib/ui/layers/legends/categorized.mjs +++ b/lib/ui/layers/legends/categorized.mjs @@ -85,7 +85,7 @@ export default function categorizedTheme(layer) { const cat_label = cat.label + (cat.count? ` [${cat.count}]`:'') // Cat label with filter function. - let label = mapp.utils.html`
catToggle(e, layer, cat)}>${cat_label}` diff --git a/lib/ui/locations/entries/cloudinary.mjs b/lib/ui/locations/entries/cloudinary.mjs index 4283b9adc7..578f869802 100644 --- a/lib/ui/locations/entries/cloudinary.mjs +++ b/lib/ui/locations/entries/cloudinary.mjs @@ -186,10 +186,10 @@ function imageLoad(e, entry) { img.onload = async () => { - let - canvas = mapp.utils.html.node``, - max_size = 1024, - width = img.width, + const canvas = mapp.utils.html.node`` + const max_size = 1024 + + let width = img.width, height = img.height // resize @@ -276,7 +276,7 @@ async function docLoad(e, entry) { async function trash(e, entry) { - const confirm = await mapp.ui.elements.confirm({text: mapp.dictionary.remove_item_confirm}); + const confirm = await mapp.ui.elements.confirm({ text: mapp.dictionary.remove_item_confirm }); if (!confirm) return; diff --git a/lib/utils/copyToClipboard.mjs b/lib/utils/copyToClipboard.mjs index 9bac15f02e..cfd1a17fb0 100644 --- a/lib/utils/copyToClipboard.mjs +++ b/lib/utils/copyToClipboard.mjs @@ -7,7 +7,7 @@ // Create temporary textarea to copy string to clipboard. export function copyToClipboard(str) { - let textArea = document.body.appendChild(mapp.utils.html.node` + const textArea = document.body.appendChild(mapp.utils.html.node`