From ed97c692167f81e9925b041f30bb4b6dead7a116 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Wed, 23 Sep 2026 21:29:49 +0200 Subject: [PATCH 1/4] ci: migrate ESLint config to flat config eslint.config.mjs for Super-Linter v8 Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- .github/linters/.eslintrc.yml | 102 ---------------------- .github/linters/eslint.config.mjs | 138 ++++++++++++++++++++++++++++++ .github/workflows/linter.yml | 1 + 3 files changed, 139 insertions(+), 102 deletions(-) delete mode 100644 .github/linters/.eslintrc.yml create mode 100644 .github/linters/eslint.config.mjs diff --git a/.github/linters/.eslintrc.yml b/.github/linters/.eslintrc.yml deleted file mode 100644 index cac6dc1..0000000 --- a/.github/linters/.eslintrc.yml +++ /dev/null @@ -1,102 +0,0 @@ ---- -env: - browser: true - es6: true - jest: true - node: true - -extends: - - "eslint:recommended" - -globals: - $WPT_ACCESSIBILITY_TREE: readonly - $WPT_BODIES: readonly - $WPT_COOKIES: readonly - $WPT_DNS: readonly - $WPT_REQUESTS: readonly - $WPT_TEST_URL: readonly - httparchive_enable_observations: writable - __REACT_DEVTOOLS_GLOBAL_HOOK__: writable - CSSUnparsedValue: readonly - LaunchParams: readonly - -ignorePatterns: - - "!.*" - - "**/node_modules/.*" - - "/dist/third-parties.js" - -plugins: - - n - - prettier - -rules: - no-inner-declarations: off - -overrides: - # JSON files - - files: - - "*.json" - extends: - - plugin:jsonc/recommended-with-json - parser: jsonc-eslint-parser - parserOptions: - jsonSyntax: JSON - - # JSONC files - - files: - - "*.jsonc" - extends: - - plugin:jsonc/recommended-with-jsonc - parser: jsonc-eslint-parser - parserOptions: - jsonSyntax: JSONC - - # JSON5 files - - files: - - "*.json5" - extends: - - plugin:jsonc/recommended-with-json5 - parser: jsonc-eslint-parser - parserOptions: - jsonSyntax: JSON5 - - # Javascript files - - files: - - "**/*.js" - extends: - - "plugin:react/recommended" - parserOptions: - ecmaVersion: latest - ecmaFeatures: - globalReturn: true - - - files: - - "**/*.mjs" - - "**/*.cjs" - - "**/*.jsx" - extends: - - "plugin:react/recommended" - parserOptions: - sourceType: module - ecmaVersion: latest - ecmaFeatures: - jsx: true - modules: true - - # TypeScript files - - files: - - "**/*.ts" - - "**/*.cts" - - "**/*.mts" - - "**/*.tsx" - extends: - - "plugin:@typescript-eslint/recommended" - - plugin:n/recommended - - plugin:react/recommended - - prettier - parser: "@typescript-eslint/parser" - plugins: - - "@typescript-eslint" - parserOptions: - ecmaVersion: latest - sourceType: module diff --git a/.github/linters/eslint.config.mjs b/.github/linters/eslint.config.mjs new file mode 100644 index 0000000..a1c9673 --- /dev/null +++ b/.github/linters/eslint.config.mjs @@ -0,0 +1,138 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import n from "eslint-plugin-n"; +import prettier from "eslint-plugin-prettier"; +import globals from "globals"; +import eslintPluginJsonc from "eslint-plugin-jsonc"; +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; +import pluginVue from "eslint-plugin-vue"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import js from "@eslint/js"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const compat = new FlatCompat({ + baseDirectory: __dirname, + recommendedConfig: js.configs.recommended, + allConfig: js.configs.all, +}); + +export default defineConfig([ + globalIgnores(["!**/.*", "**/node_modules/.*", "dist/third-parties.js"]), + { + extends: compat.extends("eslint:recommended"), + + plugins: { + n, + prettier, + }, + + languageOptions: { + globals: { + ...globals.browser, + ...globals.jest, + ...globals.node, + $WPT_ACCESSIBILITY_TREE: "readonly", + $WPT_BODIES: "readonly", + $WPT_COOKIES: "readonly", + $WPT_DNS: "readonly", + $WPT_REQUESTS: "readonly", + $WPT_TEST_URL: "readonly", + httparchive_enable_observations: "writable", + __REACT_DEVTOOLS_GLOBAL_HOOK__: "writable", + CSSUnparsedValue: "readonly", + LaunchParams: "readonly", + }, + }, + + rules: { + "no-inner-declarations": "off", + }, + }, + ...eslintPluginJsonc.configs["recommended-with-json"].map((config) => ({ + ...config, + files: ["**/*.json"], + })), + ...eslintPluginJsonc.configs["recommended-with-jsonc"].map((config) => ({ + ...config, + files: ["**/*.jsonc"], + })), + ...eslintPluginJsonc.configs["recommended-with-json5"].map((config) => ({ + ...config, + files: ["**/*.json5"], + })), + { + files: ["**/*.js"], + extends: compat.extends("plugin:react/recommended"), + + languageOptions: { + ecmaVersion: "latest", + sourceType: "script", + + parserOptions: { + ecmaFeatures: { + globalReturn: true, + }, + }, + }, + + settings: { + react: { + version: "detect", + }, + }, + }, + { + files: ["**/*.mjs", "**/*.cjs", "**/*.jsx"], + extends: compat.extends("plugin:react/recommended"), + + languageOptions: { + ecmaVersion: "latest", + sourceType: "module", + + parserOptions: { + ecmaFeatures: { + jsx: true, + modules: true, + }, + }, + }, + + settings: { + react: { + version: "detect", + }, + }, + }, + { + files: ["**/*.ts", "**/*.cts", "**/*.mts", "**/*.tsx"], + + extends: [ + n.configs["flat/recommended"], + compat.extends( + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended", + "prettier", + ), + ], + + plugins: { + "@typescript-eslint": typescriptEslint, + }, + + languageOptions: { + parser: tsParser, + ecmaVersion: "latest", + sourceType: "module", + }, + + settings: { + react: { + version: "detect", + }, + }, + }, + ...pluginVue.configs["flat/recommended"], +]); diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index d1feeb1..0312ea0 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -64,6 +64,7 @@ jobs: env: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JAVASCRIPT_ES_CONFIG_FILE: eslint.config.mjs VALIDATE_JAVASCRIPT_ES: true VALIDATE_EDITORCONFIG: true VALIDATE_MARKDOWN: true From 18d517543952087454a05344ca399c15216f5e67 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Wed, 23 Sep 2026 21:51:16 +0200 Subject: [PATCH 2/4] ci: remove legacy framework cruft and scope environments in eslint config Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- .github/linters/eslint.config.mjs | 132 ++++++++++-------------------- .github/workflows/linter.yml | 5 ++ 2 files changed, 48 insertions(+), 89 deletions(-) diff --git a/.github/linters/eslint.config.mjs b/.github/linters/eslint.config.mjs index a1c9673..c4f502b 100644 --- a/.github/linters/eslint.config.mjs +++ b/.github/linters/eslint.config.mjs @@ -1,138 +1,92 @@ import { defineConfig, globalIgnores } from "eslint/config"; +import js from "@eslint/js"; +import globals from "globals"; import n from "eslint-plugin-n"; import prettier from "eslint-plugin-prettier"; -import globals from "globals"; import eslintPluginJsonc from "eslint-plugin-jsonc"; -import typescriptEslint from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; -import pluginVue from "eslint-plugin-vue"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import js from "@eslint/js"; -import { FlatCompat } from "@eslint/eslintrc"; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all, -}); export default defineConfig([ globalIgnores(["!**/.*", "**/node_modules/.*", "dist/third-parties.js"]), - { - extends: compat.extends("eslint:recommended"), + // Base configuration: ESLint recommended, Node plugin, and Prettier integration + { plugins: { n, prettier, }, - - languageOptions: { - globals: { - ...globals.browser, - ...globals.jest, - ...globals.node, - $WPT_ACCESSIBILITY_TREE: "readonly", - $WPT_BODIES: "readonly", - $WPT_COOKIES: "readonly", - $WPT_DNS: "readonly", - $WPT_REQUESTS: "readonly", - $WPT_TEST_URL: "readonly", - httparchive_enable_observations: "writable", - __REACT_DEVTOOLS_GLOBAL_HOOK__: "writable", - CSSUnparsedValue: "readonly", - LaunchParams: "readonly", - }, - }, - rules: { + ...js.configs.recommended.rules, "no-inner-declarations": "off", }, }, + + // JSON files ...eslintPluginJsonc.configs["recommended-with-json"].map((config) => ({ ...config, files: ["**/*.json"], })), - ...eslintPluginJsonc.configs["recommended-with-jsonc"].map((config) => ({ - ...config, - files: ["**/*.jsonc"], - })), - ...eslintPluginJsonc.configs["recommended-with-json5"].map((config) => ({ - ...config, - files: ["**/*.json5"], - })), - { - files: ["**/*.js"], - extends: compat.extends("plugin:react/recommended"), + // Custom metrics (Browser / WebPageTest context) + { + files: ["dist/**/*.js", "inject-dist/**/*.js"], languageOptions: { ecmaVersion: "latest", sourceType: "script", - parserOptions: { ecmaFeatures: { globalReturn: true, }, }, - }, - - settings: { - react: { - version: "detect", + globals: { + ...globals.browser, + $WPT_ACCESSIBILITY_TREE: "readonly", + $WPT_BODIES: "readonly", + $WPT_COOKIES: "readonly", + $WPT_DNS: "readonly", + $WPT_REQUESTS: "readonly", + $WPT_TEST_URL: "readonly", + httparchive_enable_observations: "writable", + __REACT_DEVTOOLS_GLOBAL_HOOK__: "writable", + CSSUnparsedValue: "readonly", + LaunchParams: "readonly", }, }, }, - { - files: ["**/*.mjs", "**/*.cjs", "**/*.jsx"], - extends: compat.extends("plugin:react/recommended"), + // CLI and tooling scripts (Node.js context) + { + files: ["bin/**/*.js"], languageOptions: { ecmaVersion: "latest", - sourceType: "module", - - parserOptions: { - ecmaFeatures: { - jsx: true, - modules: true, - }, + sourceType: "commonjs", + globals: { + ...globals.node, }, }, + }, - settings: { - react: { - version: "detect", + // Tests (Node.js + Jest context) + { + files: ["tests/**/*.js"], + languageOptions: { + ecmaVersion: "latest", + sourceType: "commonjs", + globals: { + ...globals.node, + ...globals.jest, }, }, }, - { - files: ["**/*.ts", "**/*.cts", "**/*.mts", "**/*.tsx"], - - extends: [ - n.configs["flat/recommended"], - compat.extends( - "plugin:@typescript-eslint/recommended", - "plugin:react/recommended", - "prettier", - ), - ], - - plugins: { - "@typescript-eslint": typescriptEslint, - }, + // Root configuration files (ESM context) + { + files: ["*.mjs", ".github/**/*.mjs"], languageOptions: { - parser: tsParser, ecmaVersion: "latest", sourceType: "module", - }, - - settings: { - react: { - version: "detect", + globals: { + ...globals.node, }, }, }, - ...pluginVue.configs["flat/recommended"], ]); diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 0312ea0..e561391 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -30,6 +30,9 @@ jobs: name: Lint Code Base # Set the agent to run on runs-on: ubuntu-latest + permissions: + contents: read + statuses: write ################## # Load all steps # @@ -65,6 +68,8 @@ jobs: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} JAVASCRIPT_ES_CONFIG_FILE: eslint.config.mjs + ENABLE_GITHUB_ACTIONS_STEP_SUMMARY: true + ENABLE_GITHUB_PULL_REQUEST_SUMMARY_COMMENT: false VALIDATE_JAVASCRIPT_ES: true VALIDATE_EDITORCONFIG: true VALIDATE_MARKDOWN: true From 088dfb4e234cc8c38107bcff983daa56300b7882 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Wed, 23 Sep 2026 22:01:12 +0200 Subject: [PATCH 3/4] ci: check PR description for super-linter to support grouped Dependabot updates Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- .github/workflows/linter.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index e561391..367188f 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -54,8 +54,9 @@ jobs: - name: Set VALIDATE_ALL_CODEBASE variable to false # Only run the full workflow for manual runs or if upgrading the super linter if: | - github.event_name != 'workflow_dispatch' && - startsWith(github.event.pull_request.title,'Bump github/super-linter') != true + github.event_name != 'workflow_dispatch' && + !contains(github.event.pull_request.title, 'super-linter') && + !contains(github.event.pull_request.body, 'super-linter') run: | echo "VALIDATE_ALL_CODEBASE=false" >> $GITHUB_ENV @@ -67,8 +68,6 @@ jobs: env: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - JAVASCRIPT_ES_CONFIG_FILE: eslint.config.mjs - ENABLE_GITHUB_ACTIONS_STEP_SUMMARY: true ENABLE_GITHUB_PULL_REQUEST_SUMMARY_COMMENT: false VALIDATE_JAVASCRIPT_ES: true VALIDATE_EDITORCONFIG: true From ae1440eae7e1decb59533c8d412e03f4169352e3 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Wed, 23 Sep 2026 22:07:13 +0200 Subject: [PATCH 4/4] ci: set caughtErrors: none in no-unused-vars for ESLint v9 parity Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- .github/linters/eslint.config.mjs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/linters/eslint.config.mjs b/.github/linters/eslint.config.mjs index c4f502b..922ae72 100644 --- a/.github/linters/eslint.config.mjs +++ b/.github/linters/eslint.config.mjs @@ -17,6 +17,12 @@ export default defineConfig([ rules: { ...js.configs.recommended.rules, "no-inner-declarations": "off", + "no-unused-vars": [ + "error", + { + caughtErrors: "none", + }, + ], }, },