From 51f7a898264dc3a7aab8cfb132038d0c85b62d6c Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 27 Aug 2025 20:35:52 +0200 Subject: [PATCH 01/37] chore: add eslint formatter for multiple formats --- nx.json | 29 +- package-lock.json | 722 +++++++++++++++++- package.json | 3 + tools/eslint-multi-format/README.md | 95 +++ tools/eslint-multi-format/eslint.config.js | 21 + tools/eslint-multi-format/package.json | 37 + tools/eslint-multi-format/project.json | 18 + tools/eslint-multi-format/src/index.ts | 3 + .../src/lib/multiple-formats.ts | 76 ++ tools/eslint-multi-format/src/lib/types.ts | 9 + tools/eslint-multi-format/src/lib/utils.ts | 165 ++++ tools/eslint-multi-format/tsconfig.json | 26 + tools/eslint-multi-format/tsconfig.lib.json | 23 + tools/eslint-multi-format/tsconfig.spec.json | 28 + tools/eslint-multi-format/vite.config.ts | 59 ++ tools/tsconfig.tools.json | 3 +- tsconfig.base.json | 3 + 17 files changed, 1286 insertions(+), 34 deletions(-) create mode 100644 tools/eslint-multi-format/README.md create mode 100644 tools/eslint-multi-format/eslint.config.js create mode 100644 tools/eslint-multi-format/package.json create mode 100644 tools/eslint-multi-format/project.json create mode 100644 tools/eslint-multi-format/src/index.ts create mode 100644 tools/eslint-multi-format/src/lib/multiple-formats.ts create mode 100644 tools/eslint-multi-format/src/lib/types.ts create mode 100644 tools/eslint-multi-format/src/lib/utils.ts create mode 100644 tools/eslint-multi-format/tsconfig.json create mode 100644 tools/eslint-multi-format/tsconfig.lib.json create mode 100644 tools/eslint-multi-format/tsconfig.spec.json create mode 100644 tools/eslint-multi-format/vite.config.ts diff --git a/nx.json b/nx.json index a472f35ed..b6ea32734 100644 --- a/nx.json +++ b/nx.json @@ -59,7 +59,7 @@ "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], "outputs": ["{projectRoot}/.eslint/eslint-report*.json"], "cache": true, - "executor": "@nx/linter:eslint", + "executor": "@nx/eslint:lint", "options": { "errorOnUnmatchedPattern": false, "maxWarnings": 0, @@ -71,6 +71,19 @@ ] } }, + "lint-formatter": { + "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], + "outputs": ["{projectRoot}/.eslint/eslint-report*.json"], + "cache": true, + "executor": "nx:run-commands", + "options": { + "command": "nx lint {projectName}", + "args": ["--format=./dist/eslint-multi-format/index.js"], + "env": { + "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" + } + } + }, "nxv-pkg-install": { "parallelism": false }, @@ -164,6 +177,20 @@ "filterByTags": ["publishable"] } } + }, + { + "plugin": "@nx/vite/plugin", + "options": { + "buildTargetName": "build", + "testTargetName": "test", + "serveTargetName": "serve", + "devTargetName": "dev", + "previewTargetName": "preview", + "serveStaticTargetName": "serve-static", + "typecheckTargetName": "typecheck", + "buildDepsTargetName": "build-deps", + "watchDepsTargetName": "watch-deps" + } } ], "nxCloudId": "65d4d862d2adb16a45a4bc7c" diff --git a/package-lock.json b/package-lock.json index a08a34481..ed02d41da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", "@nx/vite": "21.4.1", + "@nx/web": "21.4.1", "@nx/workspace": "21.4.1", "@push-based/nx-verdaccio": "0.0.6", "@swc-node/register": "1.9.2", @@ -67,6 +68,7 @@ "@vitest/coverage-v8": "1.3.1", "@vitest/eslint-plugin": "^1.1.38", "@vitest/ui": "1.3.1", + "ajv": "^8.0.0", "benchmark": "^2.1.4", "chrome-launcher": "^1.1.2", "chromium": "^3.0.3", @@ -107,6 +109,7 @@ "typescript-eslint": "^8.18.0", "verdaccio": "6.1.6", "vite": "6.3.5", + "vite-plugin-dts": "~4.5.0", "vitest": "1.3.1", "zod2md": "^0.2.4" }, @@ -3333,6 +3336,29 @@ "node": ">=18" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4265,10 +4291,11 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.30", @@ -4364,6 +4391,156 @@ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, + "node_modules/@microsoft/api-extractor": { + "version": "7.52.11", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.52.11.tgz", + "integrity": "sha512-IKQ7bHg6f/Io3dQds6r9QPYk4q0OlR9A4nFDtNhUt3UUIhyitbxAqRN1CLjUVtk6IBk3xzyCMOdwwtIXQ7AlGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.30.7", + "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.17.1", + "@rushstack/node-core-library": "5.14.0", + "@rushstack/rig-package": "0.5.3", + "@rushstack/terminal": "0.15.4", + "@rushstack/ts-command-line": "5.0.2", + "lodash": "~4.17.15", + "minimatch": "10.0.3", + "resolve": "~1.22.1", + "semver": "~7.5.4", + "source-map": "~0.6.1", + "typescript": "5.8.2" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.30.7", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.7.tgz", + "integrity": "sha512-TBbmSI2/BHpfR9YhQA7nH0nqVmGgJ0xH0Ex4D99/qBDAUpnhA2oikGmdXanbw9AWWY/ExBYIpkmY8dBHdla3YQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.17.1", + "@rushstack/node-core-library": "5.14.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", + "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.1.tgz", + "integrity": "sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.15.1", + "ajv": "~8.12.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@modern-js/node-bundle-require": { "version": "2.68.2", "resolved": "https://registry.npmjs.org/@modern-js/node-bundle-require/-/node-bundle-require-2.68.2.tgz", @@ -7494,6 +7671,171 @@ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true }, + "node_modules/@rushstack/node-core-library": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.14.0.tgz", + "integrity": "sha512-eRong84/rwQUlATGFW3TMTYVyqL1vfW9Lf10PH+mVGfIb9HzU3h5AASNIw+axnBLjnD0n3rT5uQBwu9fvzATrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "~8.13.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.5.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/@rushstack/rig-package": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz", + "integrity": "sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "~1.22.1", + "strip-json-comments": "~3.1.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.15.4", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.4.tgz", + "integrity": "sha512-OQSThV0itlwVNHV6thoXiAYZlQh4Fgvie2CzxFABsbO2MWQsI4zOh3LRNigYSTrmS+ba2j0B3EObakPzf/x6Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.14.0", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.0.2.tgz", + "integrity": "sha512-+AkJDbu1GFMPIU8Sb7TLVXDv/Q7Mkvx+wAjEl8XiXVVq+p1FmWW6M3LYpJMmoHNckSofeMecgWg5lfMwNAAsEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.15.4", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, "node_modules/@sentry/core": { "version": "6.19.7", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", @@ -8626,6 +8968,13 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -10244,6 +10593,126 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@volar/language-core": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.23" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", + "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", + "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/shared": "3.5.20", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", + "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.20", + "@vue/shared": "3.5.20" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/language-core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", + "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.4.9", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.20", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", + "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", + "dev": true, + "license": "MIT" + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -11091,6 +11560,21 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -11120,6 +11604,13 @@ "ajv": "^8.8.2" } }, + "node_modules/alien-signals": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", + "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -13593,6 +14084,13 @@ "dot-prop": "^5.1.0" } }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "dev": true, + "license": "MIT" + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -13693,10 +14191,11 @@ } }, "node_modules/confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", - "dev": true + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" }, "node_modules/configstore": { "version": "5.0.1", @@ -14418,6 +14917,13 @@ "dev": true, "license": "MIT" }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -16834,6 +17340,13 @@ "dev": true, "license": "MIT" }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "dev": true, + "license": "MIT" + }, "node_modules/ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", @@ -17560,9 +18073,10 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-extra": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", - "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -18705,6 +19219,16 @@ "node": ">=8" } }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", @@ -21662,6 +22186,13 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, "node_modules/jpeg-js": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", @@ -22207,6 +22738,13 @@ "node": ">= 0.6" } }, + "node_modules/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -22874,12 +23412,13 @@ } }, "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, "node_modules/magicast": { @@ -23191,17 +23730,25 @@ } }, "node_modules/mlly": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", - "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.1", - "ufo": "^1.5.3" + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" } }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -23226,6 +23773,13 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, "node_modules/multi-progress-bars": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/multi-progress-bars/-/multi-progress-bars-5.0.3.tgz", @@ -24808,16 +25362,24 @@ } }, "node_modules/pkg-types": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz", - "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, + "license": "MIT", "dependencies": { - "confbox": "^0.1.7", - "mlly": "^1.7.1", - "pathe": "^1.1.2" + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/pkginfo": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", @@ -25932,6 +26494,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/query-registry": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/query-registry/-/query-registry-3.0.1.tgz", @@ -29407,10 +29986,11 @@ } }, "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" }, "node_modules/uglify-js": { "version": "3.19.3", @@ -30563,6 +31143,77 @@ } } }, + "node_modules/vite-plugin-dts": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", + "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor": "^7.50.1", + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.11", + "@vue/language-core": "2.2.0", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17" + }, + "peerDependencies": { + "typescript": "*", + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite-plugin-dts/node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-plugin-dts/node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/vite-plugin-dts/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite-plugin-dts/node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, "node_modules/vitest": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", @@ -31123,6 +31774,13 @@ "resolved": "https://registry.npmjs.org/vscode-material-icons/-/vscode-material-icons-0.1.1.tgz", "integrity": "sha512-GsoEEF8Tbb0yUFQ6N6FPvh11kFkL9F95x0FkKlbbfRQN9eFms67h+L3t6b9cUv58dSn2gu8kEhNfoESVCrz4ag==" }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", diff --git a/package.json b/package.json index e1f97c332..8307624fd 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", "@nx/vite": "21.4.1", + "@nx/web": "21.4.1", "@nx/workspace": "21.4.1", "@push-based/nx-verdaccio": "0.0.6", "@swc-node/register": "1.9.2", @@ -80,6 +81,7 @@ "@vitest/coverage-v8": "1.3.1", "@vitest/eslint-plugin": "^1.1.38", "@vitest/ui": "1.3.1", + "ajv": "^8.0.0", "benchmark": "^2.1.4", "chrome-launcher": "^1.1.2", "chromium": "^3.0.3", @@ -120,6 +122,7 @@ "typescript-eslint": "^8.18.0", "verdaccio": "6.1.6", "vite": "6.3.5", + "vite-plugin-dts": "~4.5.0", "vitest": "1.3.1", "zod2md": "^0.2.4" }, diff --git a/tools/eslint-multi-format/README.md b/tools/eslint-multi-format/README.md new file mode 100644 index 000000000..2110bf329 --- /dev/null +++ b/tools/eslint-multi-format/README.md @@ -0,0 +1,95 @@ +# ESLint Multi-Format Formatter + +The ESLint plugin uses a custom formatter that supports multiple output formats and destinations simultaneously. + +## Configuration + +Use the `ESLINT_FORMATTER_CONFIG` environment variable to configure the formatter with JSON. + +### Configuration Schema + +```json +{ + "outputDir": "./reports", // Optional: Output directory (default: cwd/.eslint) + "filename": "eslint-report", // Optional: Base filename without extension (default: 'eslint-report') + "formats": ["json"], // Optional: Array of format names for file output (default: ['json']) + "terminal": "stylish", // Optional: Format for terminal output (default: 'stylish') + "verbose": true // Optional: Enable verbose logging (default: false) +} +``` + +### Supported Formats + +The following ESLint formatters are supported: + +- `stylish` (default terminal output) +- `json` (default file output) +- Custom formatters (fallback to stylish formatting) + +## Usage Examples + +### Basic Usage + +```bash +# Default behavior - JSON file output + stylish console output +npx eslint . + +# Custom output directory and filename +ESLINT_FORMATTER_CONFIG='{"outputDir":"./ci-reports","filename":"lint-results"}' npx eslint . +# Creates: ci-reports/lint-results.json + terminal output +``` + +### Multiple Output Formats + +```bash +# Generate JSON file +ESLINT_FORMATTER_CONFIG='{"formats":["json"],"terminal":"stylish"}' npx eslint . +# Creates: .eslint/eslint-report.json + terminal output + +# Custom directory with JSON format +ESLINT_FORMATTER_CONFIG='{"outputDir":"./reports","filename":"eslint-results","formats":["json"]}' npx eslint . +# Creates: reports/eslint-results.json +``` + +### Terminal Output Only + +```bash +# Only show terminal output, no files +ESLINT_FORMATTER_CONFIG='{"formats":[],"terminal":"stylish"}' npx eslint . + +# Different terminal format +ESLINT_FORMATTER_CONFIG='{"formats":[],"terminal":"stylish"}' npx eslint . +``` + +### Configuration from File + +```bash +# Create a configuration file +cat > eslint-config.json << 'EOF' +{ + "outputDir": "./ci-reports", + "filename": "eslint-report", + "formats": ["json", "stylish"], + "terminal": "stylish", + "verbose": true +} +EOF + +# Use the configuration file +ESLINT_FORMATTER_CONFIG="$(cat eslint-config.json)" npx eslint . +``` + +## Default Behavior + +When no `ESLINT_FORMATTER_CONFIG` is provided, the formatter uses these defaults: + +- **outputDir**: `./.eslint` (relative to current working directory) +- **filename**: `eslint-report` +- **formats**: `["json"]` +- **terminal**: `stylish` +- **verbose**: `false` + +This means by default you get: + +- A JSON file at `./.eslint/eslint-report.json` +- Stylish terminal output diff --git a/tools/eslint-multi-format/eslint.config.js b/tools/eslint-multi-format/eslint.config.js new file mode 100644 index 000000000..40165321a --- /dev/null +++ b/tools/eslint-multi-format/eslint.config.js @@ -0,0 +1,21 @@ +import tseslint from 'typescript-eslint'; +import baseConfig from '../../eslint.config.js'; + +export default tseslint.config( + ...baseConfig, + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': 'error', + }, + }, +); diff --git a/tools/eslint-multi-format/package.json b/tools/eslint-multi-format/package.json new file mode 100644 index 000000000..737978d2e --- /dev/null +++ b/tools/eslint-multi-format/package.json @@ -0,0 +1,37 @@ +{ + "name": "eslint-formatter-multi-format", + "version": "0.0.1", + "private": false, + "type": "module", + "main": "./index.js", + "types": "./index.d.ts", + "description": "ESLint formatter that supports multiple output formats and destinations simultaneously", + "author": "Michael Hladky", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/code-pushup/cli.git", + "directory": "tools/eslint-multi-format" + }, + "keywords": [ + "eslint", + "eslint-formatter", + "eslintformatter", + "multi-format", + "code-quality", + "linting" + ], + "files": [ + "index.js", + "index.d.ts", + "lib/", + "README.md", + "package.json" + ], + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.0 || ^9.0.0" + } +} diff --git a/tools/eslint-multi-format/project.json b/tools/eslint-multi-format/project.json new file mode 100644 index 000000000..076efef1f --- /dev/null +++ b/tools/eslint-multi-format/project.json @@ -0,0 +1,18 @@ +{ + "name": "eslint-multi-formatter", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "tools/eslint-multi-format/src", + "projectType": "library", + "tags": [], + "// targets": "to see all targets run: nx show project eslint-multi-format with option --web for humans and --json for AI", + "targets": { + "lint": {}, + "build": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/eslint-multi-format" + } + } + } +} diff --git a/tools/eslint-multi-format/src/index.ts b/tools/eslint-multi-format/src/index.ts new file mode 100644 index 000000000..6e372fa3e --- /dev/null +++ b/tools/eslint-multi-format/src/index.ts @@ -0,0 +1,3 @@ +export { default } from './lib/multiple-formats.js'; +export * from './lib/multiple-formats.js'; +export * from './lib/utils.js'; diff --git a/tools/eslint-multi-format/src/lib/multiple-formats.ts b/tools/eslint-multi-format/src/lib/multiple-formats.ts new file mode 100644 index 000000000..1aa5b86e3 --- /dev/null +++ b/tools/eslint-multi-format/src/lib/multiple-formats.ts @@ -0,0 +1,76 @@ +import type { ESLint } from 'eslint'; +import path from 'node:path'; +import type { EslintFormat, FormatterConfig } from './types.js'; +import { + findConfigFromEnv as getConfigFromEnv, + getTerminalOutput, + persistEslintReports, +} from './utils.js'; + +export const DEFAULT_OUTPUT_DIR = path.join(process.cwd(), '.eslint'); +export const DEFAULT_FILENAME = 'eslint-report'; +export const DEFAULT_FORMATS = ['json'] as EslintFormat[]; +export const DEFAULT_TERMINAL = 'stylish' as EslintFormat; + +export const DEFAULT_CONFIG: Required = { + outputDir: DEFAULT_OUTPUT_DIR, + filename: DEFAULT_FILENAME, + formats: DEFAULT_FORMATS, + terminal: DEFAULT_TERMINAL, + verbose: false, +}; + +/** + * Format ESLint results using multiple configurable formatters + * + * @param results - The ESLint results + * @param args - The arguments passed to the formatter + * @returns The formatted results for terminal display + * + * @example + * // Basic usage: + * ESLINT_FORMATTER_CONFIG='{"filename":"lint-results","formats":["json"],"terminal":"stylish"}' npx eslint . + * // Creates: .eslint/eslint-results.json + terminal output + * + * // With custom output directory: + * ESLINT_FORMATTER_CONFIG='{"outputDir":"./ci-reports","filename":"eslint-report","formats":["json","html"],"terminal":"stylish"}' nx lint utils + * // Creates: ci-reports/eslint-report.json, ci-reports/eslint-report.html + terminal output + * + * Configuration schema: + * { + * "outputDir": "./reports", // Optional: Output directory (default: cwd/.eslint) + * "filename": "eslint-report", // Optional: Base filename without extension (default: 'eslint-report') + * "formats": ["json"], // Optional: Array of format names for file output (default: ['json']) + * "terminal": "stylish" // Optional: Format for terminal output (default: 'stylish') + * } + */ +export default function multipleFormats( + results: ESLint.LintResult[], + _args?: unknown, +): string { + const config = { ...DEFAULT_CONFIG, ...getConfigFromEnv(process.env) }; + + const { + outputDir = DEFAULT_OUTPUT_DIR, + filename = DEFAULT_FILENAME, + formats = DEFAULT_FORMATS, + terminal, + verbose = false, + } = config; + + const terminalOutput = getTerminalOutput(terminal, results); + + try { + persistEslintReports(formats, results, { + outputDir, + filename, + verbose, + }); + } catch (error) { + if (verbose) { + console.error('Error writing ESLint reports:', error); + } + } + + return terminalOutput; +} diff --git a/tools/eslint-multi-format/src/lib/types.ts b/tools/eslint-multi-format/src/lib/types.ts new file mode 100644 index 000000000..8bce19835 --- /dev/null +++ b/tools/eslint-multi-format/src/lib/types.ts @@ -0,0 +1,9 @@ +export type EslintFormat = 'stylish' | 'json' | string; + +export type FormatterConfig = { + outputDir?: string; + filename?: string; + formats?: EslintFormat[]; + terminal?: EslintFormat; + verbose?: boolean; +}; diff --git a/tools/eslint-multi-format/src/lib/utils.ts b/tools/eslint-multi-format/src/lib/utils.ts new file mode 100644 index 000000000..562f7c858 --- /dev/null +++ b/tools/eslint-multi-format/src/lib/utils.ts @@ -0,0 +1,165 @@ +import type { ESLint } from 'eslint'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import type { EslintFormat, FormatterConfig } from './types.js'; + +export function getExtensionForFormat(format: EslintFormat): string { + const extensionMap: Record = { + json: 'json', + stylish: 'txt', + }; + + return extensionMap[format] || 'txt'; +} + +export function findConfigFromEnv( + env: NodeJS.ProcessEnv, +): FormatterConfig | null { + const configString = env['ESLINT_FORMATTER_CONFIG']; + + if (!configString || configString.trim() === '') { + return null; + } + + try { + return JSON.parse(configString) as FormatterConfig; + } catch (error_) { + console.error( + 'Error parsing ESLINT_FORMATTER_CONFIG environment variable:', + (error_ as Error).message, + ); + return null; + } +} + +export type PersistConfig = { + outputDir: string; + filename: string; + format: EslintFormat; + verbose?: boolean; +}; + +function formatJson(results: ESLint.LintResult[]): string { + return JSON.stringify(results, null, 2); +} + +const LINE_COLUMN_PADDING = 3; +const SEVERITY_PADDING = 7; + +function formatStylish(results: ESLint.LintResult[]): string { + const resultsWithMessages = results.filter( + result => result.messages.length > 0, + ); + + const { output, totalErrors, totalWarnings } = resultsWithMessages.reduce( + (acc, result) => { + const { filePath, messages } = result; + const fileOutput = `\n${filePath}\n`; + + const { messageOutput, errors, warnings } = messages.reduce( + (msgAcc, message) => { + const { + line = 0, + column = 0, + severity, + message: text, + ruleId, + } = message; + const severityText = severity === 2 ? 'error' : 'warning'; + + const ruleIdText = ruleId ? ` ${ruleId}` : ''; + const formattedMessage = ` ${String(line).padStart(LINE_COLUMN_PADDING)}:${String(column).padStart(LINE_COLUMN_PADDING)} ${severityText.padEnd(SEVERITY_PADDING)} ${text}${ruleIdText}\n`; + + return { + messageOutput: msgAcc.messageOutput + formattedMessage, + errors: msgAcc.errors + (severity === 2 ? 1 : 0), + warnings: msgAcc.warnings + (severity === 1 ? 1 : 0), + }; + }, + { messageOutput: '', errors: 0, warnings: 0 }, + ); + + return { + output: acc.output + fileOutput + messageOutput, + totalErrors: acc.totalErrors + errors, + totalWarnings: acc.totalWarnings + warnings, + }; + }, + { output: '', totalErrors: 0, totalWarnings: 0 }, + ); + + const totalProblems = totalErrors + totalWarnings; + const summary = + totalProblems > 0 + ? `\n✖ ${totalProblems} problem${totalProblems === 1 ? '' : 's'} ` + + `(${totalErrors} error${totalErrors === 1 ? '' : 's'}, ${totalWarnings} warning${totalWarnings === 1 ? '' : 's'})` + : ''; + + return output + summary; +} + +export function formatContent( + results: ESLint.LintResult[], + format: EslintFormat, +): string { + switch (format) { + case 'json': + return formatJson(results); + case 'stylish': + return formatStylish(results); + default: + return formatStylish(results); + } +} + +export function getTerminalOutput( + format: EslintFormat | undefined, + results: ESLint.LintResult[], +): string { + if (!format) { + return ''; + } + return formatContent(results, format); +} + +export function persistEslintReport( + content: string, + options: PersistConfig, +): boolean { + const { outputDir, filename, format, verbose = false } = options; + try { + mkdirSync(outputDir, { recursive: true }); + writeFileSync( + path.join(outputDir, `${filename}.${getExtensionForFormat(format)}`), + content, + ); + if (verbose) { + console.log(`ESLint report (${format}) written to: ${outputDir}`); + } + return true; + } catch (error_) { + if (verbose) { + console.error('There was a problem writing the output file:\n%s', error_); + } + return false; + } +} + +export function persistEslintReports( + formats: EslintFormat[], + results: ESLint.LintResult[], + options: { outputDir: string; filename: string; verbose: boolean }, +): boolean { + const { outputDir, filename, verbose } = options; + + return formats.every(format => { + const content = formatContent(results, format); + + return persistEslintReport(content, { + outputDir, + filename, + format, + verbose, + }); + }); +} diff --git a/tools/eslint-multi-format/tsconfig.json b/tools/eslint-multi-format/tsconfig.json new file mode 100644 index 000000000..6914db489 --- /dev/null +++ b/tools/eslint-multi-format/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "forceConsistentCasingInFileNames": true, + "strict": true, + "importHelpers": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/tools/eslint-multi-format/tsconfig.lib.json b/tools/eslint-multi-format/tsconfig.lib.json new file mode 100644 index 000000000..ea5a20dd3 --- /dev/null +++ b/tools/eslint-multi-format/tsconfig.lib.json @@ -0,0 +1,23 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node", "vite/client"] + }, + "include": ["src/**/*.ts"], + "exclude": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ] +} diff --git a/tools/eslint-multi-format/tsconfig.spec.json b/tools/eslint-multi-format/tsconfig.spec.json new file mode 100644 index 000000000..56b748887 --- /dev/null +++ b/tools/eslint-multi-format/tsconfig.spec.json @@ -0,0 +1,28 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ] + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/tools/eslint-multi-format/vite.config.ts b/tools/eslint-multi-format/vite.config.ts new file mode 100644 index 000000000..b93b63aa8 --- /dev/null +++ b/tools/eslint-multi-format/vite.config.ts @@ -0,0 +1,59 @@ +/// +import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin'; +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; +import path from 'node:path'; +import { defineConfig } from 'vite'; +import dts from 'vite-plugin-dts'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../node_modules/.vite/eslint-multi-format', + plugins: [ + nxViteTsPaths(), + nxCopyAssetsPlugin(['*.md']), + dts({ + entryRoot: 'src', + tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), + pathsToAliases: false, + }), + ], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + // Configuration for building your library. + // See: https://vitejs.dev/guide/build.html#library-mode + build: { + outDir: '../../dist/eslint-multi-format', + emptyOutDir: true, + reportCompressedSize: true, + commonjsOptions: { + transformMixedEsModules: true, + }, + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'eslint-multi-format', + fileName: 'index', + // Change this to the formats you want to support. + // Don't forget to update your package.json as well. + formats: ['es' as const], + }, + rollupOptions: { + // External packages that should not be bundled into your library. + external: ['eslint', 'node:fs', 'node:fs/promises', 'node:path'], + }, + }, + test: { + name: 'eslint-multi-format', + watch: false, + globals: true, + environment: 'node', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + coverage: { + reportsDirectory: 'coverage', + provider: 'v8' as const, + }, + }, +})); diff --git a/tools/tsconfig.tools.json b/tools/tsconfig.tools.json index 75c41a56a..159675663 100644 --- a/tools/tsconfig.tools.json +++ b/tools/tsconfig.tools.json @@ -8,5 +8,6 @@ "types": ["node"], "importHelpers": false }, - "include": ["**/*.ts"] + "include": ["**/*.ts"], + "exclude": ["eslint-multi-format/**/*"] } diff --git a/tsconfig.base.json b/tsconfig.base.json index b183db5a3..1b05756db 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -24,6 +24,9 @@ "@code-pushup/cli": ["packages/cli/src/index.ts"], "@code-pushup/core": ["packages/core/src/index.ts"], "@code-pushup/coverage-plugin": ["packages/plugin-coverage/src/index.ts"], + "@code-pushup/eslint-multi-format": [ + "tools/eslint-multi-format/src/index.ts" + ], "@code-pushup/eslint-plugin": ["packages/plugin-eslint/src/index.ts"], "@code-pushup/js-packages-plugin": [ "packages/plugin-js-packages/src/index.ts" From d3e41aa718e411348bc739a59a8932545ab94023 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 27 Aug 2025 20:41:10 +0200 Subject: [PATCH 02/37] chore: stricter plugin usage --- nx.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nx.json b/nx.json index b6ea32734..a3438804c 100644 --- a/nx.json +++ b/nx.json @@ -190,7 +190,8 @@ "typecheckTargetName": "typecheck", "buildDepsTargetName": "build-deps", "watchDepsTargetName": "watch-deps" - } + }, + "include": ["tools/eslint-multi-format/**"] } ], "nxCloudId": "65d4d862d2adb16a45a4bc7c" From ee9aae190d06619140709fb6688eda0195c8ad01 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 27 Aug 2025 20:43:24 +0200 Subject: [PATCH 03/37] chore: remove package --- package-lock.json | 2 -- package.json | 2 -- 2 files changed, 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed02d41da..d60774fb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,6 @@ "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", "@nx/vite": "21.4.1", - "@nx/web": "21.4.1", "@nx/workspace": "21.4.1", "@push-based/nx-verdaccio": "0.0.6", "@swc-node/register": "1.9.2", @@ -68,7 +67,6 @@ "@vitest/coverage-v8": "1.3.1", "@vitest/eslint-plugin": "^1.1.38", "@vitest/ui": "1.3.1", - "ajv": "^8.0.0", "benchmark": "^2.1.4", "chrome-launcher": "^1.1.2", "chromium": "^3.0.3", diff --git a/package.json b/package.json index 8307624fd..0f7f45de6 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", "@nx/vite": "21.4.1", - "@nx/web": "21.4.1", "@nx/workspace": "21.4.1", "@push-based/nx-verdaccio": "0.0.6", "@swc-node/register": "1.9.2", @@ -81,7 +80,6 @@ "@vitest/coverage-v8": "1.3.1", "@vitest/eslint-plugin": "^1.1.38", "@vitest/ui": "1.3.1", - "ajv": "^8.0.0", "benchmark": "^2.1.4", "chrome-launcher": "^1.1.2", "chromium": "^3.0.3", From 416695659cd83027096ef8becd5588168d810c22 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 27 Aug 2025 20:59:11 +0200 Subject: [PATCH 04/37] refactor(eslint-multi-formatter): fix lint --- tools/eslint-multi-format/eslint.config.js | 7 ++++++- tools/eslint-multi-format/src/lib/utils.ts | 3 +++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/eslint-multi-format/eslint.config.js b/tools/eslint-multi-format/eslint.config.js index 40165321a..9b3cdf2b9 100644 --- a/tools/eslint-multi-format/eslint.config.js +++ b/tools/eslint-multi-format/eslint.config.js @@ -15,7 +15,12 @@ export default tseslint.config( { files: ['**/*.json'], rules: { - '@nx/dependency-checks': 'error', + '@nx/dependency-checks': [ + 'error', + { + ignoredDependencies: ['@nx/vite', 'vite', 'vite-plugin-dts'], + }, + ], }, }, ); diff --git a/tools/eslint-multi-format/src/lib/utils.ts b/tools/eslint-multi-format/src/lib/utils.ts index 562f7c858..577fb760b 100644 --- a/tools/eslint-multi-format/src/lib/utils.ts +++ b/tools/eslint-multi-format/src/lib/utils.ts @@ -128,12 +128,15 @@ export function persistEslintReport( ): boolean { const { outputDir, filename, format, verbose = false } = options; try { + // eslint-disable-next-line n/no-sync mkdirSync(outputDir, { recursive: true }); + // eslint-disable-next-line n/no-sync writeFileSync( path.join(outputDir, `${filename}.${getExtensionForFormat(format)}`), content, ); if (verbose) { + // eslint-disable-next-line no-console console.log(`ESLint report (${format}) written to: ${outputDir}`); } return true; From 8208532cb3f4cb8507443a2b6eed7656001d6efb Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:37:17 +0200 Subject: [PATCH 05/37] Update tools/eslint-multi-format/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- tools/eslint-multi-format/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/eslint-multi-format/README.md b/tools/eslint-multi-format/README.md index 2110bf329..32a1fecb0 100644 --- a/tools/eslint-multi-format/README.md +++ b/tools/eslint-multi-format/README.md @@ -8,7 +8,7 @@ Use the `ESLINT_FORMATTER_CONFIG` environment variable to configure the formatte ### Configuration Schema -```json +```jsonc { "outputDir": "./reports", // Optional: Output directory (default: cwd/.eslint) "filename": "eslint-report", // Optional: Base filename without extension (default: 'eslint-report') From d37c4a386a1ed02fd665c31d60908283d16e2c8e Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:37:42 +0200 Subject: [PATCH 06/37] Update tools/eslint-multi-format/src/lib/utils.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- tools/eslint-multi-format/src/lib/utils.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/eslint-multi-format/src/lib/utils.ts b/tools/eslint-multi-format/src/lib/utils.ts index 577fb760b..7ae209144 100644 --- a/tools/eslint-multi-format/src/lib/utils.ts +++ b/tools/eslint-multi-format/src/lib/utils.ts @@ -136,8 +136,7 @@ export function persistEslintReport( content, ); if (verbose) { - // eslint-disable-next-line no-console - console.log(`ESLint report (${format}) written to: ${outputDir}`); + console.info(`ESLint report (${format}) written to: ${outputDir}`); } return true; } catch (error_) { From 1592f62a3ba3aebb507b892ebce4800389930790 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 29 Aug 2025 17:44:03 +0200 Subject: [PATCH 07/37] refactor: full refactor + add tests --- nx.json | 7 + package-lock.json | 112 +++++++++++++ package.json | 1 + packages/plugin-eslint/src/lib/runner/lint.ts | 8 +- .../README.md | 4 +- .../eslint.config.js | 0 .../package.json | 25 +-- .../project.json | 3 +- .../src/index.ts | 0 .../src/lib/multiple-formats.ts | 6 +- .../src/lib/types.ts | 0 .../src/lib/utils.ts | 74 ++------- .../src/lib/utils.unit.test.ts | 150 ++++++++++++++++++ .../tsconfig.json | 0 .../tsconfig.lib.json | 0 .../tsconfig.spec.json | 0 .../vite.config.ts | 16 +- .../vitest.unit.config.ts | 31 ++++ tsconfig.base.json | 4 +- 19 files changed, 343 insertions(+), 98 deletions(-) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/README.md (95%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/eslint.config.js (100%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/package.json (62%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/project.json (87%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/src/index.ts (100%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/src/lib/multiple-formats.ts (95%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/src/lib/types.ts (100%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/src/lib/utils.ts (53%) create mode 100644 tools/eslint-formatter-multiple-formats/src/lib/utils.unit.test.ts rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/tsconfig.json (100%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/tsconfig.lib.json (100%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/tsconfig.spec.json (100%) rename tools/{eslint-multi-format => eslint-formatter-multiple-formats}/vite.config.ts (78%) create mode 100644 tools/eslint-formatter-multiple-formats/vitest.unit.config.ts diff --git a/nx.json b/nx.json index 30631826b..866a44343 100644 --- a/nx.json +++ b/nx.json @@ -16,6 +16,7 @@ "!{projectRoot}/**/?(*.)test.[jt]s?(x)?(.snap)", "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", "!{projectRoot}/**/?(*.)mock.[jt]s?(x)", + "!{projectRoot}/vite.config.[jt]s", "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", "!{projectRoot}/dist/**/*", "!{projectRoot}/tsconfig.@(test|tools).json", @@ -363,6 +364,12 @@ } } }, + { + "plugin": "@nx/eslint", + "options": { + "config": "{projectRoot}/eslint.config.js" + } + }, { "plugin": "@nx/vite/plugin", "options": { diff --git a/package-lock.json b/package-lock.json index 1c3ab4856..b1f43c369 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,6 +73,7 @@ "commitizen": "^4.3.1", "commitlint-plugin-tense": "^1.0.3", "dotenv": "^16.4.5", + "eslint-formatter-stylish": "^8.40.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-functional": "^7.1.0", "eslint-plugin-import": "2.31.0", @@ -16282,6 +16283,110 @@ "eslint": ">=6.0.0" } }, + "node_modules/eslint-formatter-stylish": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint-formatter-stylish/-/eslint-formatter-stylish-8.40.0.tgz", + "integrity": "sha512-blbD5ZSQnjNEUaG38VCO4WG9nfDQWE8/IOmt8DFRHXUIfZikaIXmsQTdWNFk0/e0j7RgIVRza86MpsJ+aHgFLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint-formatter-stylish/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-formatter-stylish/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -29145,6 +29250,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, "node_modules/thingies": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", diff --git a/package.json b/package.json index a4b633a89..3bbca3fdb 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "commitizen": "^4.3.1", "commitlint-plugin-tense": "^1.0.3", "dotenv": "^16.4.5", + "eslint-formatter-stylish": "^8.40.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-functional": "^7.1.0", "eslint-plugin-import": "2.31.0", diff --git a/packages/plugin-eslint/src/lib/runner/lint.ts b/packages/plugin-eslint/src/lib/runner/lint.ts index 80300ded3..b014738c1 100644 --- a/packages/plugin-eslint/src/lib/runner/lint.ts +++ b/packages/plugin-eslint/src/lib/runner/lint.ts @@ -25,7 +25,7 @@ async function executeLint({ patterns, }: ESLintTarget): Promise { // running as CLI because ESLint#lintFiles() runs out of memory - const { stdout } = await executeProcess({ + const { stdout, stderr, code } = await executeProcess({ command: 'npx', args: [ 'eslint', @@ -42,6 +42,12 @@ async function executeLint({ cwd: process.cwd(), }); + if (!stdout.trim()) { + throw new Error( + `ESLint produced empty output. Exit code: ${code}, STDERR: ${stderr}`, + ); + } + return JSON.parse(stdout) as ESLint.LintResult[]; } diff --git a/tools/eslint-multi-format/README.md b/tools/eslint-formatter-multiple-formats/README.md similarity index 95% rename from tools/eslint-multi-format/README.md rename to tools/eslint-formatter-multiple-formats/README.md index 32a1fecb0..b2bfb592f 100644 --- a/tools/eslint-multi-format/README.md +++ b/tools/eslint-formatter-multiple-formats/README.md @@ -1,4 +1,4 @@ -# ESLint Multi-Format Formatter +# ESLint Multiple-Formats Formatter The ESLint plugin uses a custom formatter that supports multiple output formats and destinations simultaneously. @@ -14,7 +14,7 @@ Use the `ESLINT_FORMATTER_CONFIG` environment variable to configure the formatte "filename": "eslint-report", // Optional: Base filename without extension (default: 'eslint-report') "formats": ["json"], // Optional: Array of format names for file output (default: ['json']) "terminal": "stylish", // Optional: Format for terminal output (default: 'stylish') - "verbose": true // Optional: Enable verbose logging (default: false) + "verbose": true, // Optional: Enable verbose logging (default: false) } ``` diff --git a/tools/eslint-multi-format/eslint.config.js b/tools/eslint-formatter-multiple-formats/eslint.config.js similarity index 100% rename from tools/eslint-multi-format/eslint.config.js rename to tools/eslint-formatter-multiple-formats/eslint.config.js diff --git a/tools/eslint-multi-format/package.json b/tools/eslint-formatter-multiple-formats/package.json similarity index 62% rename from tools/eslint-multi-format/package.json rename to tools/eslint-formatter-multiple-formats/package.json index 737978d2e..c1c24c624 100644 --- a/tools/eslint-multi-format/package.json +++ b/tools/eslint-formatter-multiple-formats/package.json @@ -1,17 +1,20 @@ { - "name": "eslint-formatter-multi-format", + "name": "eslint-formatter-multiple-formats", "version": "0.0.1", "private": false, "type": "module", - "main": "./index.js", - "types": "./index.d.ts", + "main": "./src/index.js", + "types": "./src/index.d.ts", + "engines": { + "node": ">=17.0.0" + }, "description": "ESLint formatter that supports multiple output formats and destinations simultaneously", "author": "Michael Hladky", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/code-pushup/cli.git", - "directory": "tools/eslint-multi-format" + "directory": "tools/eslint-formatter-multiple-formats" }, "keywords": [ "eslint", @@ -22,14 +25,14 @@ "linting" ], "files": [ - "index.js", - "index.d.ts", - "lib/", - "README.md", - "package.json" + "src/*", + "README.md" ], - "engines": { - "node": ">=18.0.0" + "publishConfig": { + "access": "public" + }, + "dependencies": { + "eslint-formatter-stylish": "^8.40.0" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0" diff --git a/tools/eslint-multi-format/project.json b/tools/eslint-formatter-multiple-formats/project.json similarity index 87% rename from tools/eslint-multi-format/project.json rename to tools/eslint-formatter-multiple-formats/project.json index 076efef1f..cd5e702bc 100644 --- a/tools/eslint-multi-format/project.json +++ b/tools/eslint-formatter-multiple-formats/project.json @@ -1,5 +1,5 @@ { - "name": "eslint-multi-formatter", + "name": "eslint-formatter-multiple-formats", "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "tools/eslint-multi-format/src", "projectType": "library", @@ -7,6 +7,7 @@ "// targets": "to see all targets run: nx show project eslint-multi-format with option --web for humans and --json for AI", "targets": { "lint": {}, + "unit-test": {}, "build": { "executor": "@nx/vite:build", "outputs": ["{options.outputPath}"], diff --git a/tools/eslint-multi-format/src/index.ts b/tools/eslint-formatter-multiple-formats/src/index.ts similarity index 100% rename from tools/eslint-multi-format/src/index.ts rename to tools/eslint-formatter-multiple-formats/src/index.ts diff --git a/tools/eslint-multi-format/src/lib/multiple-formats.ts b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts similarity index 95% rename from tools/eslint-multi-format/src/lib/multiple-formats.ts rename to tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts index 1aa5b86e3..84a4e7a4c 100644 --- a/tools/eslint-multi-format/src/lib/multiple-formats.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts @@ -2,8 +2,8 @@ import type { ESLint } from 'eslint'; import path from 'node:path'; import type { EslintFormat, FormatterConfig } from './types.js'; import { + formatTerminalOutput, findConfigFromEnv as getConfigFromEnv, - getTerminalOutput, persistEslintReports, } from './utils.js'; @@ -58,8 +58,6 @@ export default function multipleFormats( verbose = false, } = config; - const terminalOutput = getTerminalOutput(terminal, results); - try { persistEslintReports(formats, results, { outputDir, @@ -72,5 +70,5 @@ export default function multipleFormats( } } - return terminalOutput; + return formatTerminalOutput(terminal, results); } diff --git a/tools/eslint-multi-format/src/lib/types.ts b/tools/eslint-formatter-multiple-formats/src/lib/types.ts similarity index 100% rename from tools/eslint-multi-format/src/lib/types.ts rename to tools/eslint-formatter-multiple-formats/src/lib/types.ts diff --git a/tools/eslint-multi-format/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts similarity index 53% rename from tools/eslint-multi-format/src/lib/utils.ts rename to tools/eslint-formatter-multiple-formats/src/lib/utils.ts index 7ae209144..7c3e13039 100644 --- a/tools/eslint-multi-format/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -3,6 +3,11 @@ import { mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import type { EslintFormat, FormatterConfig } from './types.js'; +// Import the stylish formatter - using require, otherwise there is the wrong typing +const stylishFormatter = require('eslint-formatter-stylish') as ( + results: ESLint.LintResult[], +) => string; + export function getExtensionForFormat(format: EslintFormat): string { const extensionMap: Record = { json: 'json', @@ -43,61 +48,6 @@ function formatJson(results: ESLint.LintResult[]): string { return JSON.stringify(results, null, 2); } -const LINE_COLUMN_PADDING = 3; -const SEVERITY_PADDING = 7; - -function formatStylish(results: ESLint.LintResult[]): string { - const resultsWithMessages = results.filter( - result => result.messages.length > 0, - ); - - const { output, totalErrors, totalWarnings } = resultsWithMessages.reduce( - (acc, result) => { - const { filePath, messages } = result; - const fileOutput = `\n${filePath}\n`; - - const { messageOutput, errors, warnings } = messages.reduce( - (msgAcc, message) => { - const { - line = 0, - column = 0, - severity, - message: text, - ruleId, - } = message; - const severityText = severity === 2 ? 'error' : 'warning'; - - const ruleIdText = ruleId ? ` ${ruleId}` : ''; - const formattedMessage = ` ${String(line).padStart(LINE_COLUMN_PADDING)}:${String(column).padStart(LINE_COLUMN_PADDING)} ${severityText.padEnd(SEVERITY_PADDING)} ${text}${ruleIdText}\n`; - - return { - messageOutput: msgAcc.messageOutput + formattedMessage, - errors: msgAcc.errors + (severity === 2 ? 1 : 0), - warnings: msgAcc.warnings + (severity === 1 ? 1 : 0), - }; - }, - { messageOutput: '', errors: 0, warnings: 0 }, - ); - - return { - output: acc.output + fileOutput + messageOutput, - totalErrors: acc.totalErrors + errors, - totalWarnings: acc.totalWarnings + warnings, - }; - }, - { output: '', totalErrors: 0, totalWarnings: 0 }, - ); - - const totalProblems = totalErrors + totalWarnings; - const summary = - totalProblems > 0 - ? `\n✖ ${totalProblems} problem${totalProblems === 1 ? '' : 's'} ` + - `(${totalErrors} error${totalErrors === 1 ? '' : 's'}, ${totalWarnings} warning${totalWarnings === 1 ? '' : 's'})` - : ''; - - return output + summary; -} - export function formatContent( results: ESLint.LintResult[], format: EslintFormat, @@ -106,13 +56,13 @@ export function formatContent( case 'json': return formatJson(results); case 'stylish': - return formatStylish(results); + return stylishFormatter(results); default: - return formatStylish(results); + return stylishFormatter(results); } } -export function getTerminalOutput( +export function formatTerminalOutput( format: EslintFormat | undefined, results: ESLint.LintResult[], ): string { @@ -123,7 +73,7 @@ export function getTerminalOutput( } export function persistEslintReport( - content: string, + results: ESLint.LintResult[], options: PersistConfig, ): boolean { const { outputDir, filename, format, verbose = false } = options; @@ -133,7 +83,7 @@ export function persistEslintReport( // eslint-disable-next-line n/no-sync writeFileSync( path.join(outputDir, `${filename}.${getExtensionForFormat(format)}`), - content, + formatContent(results, format), ); if (verbose) { console.info(`ESLint report (${format}) written to: ${outputDir}`); @@ -155,9 +105,7 @@ export function persistEslintReports( const { outputDir, filename, verbose } = options; return formats.every(format => { - const content = formatContent(results, format); - - return persistEslintReport(content, { + return persistEslintReport(results, { outputDir, filename, format, diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.unit.test.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.unit.test.ts new file mode 100644 index 000000000..effd6d8d4 --- /dev/null +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.unit.test.ts @@ -0,0 +1,150 @@ +import type { ESLint } from 'eslint'; +import { describe, expect, it, vi } from 'vitest'; +import { removeColorCodes } from '@code-pushup/test-utils'; +import { + formatContent, + formatTerminalOutput, + findConfigFromEnv as getConfigFromEnv, + getExtensionForFormat, +} from './utils.js'; + +describe('getExtensionForFormat', () => { + it.each([ + ['json', 'json'], + ['stylish', 'txt'], + ['unknown', 'txt'], + ['', 'txt'], + ])('should return json extension for json format', (format, ext) => { + expect(getExtensionForFormat(format)).toBe(ext); + }); +}); + +describe('getConfigFromEnv', () => { + it('should return null when ESLINT_FORMATTER_CONFIG is not set', () => { + const env = {}; + expect(getConfigFromEnv(env)).toBeNull(); + }); + + it('should return null when ESLINT_FORMATTER_CONFIG is empty string', () => { + const env = { ESLINT_FORMATTER_CONFIG: '' }; + expect(getConfigFromEnv(env)).toBeNull(); + }); + + it('should return null when ESLINT_FORMATTER_CONFIG is whitespace only', () => { + const env = { ESLINT_FORMATTER_CONFIG: ' ' }; + expect(getConfigFromEnv(env)).toBeNull(); + }); + + it('should parse valid JSON configuration', () => { + const config = { + outputDir: './reports', + filename: 'lint-results', + formats: ['json', 'stylish'], + terminal: 'stylish', + }; + const env = { ESLINT_FORMATTER_CONFIG: JSON.stringify(config) }; + + expect(getConfigFromEnv(env)).toEqual(config); + }); + + it('should return null and log error for invalid JSON', () => { + const env = { ESLINT_FORMATTER_CONFIG: '{ invalid json }' }; + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + expect(getConfigFromEnv(env)).toBeNull(); + expect(consoleSpy).toHaveBeenCalledWith( + 'Error parsing ESLINT_FORMATTER_CONFIG environment variable:', + expect.any(String), + ); + }); +}); + +describe('formatContent', () => { + const mockResults: ESLint.LintResult[] = [ + { + filePath: '/test/file.js', + messages: [ + { + line: 1, + column: 1, + message: 'Test error', + severity: 2, + ruleId: 'test-rule', + }, + ], + errorCount: 1, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + fatalErrorCount: 0, + suppressedMessages: [], + usedDeprecatedRules: [], + }, + ]; + + it('should format results as JSON when format is json', () => { + const result = formatContent(mockResults, 'json'); + expect(result).toMatchInlineSnapshot(` + "[ + { + "filePath": "/test/file.js", + "messages": [ + { + "line": 1, + "column": 1, + "message": "Test error", + "severity": 2, + "ruleId": "test-rule" + } + ], + "errorCount": 1, + "warningCount": 0, + "fixableErrorCount": 0, + "fixableWarningCount": 0, + "fatalErrorCount": 0, + "suppressedMessages": [], + "usedDeprecatedRules": [] + } + ]" + `); + }); + + it('should use stylish formatter when format is stylish', () => { + const result = formatContent(mockResults, 'stylish'); + + expect(removeColorCodes(result)).toMatchInlineSnapshot(` + " + /test/file.js + 1:1 error Test error test-rule + + ✖ 1 problem (1 error, 0 warnings) + " + `); + }); + + it('should default to stylish formatter for unknown formats', () => { + const result = formatContent(mockResults, 'unknown' as any); + + expect(removeColorCodes(result)).toMatchInlineSnapshot(` + " + /test/file.js + 1:1 error Test error test-rule + + ✖ 1 problem (1 error, 0 warnings) + " + `); + }); +}); + +describe('formatTerminalOutput', () => { + const mockResults: ESLint.LintResult[] = []; + + it('should return empty string when format is undefined', () => { + expect(formatTerminalOutput(undefined, mockResults)).toBe(''); + }); + + it('should call formatContent when format is provided', () => { + const result = formatTerminalOutput('json', mockResults); + expect(result).toMatchInlineSnapshot(`"[]"`); + }); +}); diff --git a/tools/eslint-multi-format/tsconfig.json b/tools/eslint-formatter-multiple-formats/tsconfig.json similarity index 100% rename from tools/eslint-multi-format/tsconfig.json rename to tools/eslint-formatter-multiple-formats/tsconfig.json diff --git a/tools/eslint-multi-format/tsconfig.lib.json b/tools/eslint-formatter-multiple-formats/tsconfig.lib.json similarity index 100% rename from tools/eslint-multi-format/tsconfig.lib.json rename to tools/eslint-formatter-multiple-formats/tsconfig.lib.json diff --git a/tools/eslint-multi-format/tsconfig.spec.json b/tools/eslint-formatter-multiple-formats/tsconfig.spec.json similarity index 100% rename from tools/eslint-multi-format/tsconfig.spec.json rename to tools/eslint-formatter-multiple-formats/tsconfig.spec.json diff --git a/tools/eslint-multi-format/vite.config.ts b/tools/eslint-formatter-multiple-formats/vite.config.ts similarity index 78% rename from tools/eslint-multi-format/vite.config.ts rename to tools/eslint-formatter-multiple-formats/vite.config.ts index b93b63aa8..3e56933d5 100644 --- a/tools/eslint-multi-format/vite.config.ts +++ b/tools/eslint-formatter-multiple-formats/vite.config.ts @@ -24,7 +24,7 @@ export default defineConfig(() => ({ // Configuration for building your library. // See: https://vitejs.dev/guide/build.html#library-mode build: { - outDir: '../../dist/eslint-multi-format', + outDir: './dist', emptyOutDir: true, reportCompressedSize: true, commonjsOptions: { @@ -33,7 +33,7 @@ export default defineConfig(() => ({ lib: { // Could also be a dictionary or array of multiple entry points. entry: 'src/index.ts', - name: 'eslint-multi-format', + name: 'eslint-formatter-multiple-formats', fileName: 'index', // Change this to the formats you want to support. // Don't forget to update your package.json as well. @@ -44,16 +44,4 @@ export default defineConfig(() => ({ external: ['eslint', 'node:fs', 'node:fs/promises', 'node:path'], }, }, - test: { - name: 'eslint-multi-format', - watch: false, - globals: true, - environment: 'node', - include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - reporters: ['default'], - coverage: { - reportsDirectory: 'coverage', - provider: 'v8' as const, - }, - }, })); diff --git a/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts b/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts new file mode 100644 index 000000000..1f0c2b4d0 --- /dev/null +++ b/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts @@ -0,0 +1,31 @@ +/// +import { defineConfig } from 'vite'; +import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; + +export default defineConfig({ + cacheDir: '../../node_modules/.vite/plugin-eslint', + test: { + reporters: ['basic'], + globals: true, + cache: { + dir: '../../node_modules/.vitest', + }, + alias: tsconfigPathAliases(), + pool: 'threads', + poolOptions: { threads: { singleThread: true } }, + coverage: { + reporter: ['text', 'lcov'], + reportsDirectory: '../../coverage/plugin-eslint/unit-tests', + exclude: ['mocks/**', '**/types.ts'], + }, + environment: 'node', + include: ['src/**/*.unit.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + exclude: ['src/index.ts'], + globalSetup: ['../../global-setup.ts'], + setupFiles: [ + '../../testing/test-setup/src/lib/console.mock.ts', + '../../testing/test-setup/src/lib/fs.mock.ts', + '../../testing/test-setup/src/lib/reset.mocks.ts', + ], + }, +}); diff --git a/tsconfig.base.json b/tsconfig.base.json index 1b05756db..75f739be3 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -24,8 +24,8 @@ "@code-pushup/cli": ["packages/cli/src/index.ts"], "@code-pushup/core": ["packages/core/src/index.ts"], "@code-pushup/coverage-plugin": ["packages/plugin-coverage/src/index.ts"], - "@code-pushup/eslint-multi-format": [ - "tools/eslint-multi-format/src/index.ts" + "@code-pushup/eslint-formatter-multiple-formats": [ + "tools/eslint-formatter-multiple-formats/src/index.ts" ], "@code-pushup/eslint-plugin": ["packages/plugin-eslint/src/index.ts"], "@code-pushup/js-packages-plugin": [ From 56cf11e215cbaefd29fbf927dfd439e5461e58fb Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 29 Aug 2025 18:21:03 +0200 Subject: [PATCH 08/37] refactor: use error helper --- .../src/lib/utils.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index 7c3e13039..a1d9ab3aa 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -1,6 +1,7 @@ import type { ESLint } from 'eslint'; import { mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { stringifyError } from '@code-pushup/utils'; import type { EslintFormat, FormatterConfig } from './types.js'; // Import the stylish formatter - using require, otherwise there is the wrong typing @@ -28,10 +29,10 @@ export function findConfigFromEnv( try { return JSON.parse(configString) as FormatterConfig; - } catch (error_) { + } catch (error) { console.error( 'Error parsing ESLINT_FORMATTER_CONFIG environment variable:', - (error_ as Error).message, + stringifyError(error), ); return null; } @@ -89,9 +90,12 @@ export function persistEslintReport( console.info(`ESLint report (${format}) written to: ${outputDir}`); } return true; - } catch (error_) { + } catch (error) { if (verbose) { - console.error('There was a problem writing the output file:\n%s', error_); + console.error( + 'There was a problem writing the output file:\n%s', + stringifyError(error), + ); } return false; } From 53c5796b9a237c17975b5c49fe4bea38d62fea85 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 29 Aug 2025 19:05:09 +0200 Subject: [PATCH 09/37] refactor: fix lint --- tools/eslint-formatter-multiple-formats/package.json | 3 ++- tools/eslint-formatter-multiple-formats/src/lib/utils.ts | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/eslint-formatter-multiple-formats/package.json b/tools/eslint-formatter-multiple-formats/package.json index c1c24c624..6b1337fb1 100644 --- a/tools/eslint-formatter-multiple-formats/package.json +++ b/tools/eslint-formatter-multiple-formats/package.json @@ -32,7 +32,8 @@ "access": "public" }, "dependencies": { - "eslint-formatter-stylish": "^8.40.0" + "eslint-formatter-stylish": "^8.40.0", + "@code-pushup/utils": "0.77.0" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0" diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index a1d9ab3aa..b3670a2ea 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -108,12 +108,12 @@ export function persistEslintReports( ): boolean { const { outputDir, filename, verbose } = options; - return formats.every(format => { - return persistEslintReport(results, { + return formats.every(format => + persistEslintReport(results, { outputDir, filename, format, verbose, - }); - }); + }), + ); } From 4de3d33ce373559455e4dc5abbd2d5ee1d33375b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 1 Sep 2025 19:22:45 +0200 Subject: [PATCH 10/37] refactor: fix lint formatter usage --- .github/workflows/ci.yml | 2 +- code-pushup.preset.ts | 8 +- nx.json | 14 +- packages/utils/project.json | 1 + .../package.json | 3 +- .../project.json | 2 +- .../src/lib/multiple-formats.ts | 31 ++- .../src/lib/types.ts | 9 +- .../src/lib/utils.ts | 235 ++++++++++++++++-- .../vite.config.ts | 14 +- 10 files changed, 277 insertions(+), 42 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edcf22380..c05bfa025 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: npm ci - name: Lint affected projects - run: npx nx affected:lint --parallel=3 + run: ESLINT_FORMATTER_PROJECTS_DIR=packages npx nx affected:lint --parallel=3 unit-test: strategy: diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 58ae48c4e..af0cf11b6 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -177,7 +177,13 @@ export const eslintCoreConfigNx = async ( eslintrc: `packages/${projectName}/eslint.config.js`, patterns: ['.'], }) - : await eslintPlugin(await eslintConfigFromAllNxProjects()), + : await eslintPlugin(await eslintConfigFromAllNxProjects(), { + artifacts: { + generateArtifactsCommand: + 'ESLINT_FORMATTER_PROJECTS_DIR=packages NX_TUI=false npx nx run-many -t lint --include="packages/**"', + artifactsPaths: ['packages/**/.eslint/eslint-report.json'], + }, + }), ], categories: eslintCategories, }); diff --git a/nx.json b/nx.json index 866a44343..24d01c91c 100644 --- a/nx.json +++ b/nx.json @@ -97,6 +97,7 @@ "cache": true }, "lint": { + "dependsOn": ["eslint-formatter-multiple-formats:build"], "inputs": ["lint-eslint-inputs"], "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"], @@ -104,6 +105,7 @@ "options": { "errorOnUnmatchedPattern": false, "maxWarnings": 0, + "format": "./tools/eslint-formatter-multiple-formats/dist/index.js", "lintFilePatterns": [ "{projectRoot}/**/*.ts", "{projectRoot}/package.json" @@ -127,16 +129,12 @@ } }, "lint-formatter": { - "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], - "outputs": ["{projectRoot}/.eslint/eslint-report*.json"], - "cache": true, + "dependsOn": ["eslint-formatter-multiple-formats:build"], + "inputs": ["lint-eslint-inputs"], "executor": "nx:run-commands", "options": { - "command": "nx lint {projectName}", - "args": ["--format=./dist/eslint-multi-format/index.js"], - "env": { - "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" - } + "command": "./tools/scripts/lint-formatter.sh {projectName} {projectRoot}", + "cwd": "{workspaceRoot}" } }, "nxv-pkg-install": { diff --git a/packages/utils/project.json b/packages/utils/project.json index 2953464ca..f41b5308e 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -7,6 +7,7 @@ "build": {}, "lint": {}, "lint-report": {}, + "lint-formatter": {}, "perf": { "command": "npx tsx --tsconfig=../tsconfig.perf.json", "options": { diff --git a/tools/eslint-formatter-multiple-formats/package.json b/tools/eslint-formatter-multiple-formats/package.json index 6b1337fb1..a753e8792 100644 --- a/tools/eslint-formatter-multiple-formats/package.json +++ b/tools/eslint-formatter-multiple-formats/package.json @@ -32,8 +32,7 @@ "access": "public" }, "dependencies": { - "eslint-formatter-stylish": "^8.40.0", - "@code-pushup/utils": "0.77.0" + "ansis": "^3.3.0" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0" diff --git a/tools/eslint-formatter-multiple-formats/project.json b/tools/eslint-formatter-multiple-formats/project.json index cd5e702bc..5869b5c90 100644 --- a/tools/eslint-formatter-multiple-formats/project.json +++ b/tools/eslint-formatter-multiple-formats/project.json @@ -12,7 +12,7 @@ "executor": "@nx/vite:build", "outputs": ["{options.outputPath}"], "options": { - "outputPath": "dist/eslint-multi-format" + "outputPath": "{projectRoot}/dist" } } } diff --git a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts index 84a4e7a4c..4d4f73d54 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts @@ -1,18 +1,25 @@ import type { ESLint } from 'eslint'; import path from 'node:path'; -import type { EslintFormat, FormatterConfig } from './types.js'; +import * as process from 'node:process'; +import type { FormatterConfig } from './types.js'; +import type { EslintFormat } from './utils.js'; import { formatTerminalOutput, findConfigFromEnv as getConfigFromEnv, persistEslintReports, } from './utils.js'; -export const DEFAULT_OUTPUT_DIR = path.join(process.cwd(), '.eslint'); +export const DEFAULT_OUTPUT_DIR = '.eslint'; export const DEFAULT_FILENAME = 'eslint-report'; export const DEFAULT_FORMATS = ['json'] as EslintFormat[]; export const DEFAULT_TERMINAL = 'stylish' as EslintFormat; -export const DEFAULT_CONFIG: Required = { +export const DEFAULT_CONFIG: Required< + Pick< + FormatterConfig, + 'outputDir' | 'filename' | 'formats' | 'terminal' | 'verbose' + > +> = { outputDir: DEFAULT_OUTPUT_DIR, filename: DEFAULT_FILENAME, formats: DEFAULT_FORMATS, @@ -48,19 +55,29 @@ export default function multipleFormats( results: ESLint.LintResult[], _args?: unknown, ): string { - const config = { ...DEFAULT_CONFIG, ...getConfigFromEnv(process.env) }; + const config = { + ...DEFAULT_CONFIG, + ...getConfigFromEnv(process.env), + } satisfies FormatterConfig; const { outputDir = DEFAULT_OUTPUT_DIR, - filename = DEFAULT_FILENAME, - formats = DEFAULT_FORMATS, + projectsDir, + projectName = process.env['NX_TASK_TARGET_PROJECT'], + filename, + formats, terminal, verbose = false, } = config; + const filalOutputDir = + typeof projectName === 'string' && typeof projectsDir === 'string' + ? path.join(projectsDir ?? '', projectName ?? '', outputDir) + : outputDir; + try { persistEslintReports(formats, results, { - outputDir, + outputDir: filalOutputDir, filename, verbose, }); diff --git a/tools/eslint-formatter-multiple-formats/src/lib/types.ts b/tools/eslint-formatter-multiple-formats/src/lib/types.ts index 8bce19835..d878163f6 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/types.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/types.ts @@ -1,9 +1,8 @@ -export type EslintFormat = 'stylish' | 'json' | string; +import type { EslintFormat, PersistConfig } from './utils.js'; -export type FormatterConfig = { - outputDir?: string; - filename?: string; +export type FormatterConfig = Omit & { + projectsDir?: string; // e.g. 'apps' or 'packages' to make paths relative to these folders + projectName?: string; // e.g. 'utils' or 'models' also auto-derived for Nx environment variables formats?: EslintFormat[]; terminal?: EslintFormat; - verbose?: boolean; }; diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index b3670a2ea..a0fcc9b4e 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -1,13 +1,207 @@ +// Import ansis for colors (similar to chalk) +import { bold, dim, red, reset, underline, yellow } from 'ansis'; import type { ESLint } from 'eslint'; import { mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; -import { stringifyError } from '@code-pushup/utils'; -import type { EslintFormat, FormatterConfig } from './types.js'; +import type { FormatterConfig } from './types.js'; -// Import the stylish formatter - using require, otherwise there is the wrong typing -const stylishFormatter = require('eslint-formatter-stylish') as ( - results: ESLint.LintResult[], -) => string; +// Helper function to pluralize words +function pluralize(word: string, count: number): string { + return count === 1 ? word : `${word}s`; +} + +// Simple function to strip ANSI codes for length calculation +function stripAnsi(str: string): string { + // eslint-disable-next-line no-control-regex + return str.replace(/\u001b\[[0-9;]*m/g, ''); +} + +// Simple table formatting function +function createTable( + data: (string | number)[][], + options: { align?: string[]; stringLength?: (str: string) => number } = {}, +): string { + const { align = [], stringLength = s => s.length } = options; + + if (data.length === 0) return ''; + + // Calculate column widths + const colWidths: number[] = []; + data.forEach(row => { + row.forEach((cell, colIndex) => { + const cellStr = String(cell); + const width = stringLength(cellStr); + colWidths[colIndex] = Math.max(colWidths[colIndex] || 0, width); + }); + }); + + // Format rows + return data + .map(row => { + return row + .map((cell, colIndex) => { + const cellStr = String(cell); + const width = colWidths[colIndex] || 0; + const padding = width - stringLength(cellStr); + + if (align[colIndex] === 'r') { + return ' '.repeat(padding) + cellStr; + } + return cellStr + ' '.repeat(padding); + }) + .join(' '); + }) + .join('\n'); +} + +// Inline stylish formatter implementation using ansis +function stylishFormatter(results: ESLint.LintResult[]): string { + let output = '\n'; + let errorCount = 0; + let warningCount = 0; + let fixableErrorCount = 0; + let fixableWarningCount = 0; + let summaryColor = 'yellow' as 'yellow' | 'red'; + + results.forEach(result => { + const messages = result.messages; + + if (messages.length === 0) { + return; + } + + errorCount += result.errorCount; + warningCount += result.warningCount; + fixableErrorCount += result.fixableErrorCount; + fixableWarningCount += result.fixableWarningCount; + + output += `${underline(result.filePath)}\n`; + + const tableData = messages.map(message => { + let messageType: string; + + if (message.fatal || message.severity === 2) { + messageType = red('error'); + summaryColor = 'red'; + } else { + messageType = yellow('warning'); + } + + return [ + '', + message.line || 0, + message.column || 0, + messageType, + message.message.replace(/([^ ])\.$/u, '$1'), + dim(message.ruleId || ''), + ]; + }); + + const table = createTable(tableData, { + align: ['', 'r', 'l'], + stringLength: (str: string) => stripAnsi(str).length, + }); + + // Format line:column numbers with dim styling + const formattedTable = table + .split('\n') + .map(line => + line.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) => dim(`${p1}:${p2}`)), + ) + .join('\n'); + + output += `${formattedTable}\n\n`; + }); + + const total = errorCount + warningCount; + + if (total > 0) { + if (summaryColor === 'red') { + output += bold( + red( + [ + '\u2716 ', + total, + pluralize(' problem', total), + ' (', + errorCount, + pluralize(' error', errorCount), + ', ', + warningCount, + pluralize(' warning', warningCount), + ')\n', + ].join(''), + ), + ); + + if (fixableErrorCount > 0 || fixableWarningCount > 0) { + output += bold( + red( + [ + ' ', + fixableErrorCount, + pluralize(' error', fixableErrorCount), + ' and ', + fixableWarningCount, + pluralize(' warning', fixableWarningCount), + ' potentially fixable with the `--fix` option.\n', + ].join(''), + ), + ); + } + } else { + output += bold( + yellow( + [ + '\u2716 ', + total, + pluralize(' problem', total), + ' (', + errorCount, + pluralize(' error', errorCount), + ', ', + warningCount, + pluralize(' warning', warningCount), + ')\n', + ].join(''), + ), + ); + + if (fixableErrorCount > 0 || fixableWarningCount > 0) { + output += bold( + yellow( + [ + ' ', + fixableErrorCount, + pluralize(' error', fixableErrorCount), + ' and ', + fixableWarningCount, + pluralize(' warning', fixableWarningCount), + ' potentially fixable with the `--fix` option.\n', + ].join(''), + ), + ); + } + } + } + + // Reset output color to prevent changes at top level + return total > 0 ? reset(output) : ''; +} + +export function stringifyError(error: unknown): string { + // TODO: special handling for ZodError instances + if (error instanceof Error) { + if (error.name === 'Error' || error.message.startsWith(error.name)) { + return error.message; + } + return `${error.name}: ${error.message}`; + } + if (typeof error === 'string') { + return error; + } + return JSON.stringify(error); +} export function getExtensionForFormat(format: EslintFormat): string { const extensionMap: Record = { @@ -22,13 +216,20 @@ export function findConfigFromEnv( env: NodeJS.ProcessEnv, ): FormatterConfig | null { const configString = env['ESLINT_FORMATTER_CONFIG']; + const projectsDir = env['ESLINT_FORMATTER_PROJECTS_DIR']; - if (!configString || configString.trim() === '') { + if ( + (!configString || configString.trim() === '') && + (!projectsDir || projectsDir.trim() === '') + ) { return null; } try { - return JSON.parse(configString) as FormatterConfig; + return { + ...(JSON.parse(configString ?? '{}') as FormatterConfig), + projectsDir: env['ESLINT_FORMATTER_PROJECTS_DIR'], + }; } catch (error) { console.error( 'Error parsing ESLINT_FORMATTER_CONFIG environment variable:', @@ -38,13 +239,6 @@ export function findConfigFromEnv( } } -export type PersistConfig = { - outputDir: string; - filename: string; - format: EslintFormat; - verbose?: boolean; -}; - function formatJson(results: ESLint.LintResult[]): string { return JSON.stringify(results, null, 2); } @@ -73,6 +267,15 @@ export function formatTerminalOutput( return formatContent(results, format); } +export type EslintFormat = 'stylish' | 'json' | string; + +export type PersistConfig = { + outputDir: string; // e.g. './.eslint' to make paths relative to this folder + filename: string; + format: EslintFormat; + verbose: boolean; +}; + export function persistEslintReport( results: ESLint.LintResult[], options: PersistConfig, @@ -104,7 +307,7 @@ export function persistEslintReport( export function persistEslintReports( formats: EslintFormat[], results: ESLint.LintResult[], - options: { outputDir: string; filename: string; verbose: boolean }, + options: Omit, ): boolean { const { outputDir, filename, verbose } = options; diff --git a/tools/eslint-formatter-multiple-formats/vite.config.ts b/tools/eslint-formatter-multiple-formats/vite.config.ts index 3e56933d5..46320f2c9 100644 --- a/tools/eslint-formatter-multiple-formats/vite.config.ts +++ b/tools/eslint-formatter-multiple-formats/vite.config.ts @@ -41,7 +41,19 @@ export default defineConfig(() => ({ }, rollupOptions: { // External packages that should not be bundled into your library. - external: ['eslint', 'node:fs', 'node:fs/promises', 'node:path'], + external: [ + 'eslint', + 'ansis', + 'node:fs', + 'node:fs/promises', + 'node:path', + 'node:process', + ], }, }, + define: { + // Preserve Node.js globals + 'process.env': 'process.env', + 'process.cwd': 'process.cwd', + }, })); From d3351f0de6566ad738e365de63b6ce2e9cb649bc Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 1 Sep 2025 19:51:16 +0200 Subject: [PATCH 11/37] refactor: fix lint formatter lint --- .../eslint.config.js | 1 + .../project.json | 2 +- .../src/lib/multiple-formats.ts | 2 +- .../src/lib/utils.ts | 280 +++++++++--------- .../tsconfig.spec.json | 1 + .../vitest.unit.config.ts | 1 + 6 files changed, 145 insertions(+), 142 deletions(-) diff --git a/tools/eslint-formatter-multiple-formats/eslint.config.js b/tools/eslint-formatter-multiple-formats/eslint.config.js index 9b3cdf2b9..652af0285 100644 --- a/tools/eslint-formatter-multiple-formats/eslint.config.js +++ b/tools/eslint-formatter-multiple-formats/eslint.config.js @@ -21,6 +21,7 @@ export default tseslint.config( ignoredDependencies: ['@nx/vite', 'vite', 'vite-plugin-dts'], }, ], + 'n/no-sync': 'off', }, }, ); diff --git a/tools/eslint-formatter-multiple-formats/project.json b/tools/eslint-formatter-multiple-formats/project.json index 5869b5c90..16e10aee5 100644 --- a/tools/eslint-formatter-multiple-formats/project.json +++ b/tools/eslint-formatter-multiple-formats/project.json @@ -3,7 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "tools/eslint-multi-format/src", "projectType": "library", - "tags": [], + "tags": ["scope:tooling", "type:util"], "// targets": "to see all targets run: nx show project eslint-multi-format with option --web for humans and --json for AI", "targets": { "lint": {}, diff --git a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts index 4d4f73d54..99f82cf98 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts @@ -2,8 +2,8 @@ import type { ESLint } from 'eslint'; import path from 'node:path'; import * as process from 'node:process'; import type { FormatterConfig } from './types.js'; -import type { EslintFormat } from './utils.js'; import { + type EslintFormat, formatTerminalOutput, findConfigFromEnv as getConfigFromEnv, persistEslintReports, diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index a0fcc9b4e..7aaf3053a 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -13,7 +13,7 @@ function pluralize(word: string, count: number): string { // Simple function to strip ANSI codes for length calculation function stripAnsi(str: string): string { // eslint-disable-next-line no-control-regex - return str.replace(/\u001b\[[0-9;]*m/g, ''); + return str.replace(/\u001B\[[\d;]*m/g, ''); } // Simple table formatting function @@ -23,22 +23,31 @@ function createTable( ): string { const { align = [], stringLength = s => s.length } = options; - if (data.length === 0) return ''; + if (data.length === 0) { + return ''; + } // Calculate column widths - const colWidths: number[] = []; - data.forEach(row => { - row.forEach((cell, colIndex) => { - const cellStr = String(cell); - const width = stringLength(cellStr); - colWidths[colIndex] = Math.max(colWidths[colIndex] || 0, width); - }); - }); + const colWidths: number[] = data.reduce( + (widths, row) => + row.reduce((acc, cell, colIndex) => { + const cellStr = String(cell); + const width = stringLength(cellStr); + const currentWidth = acc[colIndex] || 0; + const maxWidth = Math.max(currentWidth, width); + return [ + ...acc.slice(0, colIndex), + maxWidth, + ...acc.slice(colIndex + 1), + ]; + }, widths), + [], + ); // Format rows return data - .map(row => { - return row + .map(row => + row .map((cell, colIndex) => { const cellStr = String(cell); const width = colWidths[colIndex] || 0; @@ -49,148 +58,139 @@ function createTable( } return cellStr + ' '.repeat(padding); }) - .join(' '); - }) + .join(' '), + ) .join('\n'); } -// Inline stylish formatter implementation using ansis -function stylishFormatter(results: ESLint.LintResult[]): string { - let output = '\n'; - let errorCount = 0; - let warningCount = 0; - let fixableErrorCount = 0; - let fixableWarningCount = 0; - let summaryColor = 'yellow' as 'yellow' | 'red'; - - results.forEach(result => { - const messages = result.messages; - - if (messages.length === 0) { - return; - } +// Summary statistics for lint results +type LintSummary = { + errorCount: number; + warningCount: number; + fixableErrorCount: number; + fixableWarningCount: number; + summaryColor: 'yellow' | 'red'; +}; - errorCount += result.errorCount; - warningCount += result.warningCount; - fixableErrorCount += result.fixableErrorCount; - fixableWarningCount += result.fixableWarningCount; - - output += `${underline(result.filePath)}\n`; - - const tableData = messages.map(message => { - let messageType: string; - - if (message.fatal || message.severity === 2) { - messageType = red('error'); - summaryColor = 'red'; - } else { - messageType = yellow('warning'); - } - - return [ - '', - message.line || 0, - message.column || 0, - messageType, - message.message.replace(/([^ ])\.$/u, '$1'), - dim(message.ruleId || ''), - ]; - }); - - const table = createTable(tableData, { - align: ['', 'r', 'l'], - stringLength: (str: string) => stripAnsi(str).length, - }); - - // Format line:column numbers with dim styling - const formattedTable = table - .split('\n') - .map(line => - line.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) => dim(`${p1}:${p2}`)), - ) - .join('\n'); - - output += `${formattedTable}\n\n`; +// Calculate summary statistics from results +function calculateSummary(results: ESLint.LintResult[]): LintSummary { + return results.reduce( + (summary, result) => ({ + errorCount: summary.errorCount + result.errorCount, + warningCount: summary.warningCount + result.warningCount, + fixableErrorCount: summary.fixableErrorCount + result.fixableErrorCount, + fixableWarningCount: + summary.fixableWarningCount + result.fixableWarningCount, + summaryColor: + result.errorCount > 0 ? ('red' as const) : summary.summaryColor, + }), + { + errorCount: 0, + warningCount: 0, + fixableErrorCount: 0, + fixableWarningCount: 0, + summaryColor: 'yellow', + }, + ); +} + +// Format a single result file +function formatResultFile(result: ESLint.LintResult): string { + if (result.messages.length === 0) { + return ''; + } + + const header = `${underline(result.filePath)}\n`; + + const tableData = result.messages.map(message => { + const messageType = + message.fatal || message.severity === 2 + ? red('error') + : yellow('warning'); + + return [ + '', + message.line || 0, + message.column || 0, + messageType, + message.message.replace(/([^ ])\.$/u, '$1'), + dim(message.ruleId || ''), + ]; }); - const total = errorCount + warningCount; + const table = createTable(tableData, { + align: ['', 'r', 'l'], + stringLength: (str: string) => stripAnsi(str).length, + }); - if (total > 0) { - if (summaryColor === 'red') { - output += bold( - red( - [ - '\u2716 ', - total, - pluralize(' problem', total), - ' (', - errorCount, - pluralize(' error', errorCount), - ', ', - warningCount, - pluralize(' warning', warningCount), - ')\n', - ].join(''), - ), - ); + const formattedTable = table + .split('\n') + .map(line => + line.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) => dim(`${p1}:${p2}`)), + ) + .join('\n'); - if (fixableErrorCount > 0 || fixableWarningCount > 0) { - output += bold( - red( - [ - ' ', - fixableErrorCount, - pluralize(' error', fixableErrorCount), - ' and ', - fixableWarningCount, - pluralize(' warning', fixableWarningCount), - ' potentially fixable with the `--fix` option.\n', - ].join(''), - ), - ); - } - } else { - output += bold( - yellow( - [ - '\u2716 ', - total, - pluralize(' problem', total), - ' (', - errorCount, - pluralize(' error', errorCount), - ', ', - warningCount, - pluralize(' warning', warningCount), - ')\n', - ].join(''), - ), - ); + return `${header}${formattedTable}\n\n`; +} - if (fixableErrorCount > 0 || fixableWarningCount > 0) { - output += bold( - yellow( - [ - ' ', - fixableErrorCount, - pluralize(' error', fixableErrorCount), - ' and ', - fixableWarningCount, - pluralize(' warning', fixableWarningCount), - ' potentially fixable with the `--fix` option.\n', - ].join(''), - ), - ); - } - } +// Format summary section +function formatSummary(summary: LintSummary): string { + const { + errorCount, + warningCount, + fixableErrorCount, + fixableWarningCount, + summaryColor, + } = summary; + const total = errorCount + warningCount; + + if (total === 0) { + return ''; + } + + const colorFn = summaryColor === 'red' ? red : yellow; + const problemText = [ + '\u2716 ', + total, + pluralize(' problem', total), + ' (', + errorCount, + pluralize(' error', errorCount), + ', ', + warningCount, + pluralize(' warning', warningCount), + ')\n', + ].join(''); + + const problemOutput = bold(colorFn(problemText)); + + if (fixableErrorCount > 0 || fixableWarningCount > 0) { + const fixableText = [ + ' ', + fixableErrorCount, + pluralize(' error', fixableErrorCount), + ' and ', + fixableWarningCount, + pluralize(' warning', fixableWarningCount), + ' potentially fixable with the `--fix` option.\n', + ].join(''); + + return problemOutput + bold(colorFn(fixableText)); } - // Reset output color to prevent changes at top level - return total > 0 ? reset(output) : ''; + return problemOutput; +} + +function stylishFormatter(results: ESLint.LintResult[]): string { + const summary = calculateSummary(results); + const filesOutput = results.map(formatResultFile).join(''); + const summaryOutput = formatSummary(summary); + + const total = summary.errorCount + summary.warningCount; + return total > 0 ? reset(`\n${filesOutput}${summaryOutput}`) : ''; } export function stringifyError(error: unknown): string { - // TODO: special handling for ZodError instances if (error instanceof Error) { if (error.name === 'Error' || error.message.startsWith(error.name)) { return error.message; diff --git a/tools/eslint-formatter-multiple-formats/tsconfig.spec.json b/tools/eslint-formatter-multiple-formats/tsconfig.spec.json index 56b748887..827403667 100644 --- a/tools/eslint-formatter-multiple-formats/tsconfig.spec.json +++ b/tools/eslint-formatter-multiple-formats/tsconfig.spec.json @@ -15,6 +15,7 @@ "vite.config.mts", "vitest.config.ts", "vitest.config.mts", + "vitest.unit.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.test.tsx", diff --git a/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts b/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts index 1f0c2b4d0..d6e409500 100644 --- a/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts +++ b/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts @@ -1,5 +1,6 @@ /// import { defineConfig } from 'vite'; +// eslint-disable-next-line import/no-useless-path-segments import { tsconfigPathAliases } from '../../tools/vitest-tsconfig-path-aliases.js'; export default defineConfig({ From a786407bdacb085e096b38161c4e38e399319aa7 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 1 Sep 2025 20:19:37 +0200 Subject: [PATCH 12/37] refactor: adjust lint targets --- nx.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nx.json b/nx.json index 24d01c91c..f1f88eaab 100644 --- a/nx.json +++ b/nx.json @@ -133,8 +133,10 @@ "inputs": ["lint-eslint-inputs"], "executor": "nx:run-commands", "options": { - "command": "./tools/scripts/lint-formatter.sh {projectName} {projectRoot}", - "cwd": "{workspaceRoot}" + "command": "nx run lint {projectName}", + "env": { + "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" + } } }, "nxv-pkg-install": { From e1554d6adc26c08d629b8bdf4da3cb4a57230011 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 1 Sep 2025 20:35:32 +0200 Subject: [PATCH 13/37] refactor: remove packages --- nx.json | 4 +- package-lock.json | 832 +----------------- package.json | 2 - .../project.json | 8 +- .../vite.config.ts | 59 -- 5 files changed, 34 insertions(+), 871 deletions(-) delete mode 100644 tools/eslint-formatter-multiple-formats/vite.config.ts diff --git a/nx.json b/nx.json index f1f88eaab..414f0c765 100644 --- a/nx.json +++ b/nx.json @@ -16,7 +16,6 @@ "!{projectRoot}/**/?(*.)test.[jt]s?(x)?(.snap)", "!{projectRoot}/**/?(*.)mocks.[jt]s?(x)", "!{projectRoot}/**/?(*.)mock.[jt]s?(x)", - "!{projectRoot}/vite.config.[jt]s", "!{projectRoot}/vitest.@(unit|int|e2e).config.[jt]s", "!{projectRoot}/dist/**/*", "!{projectRoot}/tsconfig.@(test|tools).json", @@ -105,7 +104,6 @@ "options": { "errorOnUnmatchedPattern": false, "maxWarnings": 0, - "format": "./tools/eslint-formatter-multiple-formats/dist/index.js", "lintFilePatterns": [ "{projectRoot}/**/*.ts", "{projectRoot}/package.json" @@ -133,7 +131,7 @@ "inputs": ["lint-eslint-inputs"], "executor": "nx:run-commands", "options": { - "command": "nx run lint {projectName}", + "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multiple-formats/dist/index.js", "env": { "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" } diff --git a/package-lock.json b/package-lock.json index b1f43c369..53ab456d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,7 +73,6 @@ "commitizen": "^4.3.1", "commitlint-plugin-tense": "^1.0.3", "dotenv": "^16.4.5", - "eslint-formatter-stylish": "^8.40.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-functional": "^7.1.0", "eslint-plugin-import": "2.31.0", @@ -108,7 +107,6 @@ "typescript-eslint": "^8.18.0", "verdaccio": "6.1.6", "vite": "6.3.5", - "vite-plugin-dts": "~4.5.0", "vitest": "1.3.1", "zod2md": "^0.2.4" }, @@ -3335,29 +3333,6 @@ "node": ">=18" } }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4290,11 +4265,10 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.30", @@ -4390,156 +4364,6 @@ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" }, - "node_modules/@microsoft/api-extractor": { - "version": "7.52.11", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.52.11.tgz", - "integrity": "sha512-IKQ7bHg6f/Io3dQds6r9QPYk4q0OlR9A4nFDtNhUt3UUIhyitbxAqRN1CLjUVtk6IBk3xzyCMOdwwtIXQ7AlGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/api-extractor-model": "7.30.7", - "@microsoft/tsdoc": "~0.15.1", - "@microsoft/tsdoc-config": "~0.17.1", - "@rushstack/node-core-library": "5.14.0", - "@rushstack/rig-package": "0.5.3", - "@rushstack/terminal": "0.15.4", - "@rushstack/ts-command-line": "5.0.2", - "lodash": "~4.17.15", - "minimatch": "10.0.3", - "resolve": "~1.22.1", - "semver": "~7.5.4", - "source-map": "~0.6.1", - "typescript": "5.8.2" - }, - "bin": { - "api-extractor": "bin/api-extractor" - } - }, - "node_modules/@microsoft/api-extractor-model": { - "version": "7.30.7", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.30.7.tgz", - "integrity": "sha512-TBbmSI2/BHpfR9YhQA7nH0nqVmGgJ0xH0Ex4D99/qBDAUpnhA2oikGmdXanbw9AWWY/ExBYIpkmY8dBHdla3YQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/tsdoc": "~0.15.1", - "@microsoft/tsdoc-config": "~0.17.1", - "@rushstack/node-core-library": "5.14.0" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/@microsoft/tsdoc": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz", - "integrity": "sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.17.1.tgz", - "integrity": "sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/tsdoc": "0.15.1", - "ajv": "~8.12.0", - "jju": "~1.4.0", - "resolve": "~1.22.2" - } - }, - "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@modern-js/node-bundle-require": { "version": "2.68.2", "resolved": "https://registry.npmjs.org/@modern-js/node-bundle-require/-/node-bundle-require-2.68.2.tgz", @@ -7670,171 +7494,6 @@ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", "dev": true }, - "node_modules/@rushstack/node-core-library": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.14.0.tgz", - "integrity": "sha512-eRong84/rwQUlATGFW3TMTYVyqL1vfW9Lf10PH+mVGfIb9HzU3h5AASNIw+axnBLjnD0n3rT5uQBwu9fvzATrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "~8.13.0", - "ajv-draft-04": "~1.0.0", - "ajv-formats": "~3.0.1", - "fs-extra": "~11.3.0", - "import-lazy": "~4.0.0", - "jju": "~1.4.0", - "resolve": "~1.22.1", - "semver": "~7.5.4" - }, - "peerDependencies": { - "@types/node": "*" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@rushstack/node-core-library/node_modules/ajv": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", - "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/@rushstack/rig-package": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.3.tgz", - "integrity": "sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "~1.22.1", - "strip-json-comments": "~3.1.1" - } - }, - "node_modules/@rushstack/terminal": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.15.4.tgz", - "integrity": "sha512-OQSThV0itlwVNHV6thoXiAYZlQh4Fgvie2CzxFABsbO2MWQsI4zOh3LRNigYSTrmS+ba2j0B3EObakPzf/x6Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rushstack/node-core-library": "5.14.0", - "supports-color": "~8.1.1" - }, - "peerDependencies": { - "@types/node": "*" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@rushstack/terminal/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@rushstack/terminal/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/@rushstack/ts-command-line": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.0.2.tgz", - "integrity": "sha512-+AkJDbu1GFMPIU8Sb7TLVXDv/Q7Mkvx+wAjEl8XiXVVq+p1FmWW6M3LYpJMmoHNckSofeMecgWg5lfMwNAAsEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rushstack/terminal": "0.15.4", - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "string-argv": "~0.3.1" - } - }, "node_modules/@sentry/core": { "version": "6.19.7", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.19.7.tgz", @@ -8967,13 +8626,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@types/argparse": { - "version": "1.0.38", - "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", - "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -10592,126 +10244,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@volar/language-core": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", - "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/source-map": "2.4.23" - } - }, - "node_modules/@volar/source-map": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", - "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@volar/typescript": { - "version": "2.4.23", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz", - "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.23", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.20.tgz", - "integrity": "sha512-8TWXUyiqFd3GmP4JTX9hbiTFRwYHgVL/vr3cqhr4YQ258+9FADwvj7golk2sWNGHR67QgmCZ8gz80nQcMokhwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.3", - "@vue/shared": "3.5.20", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-core/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.20.tgz", - "integrity": "sha512-whB44M59XKjqUEYOMPYU0ijUV0G+4fdrHVKDe32abNdX/kJe1NUEMqsi4cwzXa9kyM9w5S8WqFsrfo1ogtBZGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.20", - "@vue/shared": "3.5.20" - } - }, - "node_modules/@vue/compiler-vue2": { - "version": "2.7.16", - "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", - "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", - "dev": true, - "license": "MIT", - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, - "node_modules/@vue/language-core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", - "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "~2.4.11", - "@vue/compiler-dom": "^3.5.0", - "@vue/compiler-vue2": "^2.7.16", - "@vue/shared": "^3.5.0", - "alien-signals": "^0.4.9", - "minimatch": "^9.0.3", - "muggle-string": "^0.4.1", - "path-browserify": "^1.0.1" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.20", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.20.tgz", - "integrity": "sha512-SoRGP596KU/ig6TfgkCMbXkr4YJ91n/QSdMuqeP5r3hVIYA3CPHUBCc7Skak0EAKV+5lL4KyIh61VA/pK1CIAA==", - "dev": true, - "license": "MIT" - }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -11559,21 +11091,6 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^8.5.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, "node_modules/ajv-formats": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", @@ -11603,13 +11120,6 @@ "ajv": "^8.8.2" } }, - "node_modules/alien-signals": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", - "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", - "dev": true, - "license": "MIT" - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -14083,13 +13593,6 @@ "dot-prop": "^5.1.0" } }, - "node_modules/compare-versions": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", - "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", - "dev": true, - "license": "MIT" - }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -14190,11 +13693,10 @@ } }, "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", + "dev": true }, "node_modules/configstore": { "version": "5.0.1", @@ -14916,13 +14418,6 @@ "dev": true, "license": "MIT" }, - "node_modules/de-indent": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", - "dev": true, - "license": "MIT" - }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -16283,110 +15778,6 @@ "eslint": ">=6.0.0" } }, - "node_modules/eslint-formatter-stylish": { - "version": "8.40.0", - "resolved": "https://registry.npmjs.org/eslint-formatter-stylish/-/eslint-formatter-stylish-8.40.0.tgz", - "integrity": "sha512-blbD5ZSQnjNEUaG38VCO4WG9nfDQWE8/IOmt8DFRHXUIfZikaIXmsQTdWNFk0/e0j7RgIVRza86MpsJ+aHgFLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-formatter-stylish/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint-formatter-stylish/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint-formatter-stylish/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint-formatter-stylish/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint-formatter-stylish/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-formatter-stylish/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint-formatter-stylish/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -17443,13 +16834,6 @@ "dev": true, "license": "MIT" }, - "node_modules/exsolve": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", - "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", - "dev": true, - "license": "MIT" - }, "node_modules/ext-list": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", @@ -18176,10 +17560,9 @@ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-extra": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", - "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", - "license": "MIT", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -19322,16 +18705,6 @@ "node": ">=8" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", @@ -22289,13 +21662,6 @@ "jiti": "lib/jiti-cli.mjs" } }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true, - "license": "MIT" - }, "node_modules/jpeg-js": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", @@ -22841,13 +22207,6 @@ "node": ">= 0.6" } }, - "node_modules/kolorist": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", - "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", - "dev": true, - "license": "MIT" - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -23515,13 +22874,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.18", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", - "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "version": "0.30.11", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", + "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", "dev": true, - "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/magicast": { @@ -23833,25 +23191,17 @@ } }, "node_modules/mlly": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", - "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", "dev": true, - "license": "MIT", "dependencies": { - "acorn": "^8.15.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.1" + "acorn": "^8.11.3", + "pathe": "^1.1.2", + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" } }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -23876,13 +23226,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/muggle-string": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", - "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", - "dev": true, - "license": "MIT" - }, "node_modules/multi-progress-bars": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/multi-progress-bars/-/multi-progress-bars-5.0.3.tgz", @@ -25465,24 +24808,16 @@ } }, "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.2.0.tgz", + "integrity": "sha512-+ifYuSSqOQ8CqP4MbZA5hDpb97n3E8SVWdJe+Wms9kj745lmd3b7EZJiqvmLwAlmRfjrI7Hi5z3kdBJ93lFNPA==", "dev": true, - "license": "MIT", "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" + "confbox": "^0.1.7", + "mlly": "^1.7.1", + "pathe": "^1.1.2" } }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, "node_modules/pkginfo": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.4.1.tgz", @@ -26597,23 +25932,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/quansync": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", - "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/antfu" - }, - { - "type": "individual", - "url": "https://github.com/sponsors/sxzz" - } - ], - "license": "MIT" - }, "node_modules/query-registry": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/query-registry/-/query-registry-3.0.1.tgz", @@ -29250,13 +28568,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/thingies": { "version": "1.21.0", "resolved": "https://registry.npmjs.org/thingies/-/thingies-1.21.0.tgz", @@ -30096,11 +29407,10 @@ } }, "node_modules/ufo": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", - "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", - "dev": true, - "license": "MIT" + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", + "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", + "dev": true }, "node_modules/uglify-js": { "version": "3.19.3", @@ -31253,77 +30563,6 @@ } } }, - "node_modules/vite-plugin-dts": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", - "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/api-extractor": "^7.50.1", - "@rollup/pluginutils": "^5.1.4", - "@volar/typescript": "^2.4.11", - "@vue/language-core": "2.2.0", - "compare-versions": "^6.1.1", - "debug": "^4.4.0", - "kolorist": "^1.8.0", - "local-pkg": "^1.0.0", - "magic-string": "^0.30.17" - }, - "peerDependencies": { - "typescript": "*", - "vite": "*" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "node_modules/vite-plugin-dts/node_modules/confbox": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", - "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite-plugin-dts/node_modules/local-pkg": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", - "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mlly": "^1.7.4", - "pkg-types": "^2.3.0", - "quansync": "^0.2.11" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/vite-plugin-dts/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite-plugin-dts/node_modules/pkg-types": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", - "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.2.2", - "exsolve": "^1.0.7", - "pathe": "^2.0.3" - } - }, "node_modules/vitest": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.1.tgz", @@ -31884,13 +31123,6 @@ "resolved": "https://registry.npmjs.org/vscode-material-icons/-/vscode-material-icons-0.1.1.tgz", "integrity": "sha512-GsoEEF8Tbb0yUFQ6N6FPvh11kFkL9F95x0FkKlbbfRQN9eFms67h+L3t6b9cUv58dSn2gu8kEhNfoESVCrz4ag==" }, - "node_modules/vscode-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", - "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", - "dev": true, - "license": "MIT" - }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", diff --git a/package.json b/package.json index 3bbca3fdb..ba7596460 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,6 @@ "commitizen": "^4.3.1", "commitlint-plugin-tense": "^1.0.3", "dotenv": "^16.4.5", - "eslint-formatter-stylish": "^8.40.0", "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-functional": "^7.1.0", "eslint-plugin-import": "2.31.0", @@ -121,7 +120,6 @@ "typescript-eslint": "^8.18.0", "verdaccio": "6.1.6", "vite": "6.3.5", - "vite-plugin-dts": "~4.5.0", "vitest": "1.3.1", "zod2md": "^0.2.4" }, diff --git a/tools/eslint-formatter-multiple-formats/project.json b/tools/eslint-formatter-multiple-formats/project.json index 16e10aee5..5954580a4 100644 --- a/tools/eslint-formatter-multiple-formats/project.json +++ b/tools/eslint-formatter-multiple-formats/project.json @@ -8,12 +8,6 @@ "targets": { "lint": {}, "unit-test": {}, - "build": { - "executor": "@nx/vite:build", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "{projectRoot}/dist" - } - } + "build": {} } } diff --git a/tools/eslint-formatter-multiple-formats/vite.config.ts b/tools/eslint-formatter-multiple-formats/vite.config.ts deleted file mode 100644 index 46320f2c9..000000000 --- a/tools/eslint-formatter-multiple-formats/vite.config.ts +++ /dev/null @@ -1,59 +0,0 @@ -/// -import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin'; -import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; -import path from 'node:path'; -import { defineConfig } from 'vite'; -import dts from 'vite-plugin-dts'; - -export default defineConfig(() => ({ - root: __dirname, - cacheDir: '../../node_modules/.vite/eslint-multi-format', - plugins: [ - nxViteTsPaths(), - nxCopyAssetsPlugin(['*.md']), - dts({ - entryRoot: 'src', - tsconfigPath: path.join(__dirname, 'tsconfig.lib.json'), - pathsToAliases: false, - }), - ], - // Uncomment this if you are using workers. - // worker: { - // plugins: [ nxViteTsPaths() ], - // }, - // Configuration for building your library. - // See: https://vitejs.dev/guide/build.html#library-mode - build: { - outDir: './dist', - emptyOutDir: true, - reportCompressedSize: true, - commonjsOptions: { - transformMixedEsModules: true, - }, - lib: { - // Could also be a dictionary or array of multiple entry points. - entry: 'src/index.ts', - name: 'eslint-formatter-multiple-formats', - fileName: 'index', - // Change this to the formats you want to support. - // Don't forget to update your package.json as well. - formats: ['es' as const], - }, - rollupOptions: { - // External packages that should not be bundled into your library. - external: [ - 'eslint', - 'ansis', - 'node:fs', - 'node:fs/promises', - 'node:path', - 'node:process', - ], - }, - }, - define: { - // Preserve Node.js globals - 'process.env': 'process.env', - 'process.cwd': 'process.cwd', - }, -})); From 944b1414025a08cba13bc652ded4eb37757100d1 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Mon, 1 Sep 2025 20:45:06 +0200 Subject: [PATCH 14/37] refactor: fix lint --- tools/eslint-formatter-multiple-formats/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/eslint-formatter-multiple-formats/package.json b/tools/eslint-formatter-multiple-formats/package.json index a753e8792..402ccbf3c 100644 --- a/tools/eslint-formatter-multiple-formats/package.json +++ b/tools/eslint-formatter-multiple-formats/package.json @@ -32,7 +32,8 @@ "access": "public" }, "dependencies": { - "ansis": "^3.3.0" + "ansis": "^3.3.0", + "tslib": "^2.8.1" }, "peerDependencies": { "eslint": "^8.0.0 || ^9.0.0" From 28bc74d7caf379fece7ce208f6c011df5d49a484 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:11:27 +0200 Subject: [PATCH 15/37] refactor: revert env vars --- .github/workflows/ci.yml | 2 +- code-pushup.preset.ts | 3 +-- nx.json | 20 ++----------------- .../src/lib/multiple-formats.ts | 9 +-------- .../src/lib/utils.ts | 11 ++-------- 5 files changed, 7 insertions(+), 38 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c05bfa025..edcf22380 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: npm ci - name: Lint affected projects - run: ESLINT_FORMATTER_PROJECTS_DIR=packages npx nx affected:lint --parallel=3 + run: npx nx affected:lint --parallel=3 unit-test: strategy: diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index af0cf11b6..752c853a3 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -179,8 +179,7 @@ export const eslintCoreConfigNx = async ( }) : await eslintPlugin(await eslintConfigFromAllNxProjects(), { artifacts: { - generateArtifactsCommand: - 'ESLINT_FORMATTER_PROJECTS_DIR=packages NX_TUI=false npx nx run-many -t lint --include="packages/**"', + generateArtifactsCommand: 'npx nx run-many -t lint-formatter', artifactsPaths: ['packages/**/.eslint/eslint-report.json'], }, }), diff --git a/nx.json b/nx.json index 414f0c765..1c64dfb2f 100644 --- a/nx.json +++ b/nx.json @@ -99,7 +99,6 @@ "dependsOn": ["eslint-formatter-multiple-formats:build"], "inputs": ["lint-eslint-inputs"], "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], "cache": true, "options": { "errorOnUnmatchedPattern": false, @@ -110,28 +109,13 @@ ] } }, - "lint-report": { - "inputs": ["default", "{workspaceRoot}/eslint.config.?(c)js"], - "outputs": ["{projectRoot}/.eslint/eslint-report*.json"], - "cache": true, - "executor": "@nx/eslint:lint", - "options": { - "errorOnUnmatchedPattern": false, - "maxWarnings": 0, - "format": "json", - "outputFile": "{projectRoot}/.eslint/eslint-report.json", - "lintFilePatterns": [ - "{projectRoot}/**/*.ts", - "{projectRoot}/package.json" - ] - } - }, "lint-formatter": { "dependsOn": ["eslint-formatter-multiple-formats:build"], "inputs": ["lint-eslint-inputs"], + "outputs": ["{projectRoot}/.eslint"], "executor": "nx:run-commands", "options": { - "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multiple-formats/dist/index.js", + "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multiple-formats/dist/src/index.js", "env": { "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" } diff --git a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts index 99f82cf98..d15e3fff9 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts @@ -62,22 +62,15 @@ export default function multipleFormats( const { outputDir = DEFAULT_OUTPUT_DIR, - projectsDir, - projectName = process.env['NX_TASK_TARGET_PROJECT'], filename, formats, terminal, verbose = false, } = config; - const filalOutputDir = - typeof projectName === 'string' && typeof projectsDir === 'string' - ? path.join(projectsDir ?? '', projectName ?? '', outputDir) - : outputDir; - try { persistEslintReports(formats, results, { - outputDir: filalOutputDir, + outputDir, filename, verbose, }); diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index 7aaf3053a..a2838f305 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -216,20 +216,13 @@ export function findConfigFromEnv( env: NodeJS.ProcessEnv, ): FormatterConfig | null { const configString = env['ESLINT_FORMATTER_CONFIG']; - const projectsDir = env['ESLINT_FORMATTER_PROJECTS_DIR']; - if ( - (!configString || configString.trim() === '') && - (!projectsDir || projectsDir.trim() === '') - ) { + if (!configString || configString.trim() === '') { return null; } try { - return { - ...(JSON.parse(configString ?? '{}') as FormatterConfig), - projectsDir: env['ESLINT_FORMATTER_PROJECTS_DIR'], - }; + return JSON.parse(configString ?? '{}') as FormatterConfig; } catch (error) { console.error( 'Error parsing ESLINT_FORMATTER_CONFIG environment variable:', From 4e154e1f54b493777d5be5a0b9b559c3d5efd708 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:12:44 +0200 Subject: [PATCH 16/37] refactor: adjust GH ci action --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edcf22380..c23527466 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: npm ci - name: Lint affected projects - run: npx nx affected:lint --parallel=3 + run: npx nx affected:lint-formatter --parallel=3 unit-test: strategy: From 7fa3e534809b6a638d1e1f17febbf1605d60e783 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:14:48 +0200 Subject: [PATCH 17/37] refactor: adjust GH ci action 2 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c23527466..d65b840cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: npm ci - name: Lint affected projects - run: npx nx affected:lint-formatter --parallel=3 + run: npx nx affected -t lint-formatter --parallel=3 unit-test: strategy: From 72b3f2ccadc6e9968e3da609ffaa9d288d293f6e Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:25:23 +0200 Subject: [PATCH 18/37] refactor: adjust targets --- code-pushup.preset.ts | 3 ++- nx.json | 6 ++++++ project.json | 9 ++++++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 752c853a3..d2fd31910 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -179,7 +179,8 @@ export const eslintCoreConfigNx = async ( }) : await eslintPlugin(await eslintConfigFromAllNxProjects(), { artifacts: { - generateArtifactsCommand: 'npx nx run-many -t lint-formatter', + // We leverage Nx dependsOn to only run all lint targets before we run code-pushup + // generateArtifactsCommand: 'npx nx run-many -t lint-formatter', artifactsPaths: ['packages/**/.eslint/eslint-report.json'], }, }), diff --git a/nx.json b/nx.json index 1c64dfb2f..6ee72ff68 100644 --- a/nx.json +++ b/nx.json @@ -179,6 +179,12 @@ } }, "code-pushup-eslint": { + "dependsOn": [ + { + "target": "lint-formatter", + "projects": "self" + } + ], "cache": true, "inputs": ["code-pushup-inputs", "lint-eslint-inputs"], "outputs": ["{projectRoot}/.code-pushup/eslint/runner-output.json"], diff --git a/project.json b/project.json index aa58578bd..e0ca40ce9 100644 --- a/project.json +++ b/project.json @@ -5,7 +5,14 @@ "code-pushup-js-packages": {}, "code-pushup-lighthouse": {}, "code-pushup-coverage": {}, - "code-pushup-eslint": {}, + "code-pushup-eslint": { + "dependsOn": [ + { + "target": "lint-formatter", + "projects": "*" + } + ] + }, "code-pushup-jsdocs": {}, "code-pushup-typescript": {}, "code-pushup": { From 6e0d998a983a29dfa798ff6001aa3bd0823d6b4d Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:30:28 +0200 Subject: [PATCH 19/37] refactor: adjust targets 3 --- nx.json | 7 ------- 1 file changed, 7 deletions(-) diff --git a/nx.json b/nx.json index 6ee72ff68..64ef18b50 100644 --- a/nx.json +++ b/nx.json @@ -96,7 +96,6 @@ "cache": true }, "lint": { - "dependsOn": ["eslint-formatter-multiple-formats:build"], "inputs": ["lint-eslint-inputs"], "executor": "@nx/eslint:lint", "cache": true, @@ -179,12 +178,6 @@ } }, "code-pushup-eslint": { - "dependsOn": [ - { - "target": "lint-formatter", - "projects": "self" - } - ], "cache": true, "inputs": ["code-pushup-inputs", "lint-eslint-inputs"], "outputs": ["{projectRoot}/.code-pushup/eslint/runner-output.json"], From 689d6714b22ba0fbb6400aee98779e20247ada81 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:32:51 +0200 Subject: [PATCH 20/37] refactor: adjust targets 4 --- nx.json | 1 - 1 file changed, 1 deletion(-) diff --git a/nx.json b/nx.json index 64ef18b50..8b10ca78a 100644 --- a/nx.json +++ b/nx.json @@ -159,7 +159,6 @@ "inputs": ["code-pushup-inputs", "test-vitest-inputs"], "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], "executor": "nx:run-commands", - "dependsOn": ["*-test"], "options": { "command": "node packages/cli/src/index.ts collect", "args": [ From 26b80b85b8c925c5f3fa27a04201ee954cb70ba2 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:38:11 +0200 Subject: [PATCH 21/37] refactor: adjust targets 5 --- .github/workflows/ci.yml | 2 +- nx.json | 2 +- packages/utils/project.json | 1 - project.json | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d65b840cb..82adfeef2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,7 +49,7 @@ jobs: - name: Install dependencies run: npm ci - name: Lint affected projects - run: npx nx affected -t lint-formatter --parallel=3 + run: npx nx affected -t lint-report --parallel=3 unit-test: strategy: diff --git a/nx.json b/nx.json index 8b10ca78a..5b0be15ed 100644 --- a/nx.json +++ b/nx.json @@ -108,7 +108,7 @@ ] } }, - "lint-formatter": { + "lint-report": { "dependsOn": ["eslint-formatter-multiple-formats:build"], "inputs": ["lint-eslint-inputs"], "outputs": ["{projectRoot}/.eslint"], diff --git a/packages/utils/project.json b/packages/utils/project.json index f41b5308e..2953464ca 100644 --- a/packages/utils/project.json +++ b/packages/utils/project.json @@ -7,7 +7,6 @@ "build": {}, "lint": {}, "lint-report": {}, - "lint-formatter": {}, "perf": { "command": "npx tsx --tsconfig=../tsconfig.perf.json", "options": { diff --git a/project.json b/project.json index e0ca40ce9..5dac1cb39 100644 --- a/project.json +++ b/project.json @@ -8,7 +8,7 @@ "code-pushup-eslint": { "dependsOn": [ { - "target": "lint-formatter", + "target": "lint-report", "projects": "*" } ] From 6372d63dd51a75da6e3f23edc527b7f772dcb46c Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 13:42:21 +0200 Subject: [PATCH 22/37] refactor: adjust targets 6 --- code-pushup.preset.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index d2fd31910..999051907 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -180,7 +180,7 @@ export const eslintCoreConfigNx = async ( : await eslintPlugin(await eslintConfigFromAllNxProjects(), { artifacts: { // We leverage Nx dependsOn to only run all lint targets before we run code-pushup - // generateArtifactsCommand: 'npx nx run-many -t lint-formatter', + // generateArtifactsCommand: 'npx nx run-many -t lint-report', artifactsPaths: ['packages/**/.eslint/eslint-report.json'], }, }), From 3d306da270af57ef4ff347e89ab6b685e1467d35 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 18:35:47 +0200 Subject: [PATCH 23/37] chore: revert targets --- nx.json | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/nx.json b/nx.json index 5b0be15ed..5cd2e84ed 100644 --- a/nx.json +++ b/nx.json @@ -159,6 +159,7 @@ "inputs": ["code-pushup-inputs", "test-vitest-inputs"], "outputs": ["{projectRoot}/.code-pushup/coverage/runner-output.json"], "executor": "nx:run-commands", + "dependsOn": ["*-test"], "options": { "command": "node packages/cli/src/index.ts collect", "args": [ @@ -343,27 +344,6 @@ "filterByTags": ["publishable"] } } - }, - { - "plugin": "@nx/eslint", - "options": { - "config": "{projectRoot}/eslint.config.js" - } - }, - { - "plugin": "@nx/vite/plugin", - "options": { - "buildTargetName": "build", - "testTargetName": "test", - "serveTargetName": "serve", - "devTargetName": "dev", - "previewTargetName": "preview", - "serveStaticTargetName": "serve-static", - "typecheckTargetName": "typecheck", - "buildDepsTargetName": "build-deps", - "watchDepsTargetName": "watch-deps" - }, - "include": ["tools/eslint-multi-format/**"] } ], "nxCloudId": "65d4d862d2adb16a45a4bc7c" From 17f802948e6ef94f5ff24c3833c3be475e51ffdd Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 18:39:42 +0200 Subject: [PATCH 24/37] chore: fix lint setup --- tools/eslint-formatter-multiple-formats/eslint.config.js | 8 +------- .../src/lib/multiple-formats.ts | 1 - tools/tsconfig.tools.json | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/tools/eslint-formatter-multiple-formats/eslint.config.js b/tools/eslint-formatter-multiple-formats/eslint.config.js index 652af0285..29bda515b 100644 --- a/tools/eslint-formatter-multiple-formats/eslint.config.js +++ b/tools/eslint-formatter-multiple-formats/eslint.config.js @@ -15,13 +15,7 @@ export default tseslint.config( { files: ['**/*.json'], rules: { - '@nx/dependency-checks': [ - 'error', - { - ignoredDependencies: ['@nx/vite', 'vite', 'vite-plugin-dts'], - }, - ], - 'n/no-sync': 'off', + '@nx/dependency-checks': ['error'], }, }, ); diff --git a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts index d15e3fff9..487903ceb 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts @@ -1,5 +1,4 @@ import type { ESLint } from 'eslint'; -import path from 'node:path'; import * as process from 'node:process'; import type { FormatterConfig } from './types.js'; import { diff --git a/tools/tsconfig.tools.json b/tools/tsconfig.tools.json index 159675663..060e2c775 100644 --- a/tools/tsconfig.tools.json +++ b/tools/tsconfig.tools.json @@ -9,5 +9,5 @@ "importHelpers": false }, "include": ["**/*.ts"], - "exclude": ["eslint-multi-format/**/*"] + "exclude": ["eslint-formatter-multiple-formats/**/*"] } From 9a73ab9f6800c4e04ebaed300df90c4097af15a1 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 19:02:25 +0200 Subject: [PATCH 25/37] refactor: fix async --- .../src/lib/multiple-formats.ts | 6 ++-- .../src/lib/utils.ts | 32 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts index 487903ceb..874a915a5 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts @@ -50,10 +50,10 @@ export const DEFAULT_CONFIG: Required< * "terminal": "stylish" // Optional: Format for terminal output (default: 'stylish') * } */ -export default function multipleFormats( +export default async function multipleFormats( results: ESLint.LintResult[], _args?: unknown, -): string { +): Promise { const config = { ...DEFAULT_CONFIG, ...getConfigFromEnv(process.env), @@ -68,7 +68,7 @@ export default function multipleFormats( } = config; try { - persistEslintReports(formats, results, { + await persistEslintReports(formats, results, { outputDir, filename, verbose, diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index a2838f305..44a74ef21 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -1,7 +1,7 @@ // Import ansis for colors (similar to chalk) import { bold, dim, red, reset, underline, yellow } from 'ansis'; import type { ESLint } from 'eslint'; -import { mkdirSync, writeFileSync } from 'node:fs'; +import { mkdir, writeFile } from 'node:fs/promises'; import path from 'node:path'; import type { FormatterConfig } from './types.js'; @@ -269,16 +269,14 @@ export type PersistConfig = { verbose: boolean; }; -export function persistEslintReport( +export async function persistEslintReport( results: ESLint.LintResult[], options: PersistConfig, -): boolean { +): Promise { const { outputDir, filename, format, verbose = false } = options; try { - // eslint-disable-next-line n/no-sync - mkdirSync(outputDir, { recursive: true }); - // eslint-disable-next-line n/no-sync - writeFileSync( + await mkdir(outputDir, { recursive: true }); + await writeFile( path.join(outputDir, `${filename}.${getExtensionForFormat(format)}`), formatContent(results, format), ); @@ -297,19 +295,21 @@ export function persistEslintReport( } } -export function persistEslintReports( +export async function persistEslintReports( formats: EslintFormat[], results: ESLint.LintResult[], options: Omit, -): boolean { +): Promise { const { outputDir, filename, verbose } = options; - return formats.every(format => - persistEslintReport(results, { - outputDir, - filename, - format, - verbose, - }), + await Promise.all( + formats.map(format => + persistEslintReport(results, { + outputDir, + filename, + format, + verbose, + }), + ), ); } From 37ea31564c16740b107e3d1f9bda7affa899818b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 20:19:15 +0200 Subject: [PATCH 26/37] refactor: copy code --- .../src/lib/stylish.ts | 126 ++++++++++++++++++ .../src/lib/text-table.ts | 77 +++++++++++ 2 files changed, 203 insertions(+) create mode 100644 tools/eslint-formatter-multiple-formats/src/lib/stylish.ts create mode 100644 tools/eslint-formatter-multiple-formats/src/lib/text-table.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/stylish.ts b/tools/eslint-formatter-multiple-formats/src/lib/stylish.ts new file mode 100644 index 000000000..883f8da71 --- /dev/null +++ b/tools/eslint-formatter-multiple-formats/src/lib/stylish.ts @@ -0,0 +1,126 @@ +/* COPY OF https://github.com/eslint/eslint/blob/a355a0e5b2e6a47cda099b31dc7d112cfb5c4315/lib/cli-engine/formatters/stylish.js */ + +/** + * @fileoverview Stylish reporter + * @author Sindre Sorhus + */ +import { bold, dim, red, reset, underline, yellow } from 'ansis'; +import type { ESLint } from 'eslint'; +import { stripVTControlCharacters } from 'node:util'; +import { textTable } from './text-table.js'; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +/** + * Given a word and a count, append an s if count is not one. + * @param {string} word A word in its singular form. + * @param {number} count A number controlling whether word should be pluralized. + * @returns {string} The original word with an s on the end if count is not one. + */ +function pluralize(word: string, count: number): string { + return count === 1 ? word : `${word}s`; +} + +//------------------------------------------------------------------------------ +// Public Interface +//------------------------------------------------------------------------------ + +export default function (results: ESLint.LintResult[]): string { + let output = '\n', + errorCount = 0, + warningCount = 0, + fixableErrorCount = 0, + fixableWarningCount = 0, + summaryColor = 'yellow'; + + results.forEach(result => { + const messages = result.messages; + + if (messages.length === 0) { + return; + } + + errorCount += result.errorCount; + warningCount += result.warningCount; + fixableErrorCount += result.fixableErrorCount; + fixableWarningCount += result.fixableWarningCount; + + output += `${underline(result.filePath)}\n`; + + output += `${textTable( + messages.map(message => { + let messageType; + + if (message.fatal || message.severity === 2) { + messageType = red('error'); + summaryColor = 'red'; + } else { + messageType = yellow('warning'); + } + + return [ + '', + String(message.line || 0), + String(message.column || 0), + messageType, + message.message.replace(/([^ ])\.$/u, '$1'), + dim(message.ruleId || ''), + ]; + }), + { + align: ['', 'r', 'l'], + stringLength(str: string) { + return stripVTControlCharacters(str).length; + }, + }, + ) + .split('\n') + .map(el => + el.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) => dim(`${p1}:${p2}`)), + ) + .join('\n')}\n\n`; + }); + + const total = errorCount + warningCount; + + if (total > 0) { + const colorFn = summaryColor === 'red' ? red : yellow; + output += bold( + colorFn( + [ + '\u2716 ', + total, + pluralize(' problem', total), + ' (', + errorCount, + pluralize(' error', errorCount), + ', ', + warningCount, + pluralize(' warning', warningCount), + ')\n', + ].join(''), + ), + ); + + if (fixableErrorCount > 0 || fixableWarningCount > 0) { + output += bold( + colorFn( + [ + ' ', + fixableErrorCount, + pluralize(' error', fixableErrorCount), + ' and ', + fixableWarningCount, + pluralize(' warning', fixableWarningCount), + ' potentially fixable with the `--fix` option.\n', + ].join(''), + ), + ); + } + } + + // Resets output color, for prevent change on top level + return total > 0 ? reset(output) : ''; +} diff --git a/tools/eslint-formatter-multiple-formats/src/lib/text-table.ts b/tools/eslint-formatter-multiple-formats/src/lib/text-table.ts new file mode 100644 index 000000000..d4f95d4b5 --- /dev/null +++ b/tools/eslint-formatter-multiple-formats/src/lib/text-table.ts @@ -0,0 +1,77 @@ +/* COPY OF https://github.com/eslint/eslint/blob/a355a0e5b2e6a47cda099b31dc7d112cfb5c4315/lib/shared/text-table.js */ + +/** + * @fileoverview Optimized version of the `text-table` npm module to improve performance by replacing inefficient regex-based + * whitespace trimming with a modern built-in method. + * + * This modification addresses a performance issue reported in https://github.com/eslint/eslint/issues/18709 + * + * The `text-table` module is published under the MIT License. For the original source, refer to: + * https://www.npmjs.com/package/text-table. + */ + +/* + * + * This software is released under the MIT license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export interface TextTableOptions { + align?: (string | undefined)[]; + stringLength?: (str: string) => number; +} + +export function textTable( + rows_: (string | number)[][], + opts: TextTableOptions = {}, +): string { + const hsep = ' '; + const align = opts.align ?? []; + const stringLength = opts.stringLength ?? ((str: string) => str.length); + + const sizes = rows_.reduce((acc: number[], row: (string | number)[]) => { + row.forEach((c: string | number, ix: number) => { + const n = stringLength(String(c)); + + if (!acc[ix] || n > acc[ix]) { + acc[ix] = n; + } + }); + return acc; + }, []); + + return rows_ + .map((row: (string | number)[]) => + row + .map((c: string | number, ix: number) => { + const cellStr = String(c); + const n = (sizes[ix] ?? 0) - stringLength(cellStr) || 0; + const s = Array(Math.max(n + 1, 1)).join(' '); + + if (align[ix] === 'r') { + return s + cellStr; + } + + return cellStr + s; + }) + .join(hsep) + .trimEnd(), + ) + .join('\n'); +} From 563c8ec88d9a9d19af366cfcc298068083211f02 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 20:20:09 +0200 Subject: [PATCH 27/37] refactor: use copy code --- code-pushup.preset.ts | 2 +- .../src/lib/utils.ts | 188 +----------------- 2 files changed, 2 insertions(+), 188 deletions(-) diff --git a/code-pushup.preset.ts b/code-pushup.preset.ts index 91e7444ab..34fb85c10 100644 --- a/code-pushup.preset.ts +++ b/code-pushup.preset.ts @@ -180,7 +180,7 @@ export const eslintCoreConfigNx = async ( : await eslintPlugin(await eslintConfigFromAllNxProjects(), { artifacts: { // We leverage Nx dependsOn to only run all lint targets before we run code-pushup - // generateArtifactsCommand: 'npx nx run-many -t lint-report', + // generateArtifactsCommand: 'npx nx run-many -t lint', artifactsPaths: ['packages/**/.eslint/eslint-report.json'], }, }), diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts index 44a74ef21..1a9d90e9d 100644 --- a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts +++ b/tools/eslint-formatter-multiple-formats/src/lib/utils.ts @@ -1,195 +1,9 @@ -// Import ansis for colors (similar to chalk) -import { bold, dim, red, reset, underline, yellow } from 'ansis'; import type { ESLint } from 'eslint'; import { mkdir, writeFile } from 'node:fs/promises'; import path from 'node:path'; +import stylishFormatter from './stylish.js'; import type { FormatterConfig } from './types.js'; -// Helper function to pluralize words -function pluralize(word: string, count: number): string { - return count === 1 ? word : `${word}s`; -} - -// Simple function to strip ANSI codes for length calculation -function stripAnsi(str: string): string { - // eslint-disable-next-line no-control-regex - return str.replace(/\u001B\[[\d;]*m/g, ''); -} - -// Simple table formatting function -function createTable( - data: (string | number)[][], - options: { align?: string[]; stringLength?: (str: string) => number } = {}, -): string { - const { align = [], stringLength = s => s.length } = options; - - if (data.length === 0) { - return ''; - } - - // Calculate column widths - const colWidths: number[] = data.reduce( - (widths, row) => - row.reduce((acc, cell, colIndex) => { - const cellStr = String(cell); - const width = stringLength(cellStr); - const currentWidth = acc[colIndex] || 0; - const maxWidth = Math.max(currentWidth, width); - return [ - ...acc.slice(0, colIndex), - maxWidth, - ...acc.slice(colIndex + 1), - ]; - }, widths), - [], - ); - - // Format rows - return data - .map(row => - row - .map((cell, colIndex) => { - const cellStr = String(cell); - const width = colWidths[colIndex] || 0; - const padding = width - stringLength(cellStr); - - if (align[colIndex] === 'r') { - return ' '.repeat(padding) + cellStr; - } - return cellStr + ' '.repeat(padding); - }) - .join(' '), - ) - .join('\n'); -} - -// Summary statistics for lint results -type LintSummary = { - errorCount: number; - warningCount: number; - fixableErrorCount: number; - fixableWarningCount: number; - summaryColor: 'yellow' | 'red'; -}; - -// Calculate summary statistics from results -function calculateSummary(results: ESLint.LintResult[]): LintSummary { - return results.reduce( - (summary, result) => ({ - errorCount: summary.errorCount + result.errorCount, - warningCount: summary.warningCount + result.warningCount, - fixableErrorCount: summary.fixableErrorCount + result.fixableErrorCount, - fixableWarningCount: - summary.fixableWarningCount + result.fixableWarningCount, - summaryColor: - result.errorCount > 0 ? ('red' as const) : summary.summaryColor, - }), - { - errorCount: 0, - warningCount: 0, - fixableErrorCount: 0, - fixableWarningCount: 0, - summaryColor: 'yellow', - }, - ); -} - -// Format a single result file -function formatResultFile(result: ESLint.LintResult): string { - if (result.messages.length === 0) { - return ''; - } - - const header = `${underline(result.filePath)}\n`; - - const tableData = result.messages.map(message => { - const messageType = - message.fatal || message.severity === 2 - ? red('error') - : yellow('warning'); - - return [ - '', - message.line || 0, - message.column || 0, - messageType, - message.message.replace(/([^ ])\.$/u, '$1'), - dim(message.ruleId || ''), - ]; - }); - - const table = createTable(tableData, { - align: ['', 'r', 'l'], - stringLength: (str: string) => stripAnsi(str).length, - }); - - const formattedTable = table - .split('\n') - .map(line => - line.replace(/(\d+)\s+(\d+)/u, (m, p1, p2) => dim(`${p1}:${p2}`)), - ) - .join('\n'); - - return `${header}${formattedTable}\n\n`; -} - -// Format summary section -function formatSummary(summary: LintSummary): string { - const { - errorCount, - warningCount, - fixableErrorCount, - fixableWarningCount, - summaryColor, - } = summary; - const total = errorCount + warningCount; - - if (total === 0) { - return ''; - } - - const colorFn = summaryColor === 'red' ? red : yellow; - const problemText = [ - '\u2716 ', - total, - pluralize(' problem', total), - ' (', - errorCount, - pluralize(' error', errorCount), - ', ', - warningCount, - pluralize(' warning', warningCount), - ')\n', - ].join(''); - - const problemOutput = bold(colorFn(problemText)); - - if (fixableErrorCount > 0 || fixableWarningCount > 0) { - const fixableText = [ - ' ', - fixableErrorCount, - pluralize(' error', fixableErrorCount), - ' and ', - fixableWarningCount, - pluralize(' warning', fixableWarningCount), - ' potentially fixable with the `--fix` option.\n', - ].join(''); - - return problemOutput + bold(colorFn(fixableText)); - } - - return problemOutput; -} - -function stylishFormatter(results: ESLint.LintResult[]): string { - const summary = calculateSummary(results); - const filesOutput = results.map(formatResultFile).join(''); - const summaryOutput = formatSummary(summary); - - const total = summary.errorCount + summary.warningCount; - return total > 0 ? reset(`\n${filesOutput}${summaryOutput}`) : ''; -} - export function stringifyError(error: unknown): string { if (error instanceof Error) { if (error.name === 'Error' || error.message.startsWith(error.name)) { From fe10e3988935ee2cdfd2c3ae0a736c5bbc9c3181 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Tue, 2 Sep 2025 20:21:25 +0200 Subject: [PATCH 28/37] refactor: wip --- nx.json | 26 +++++++++++--------------- package-lock.json | 2 +- project.json | 2 +- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/nx.json b/nx.json index 5cd2e84ed..9bb9b8859 100644 --- a/nx.json +++ b/nx.json @@ -97,25 +97,21 @@ }, "lint": { "inputs": ["lint-eslint-inputs"], - "executor": "@nx/eslint:lint", - "cache": true, - "options": { - "errorOnUnmatchedPattern": false, - "maxWarnings": 0, - "lintFilePatterns": [ - "{projectRoot}/**/*.ts", - "{projectRoot}/package.json" - ] - } - }, - "lint-report": { "dependsOn": ["eslint-formatter-multiple-formats:build"], - "inputs": ["lint-eslint-inputs"], - "outputs": ["{projectRoot}/.eslint"], "executor": "nx:run-commands", + "cache": true, "options": { - "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multiple-formats/dist/src/index.js", + "command": "npx eslint", + "args": [ + "{projectRoot}", + "--config={projectRoot}/eslint.config.js", + "--max-warnings=0", + "--format=./tools/eslint-formatter-multiple-formats/dist/src/index.js", + "--error-on-unmatched-pattern=false", + "--max-warnings=0" + ], "env": { + "NX_TUI": "false", "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" } } diff --git a/package-lock.json b/package-lock.json index 53ab456d8..2bec297ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "@commitlint/cz-commitlint": "^19.5.0", "@commitlint/types": "^19.5.0", "@nodelib/fs.walk": "^2.0.0", + "@nx/eslint": "^21.4.1", "@nx/eslint-plugin": "21.4.1", "@nx/js": "21.4.1", "@nx/plugin": "21.4.1", @@ -8193,7 +8194,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" diff --git a/project.json b/project.json index a7ed18777..c53ed1a80 100644 --- a/project.json +++ b/project.json @@ -19,7 +19,7 @@ "code-pushup-eslint": { "dependsOn": [ { - "target": "lint-report", + "target": "lint", "projects": "*" } ] From e0270c68f5ccb10797fc664122a863a7145260cf Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 00:12:26 +0200 Subject: [PATCH 29/37] refactor: rename package from eslint-formatter-multiple-formats to eslint-formatter-multi --- .../README.md | 20 +------------------ .../eslint.config.js | 0 .../package.json | 4 ++-- tools/eslint-formatter-multi/project.json | 12 +++++++++++ .../src/index.ts | 0 .../src/lib/multiple-formats.ts | 0 .../src/lib/stylish.ts | 0 .../src/lib/text-table.ts | 0 .../src/lib/types.ts | 0 .../src/lib/utils.ts | 0 .../src/lib/utils.unit.test.ts | 0 .../tsconfig.json | 0 .../tsconfig.lib.json | 0 .../tsconfig.spec.json | 0 .../vitest.unit.config.ts | 0 .../project.json | 13 ------------ tsconfig.base.json | 4 ++-- 17 files changed, 17 insertions(+), 36 deletions(-) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/README.md (85%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/eslint.config.js (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/package.json (88%) create mode 100644 tools/eslint-formatter-multi/project.json rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/index.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/lib/multiple-formats.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/lib/stylish.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/lib/text-table.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/lib/types.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/lib/utils.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/src/lib/utils.unit.test.ts (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/tsconfig.json (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/tsconfig.lib.json (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/tsconfig.spec.json (100%) rename tools/{eslint-formatter-multiple-formats => eslint-formatter-multi}/vitest.unit.config.ts (100%) delete mode 100644 tools/eslint-formatter-multiple-formats/project.json diff --git a/tools/eslint-formatter-multiple-formats/README.md b/tools/eslint-formatter-multi/README.md similarity index 85% rename from tools/eslint-formatter-multiple-formats/README.md rename to tools/eslint-formatter-multi/README.md index b2bfb592f..2a4032a8d 100644 --- a/tools/eslint-formatter-multiple-formats/README.md +++ b/tools/eslint-formatter-multi/README.md @@ -1,4 +1,4 @@ -# ESLint Multiple-Formats Formatter +# ESLint Multi Formatter The ESLint plugin uses a custom formatter that supports multiple output formats and destinations simultaneously. @@ -61,24 +61,6 @@ ESLINT_FORMATTER_CONFIG='{"formats":[],"terminal":"stylish"}' npx eslint . ESLINT_FORMATTER_CONFIG='{"formats":[],"terminal":"stylish"}' npx eslint . ``` -### Configuration from File - -```bash -# Create a configuration file -cat > eslint-config.json << 'EOF' -{ - "outputDir": "./ci-reports", - "filename": "eslint-report", - "formats": ["json", "stylish"], - "terminal": "stylish", - "verbose": true -} -EOF - -# Use the configuration file -ESLINT_FORMATTER_CONFIG="$(cat eslint-config.json)" npx eslint . -``` - ## Default Behavior When no `ESLINT_FORMATTER_CONFIG` is provided, the formatter uses these defaults: diff --git a/tools/eslint-formatter-multiple-formats/eslint.config.js b/tools/eslint-formatter-multi/eslint.config.js similarity index 100% rename from tools/eslint-formatter-multiple-formats/eslint.config.js rename to tools/eslint-formatter-multi/eslint.config.js diff --git a/tools/eslint-formatter-multiple-formats/package.json b/tools/eslint-formatter-multi/package.json similarity index 88% rename from tools/eslint-formatter-multiple-formats/package.json rename to tools/eslint-formatter-multi/package.json index 402ccbf3c..87f93f505 100644 --- a/tools/eslint-formatter-multiple-formats/package.json +++ b/tools/eslint-formatter-multi/package.json @@ -1,5 +1,5 @@ { - "name": "eslint-formatter-multiple-formats", + "name": "eslint-formatter-multi", "version": "0.0.1", "private": false, "type": "module", @@ -14,7 +14,7 @@ "repository": { "type": "git", "url": "https://github.com/code-pushup/cli.git", - "directory": "tools/eslint-formatter-multiple-formats" + "directory": "tools/eslint-formatter-multi" }, "keywords": [ "eslint", diff --git a/tools/eslint-formatter-multi/project.json b/tools/eslint-formatter-multi/project.json new file mode 100644 index 000000000..34fb74339 --- /dev/null +++ b/tools/eslint-formatter-multi/project.json @@ -0,0 +1,12 @@ +{ + "name": "eslint-formatter-multi", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "tools/eslint-formatter-multi/src", + "projectType": "library", + "tags": ["scope:tooling", "type:util"], + "targets": { + "lint": {}, + "unit-test": {}, + "build": {} + } +} diff --git a/tools/eslint-formatter-multiple-formats/src/index.ts b/tools/eslint-formatter-multi/src/index.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/index.ts rename to tools/eslint-formatter-multi/src/index.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts b/tools/eslint-formatter-multi/src/lib/multiple-formats.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/lib/multiple-formats.ts rename to tools/eslint-formatter-multi/src/lib/multiple-formats.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/stylish.ts b/tools/eslint-formatter-multi/src/lib/stylish.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/lib/stylish.ts rename to tools/eslint-formatter-multi/src/lib/stylish.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/text-table.ts b/tools/eslint-formatter-multi/src/lib/text-table.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/lib/text-table.ts rename to tools/eslint-formatter-multi/src/lib/text-table.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/types.ts b/tools/eslint-formatter-multi/src/lib/types.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/lib/types.ts rename to tools/eslint-formatter-multi/src/lib/types.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.ts b/tools/eslint-formatter-multi/src/lib/utils.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/lib/utils.ts rename to tools/eslint-formatter-multi/src/lib/utils.ts diff --git a/tools/eslint-formatter-multiple-formats/src/lib/utils.unit.test.ts b/tools/eslint-formatter-multi/src/lib/utils.unit.test.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/src/lib/utils.unit.test.ts rename to tools/eslint-formatter-multi/src/lib/utils.unit.test.ts diff --git a/tools/eslint-formatter-multiple-formats/tsconfig.json b/tools/eslint-formatter-multi/tsconfig.json similarity index 100% rename from tools/eslint-formatter-multiple-formats/tsconfig.json rename to tools/eslint-formatter-multi/tsconfig.json diff --git a/tools/eslint-formatter-multiple-formats/tsconfig.lib.json b/tools/eslint-formatter-multi/tsconfig.lib.json similarity index 100% rename from tools/eslint-formatter-multiple-formats/tsconfig.lib.json rename to tools/eslint-formatter-multi/tsconfig.lib.json diff --git a/tools/eslint-formatter-multiple-formats/tsconfig.spec.json b/tools/eslint-formatter-multi/tsconfig.spec.json similarity index 100% rename from tools/eslint-formatter-multiple-formats/tsconfig.spec.json rename to tools/eslint-formatter-multi/tsconfig.spec.json diff --git a/tools/eslint-formatter-multiple-formats/vitest.unit.config.ts b/tools/eslint-formatter-multi/vitest.unit.config.ts similarity index 100% rename from tools/eslint-formatter-multiple-formats/vitest.unit.config.ts rename to tools/eslint-formatter-multi/vitest.unit.config.ts diff --git a/tools/eslint-formatter-multiple-formats/project.json b/tools/eslint-formatter-multiple-formats/project.json deleted file mode 100644 index 5954580a4..000000000 --- a/tools/eslint-formatter-multiple-formats/project.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "eslint-formatter-multiple-formats", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "tools/eslint-multi-format/src", - "projectType": "library", - "tags": ["scope:tooling", "type:util"], - "// targets": "to see all targets run: nx show project eslint-multi-format with option --web for humans and --json for AI", - "targets": { - "lint": {}, - "unit-test": {}, - "build": {} - } -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 75f739be3..7f3b4d21f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -24,8 +24,8 @@ "@code-pushup/cli": ["packages/cli/src/index.ts"], "@code-pushup/core": ["packages/core/src/index.ts"], "@code-pushup/coverage-plugin": ["packages/plugin-coverage/src/index.ts"], - "@code-pushup/eslint-formatter-multiple-formats": [ - "tools/eslint-formatter-multiple-formats/src/index.ts" + "@code-pushup/eslint-formatter-multi": [ + "tools/eslint-formatter-multi/src/index.ts" ], "@code-pushup/eslint-plugin": ["packages/plugin-eslint/src/index.ts"], "@code-pushup/js-packages-plugin": [ From 7981046228b745c319d1a0e05715625f9de322d6 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 00:15:45 +0200 Subject: [PATCH 30/37] refactor: fix targets --- nx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx.json b/nx.json index 9bb9b8859..23c6f5629 100644 --- a/nx.json +++ b/nx.json @@ -106,7 +106,7 @@ "{projectRoot}", "--config={projectRoot}/eslint.config.js", "--max-warnings=0", - "--format=./tools/eslint-formatter-multiple-formats/dist/src/index.js", + "--format=./tools/eslint-formatter-multi/dist/src/index.js", "--error-on-unmatched-pattern=false", "--max-warnings=0" ], From 6c499ccceb2607b32c4cad48406b51a6c04015ad Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 00:37:37 +0200 Subject: [PATCH 31/37] refactor: fix lint --- nx.json | 26 +++++++++++-------- .../eslint-formatter-multi/src/lib/stylish.ts | 5 +++- .../src/lib/text-table.ts | 7 ++--- tools/eslint-formatter-multi/src/lib/utils.ts | 2 +- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/nx.json b/nx.json index 23c6f5629..5cd2e84ed 100644 --- a/nx.json +++ b/nx.json @@ -97,21 +97,25 @@ }, "lint": { "inputs": ["lint-eslint-inputs"], + "executor": "@nx/eslint:lint", + "cache": true, + "options": { + "errorOnUnmatchedPattern": false, + "maxWarnings": 0, + "lintFilePatterns": [ + "{projectRoot}/**/*.ts", + "{projectRoot}/package.json" + ] + } + }, + "lint-report": { "dependsOn": ["eslint-formatter-multiple-formats:build"], + "inputs": ["lint-eslint-inputs"], + "outputs": ["{projectRoot}/.eslint"], "executor": "nx:run-commands", - "cache": true, "options": { - "command": "npx eslint", - "args": [ - "{projectRoot}", - "--config={projectRoot}/eslint.config.js", - "--max-warnings=0", - "--format=./tools/eslint-formatter-multi/dist/src/index.js", - "--error-on-unmatched-pattern=false", - "--max-warnings=0" - ], + "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multiple-formats/dist/src/index.js", "env": { - "NX_TUI": "false", "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" } } diff --git a/tools/eslint-formatter-multi/src/lib/stylish.ts b/tools/eslint-formatter-multi/src/lib/stylish.ts index 883f8da71..43834d3d0 100644 --- a/tools/eslint-formatter-multi/src/lib/stylish.ts +++ b/tools/eslint-formatter-multi/src/lib/stylish.ts @@ -27,7 +27,9 @@ function pluralize(word: string, count: number): string { // Public Interface //------------------------------------------------------------------------------ -export default function (results: ESLint.LintResult[]): string { +// eslint-disable-next-line max-lines-per-function +export function stylishFormatter(results: ESLint.LintResult[]): string { + // eslint-disable-next-line functional/no-let let output = '\n', errorCount = 0, warningCount = 0, @@ -51,6 +53,7 @@ export default function (results: ESLint.LintResult[]): string { output += `${textTable( messages.map(message => { + // eslint-disable-next-line functional/no-let let messageType; if (message.fatal || message.severity === 2) { diff --git a/tools/eslint-formatter-multi/src/lib/text-table.ts b/tools/eslint-formatter-multi/src/lib/text-table.ts index d4f95d4b5..58f0d65da 100644 --- a/tools/eslint-formatter-multi/src/lib/text-table.ts +++ b/tools/eslint-formatter-multi/src/lib/text-table.ts @@ -32,10 +32,10 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export interface TextTableOptions { +export type TextTableOptions = { align?: (string | undefined)[]; stringLength?: (str: string) => number; -} +}; export function textTable( rows_: (string | number)[][], @@ -50,6 +50,7 @@ export function textTable( const n = stringLength(String(c)); if (!acc[ix] || n > acc[ix]) { + // eslint-disable-next-line functional/immutable-data,no-param-reassign acc[ix] = n; } }); @@ -62,7 +63,7 @@ export function textTable( .map((c: string | number, ix: number) => { const cellStr = String(c); const n = (sizes[ix] ?? 0) - stringLength(cellStr) || 0; - const s = Array(Math.max(n + 1, 1)).join(' '); + const s = Array.from({ length: Math.max(n + 1, 1) }).join(' '); if (align[ix] === 'r') { return s + cellStr; diff --git a/tools/eslint-formatter-multi/src/lib/utils.ts b/tools/eslint-formatter-multi/src/lib/utils.ts index 1a9d90e9d..ffe64e603 100644 --- a/tools/eslint-formatter-multi/src/lib/utils.ts +++ b/tools/eslint-formatter-multi/src/lib/utils.ts @@ -1,7 +1,7 @@ import type { ESLint } from 'eslint'; import { mkdir, writeFile } from 'node:fs/promises'; import path from 'node:path'; -import stylishFormatter from './stylish.js'; +import { stylishFormatter } from './stylish.js'; import type { FormatterConfig } from './types.js'; export function stringifyError(error: unknown): string { From ccdb58d6a3dc6be8c5c06febe023d2e4bdb9ba35 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 00:46:04 +0200 Subject: [PATCH 32/37] refactor: fix lint target --- nx.json | 4 ++-- tools/tsconfig.tools.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nx.json b/nx.json index 5cd2e84ed..c4d40d6fd 100644 --- a/nx.json +++ b/nx.json @@ -109,12 +109,12 @@ } }, "lint-report": { - "dependsOn": ["eslint-formatter-multiple-formats:build"], + "dependsOn": ["eslint-formatter-multi:build"], "inputs": ["lint-eslint-inputs"], "outputs": ["{projectRoot}/.eslint"], "executor": "nx:run-commands", "options": { - "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multiple-formats/dist/src/index.js", + "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multi/dist/src/index.js", "env": { "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" } diff --git a/tools/tsconfig.tools.json b/tools/tsconfig.tools.json index 060e2c775..387fcedf7 100644 --- a/tools/tsconfig.tools.json +++ b/tools/tsconfig.tools.json @@ -9,5 +9,5 @@ "importHelpers": false }, "include": ["**/*.ts"], - "exclude": ["eslint-formatter-multiple-formats/**/*"] + "exclude": ["eslint-formatter-multi/**/*"] } From 16a39775429684fe6c6091f98eb1f79e5cbdd265 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 02:40:46 +0200 Subject: [PATCH 33/37] refactor: use plugin to set up targets --- nx.json | 63 ++++++++++++++----------- package-lock.json | 118 +++++++--------------------------------------- package.json | 3 +- 3 files changed, 55 insertions(+), 129 deletions(-) diff --git a/nx.json b/nx.json index c4d40d6fd..0d15ed9d3 100644 --- a/nx.json +++ b/nx.json @@ -49,12 +49,32 @@ } ], "sharedGlobals": [ - { "runtime": "node -e \"console.log(require('os').platform())\"" }, - { "runtime": "node -v" }, - { "runtime": "npm -v" } + { + "runtime": "node -e \"console.log(require('os').platform())\"" + }, + { + "runtime": "node -v" + }, + { + "runtime": "npm -v" + } ] }, "targetDefaults": { + "lint": { + "dependsOn": ["eslint-formatter-multi:build"], + "inputs": ["lint-eslint-inputs"], + "outputs": ["{projectRoot}/.eslint/**/*"], + "cache": true, + "options": { + "max-warnings": 0, + "error-on-unmatched-pattern": false, + "//": "replace the formatter path with the released package @code-pushup/eslint-formatter-multi when available", + "//": "this will make the formatter resolve in any target.", + "format": "./tools/eslint-formatter-multi/dist/src/index.js", + "cwd": "{workspaceRoot}" + } + }, "build": { "dependsOn": ["^build"], "inputs": ["production", "^production"], @@ -95,31 +115,6 @@ "inputs": ["default"], "cache": true }, - "lint": { - "inputs": ["lint-eslint-inputs"], - "executor": "@nx/eslint:lint", - "cache": true, - "options": { - "errorOnUnmatchedPattern": false, - "maxWarnings": 0, - "lintFilePatterns": [ - "{projectRoot}/**/*.ts", - "{projectRoot}/package.json" - ] - } - }, - "lint-report": { - "dependsOn": ["eslint-formatter-multi:build"], - "inputs": ["lint-eslint-inputs"], - "outputs": ["{projectRoot}/.eslint"], - "executor": "nx:run-commands", - "options": { - "command": "nx run {projectName}:lint --format=./tools/eslint-formatter-multi/dist/src/index.js", - "env": { - "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" - } - } - }, "nxv-pkg-install": { "parallelism": false }, @@ -330,6 +325,12 @@ "releaseTagPattern": "v{version}" }, "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + }, { "plugin": "@push-based/nx-verdaccio", "options": { @@ -344,6 +345,12 @@ "filterByTags": ["publishable"] } } + }, + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } } ], "nxCloudId": "65d4d862d2adb16a45a4bc7c" diff --git a/package-lock.json b/package-lock.json index 2bec297ba..ed6437218 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,7 +45,7 @@ "@commitlint/types": "^19.5.0", "@nodelib/fs.walk": "^2.0.0", "@nx/eslint": "^21.4.1", - "@nx/eslint-plugin": "21.4.1", + "@nx/eslint-plugin": "^21.4.1", "@nx/js": "21.4.1", "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", @@ -8035,7 +8035,7 @@ "version": "1.13.3", "resolved": "https://registry.npmjs.org/@swc-node/core/-/core-1.13.3.tgz", "integrity": "sha512-OGsvXIid2Go21kiNqeTIn79jcaX4l0G93X2rAnas4LFoDyA9wAwVK7xZdm+QsKoMn5Mus2yFLCc4OtX2dD/PWA==", - "devOptional": true, + "dev": true, "engines": { "node": ">= 10" }, @@ -8052,7 +8052,7 @@ "version": "1.9.2", "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.9.2.tgz", "integrity": "sha512-BBjg0QNuEEmJSoU/++JOXhrjWdu3PTyYeJWsvchsI0Aqtj8ICkz/DqlwtXbmZVZ5vuDPpTfFlwDBZe81zgShMA==", - "devOptional": true, + "dev": true, "dependencies": { "@swc-node/core": "^1.13.1", "@swc-node/sourcemap-support": "^0.5.0", @@ -8074,7 +8074,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.5.1.tgz", "integrity": "sha512-JxIvIo/Hrpv0JCHSyRpetAdQ6lB27oFYhv0PKCNf1g2gUXOjpeR1exrXccRxLMuAV5WAmGFBwRnNOJqN38+qtg==", - "devOptional": true, + "dev": true, "dependencies": { "source-map-support": "^0.5.21", "tslib": "^2.6.3" @@ -8084,7 +8084,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.10.0" } @@ -8093,7 +8093,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "devOptional": true, + "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8153,7 +8153,7 @@ "version": "1.5.7", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", - "devOptional": true, + "dev": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.2", @@ -8194,6 +8194,7 @@ "cpu": [ "x64" ], + "dev": true, "optional": true, "os": [ "win32" @@ -8206,7 +8207,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", - "devOptional": true, + "dev": true, "dependencies": { "@swc/counter": "^0.1.3" } @@ -8215,7 +8216,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "devOptional": true + "dev": true }, "node_modules/@swc/helpers": { "version": "0.5.13", @@ -8225,17 +8226,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@swc/types": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.24.tgz", - "integrity": "sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng==", - "devOptional": true, - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@swc/counter": "^0.1.3" - } - }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -8248,59 +8238,6 @@ "node": ">=10" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/@testing-library/dom/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@testing-library/jest-dom": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", @@ -8626,14 +8563,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "license": "MIT", - "peer": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -12355,7 +12284,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "devOptional": true + "dev": true }, "node_modules/build-md": { "version": "0.4.2", @@ -13142,7 +13071,7 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "devOptional": true + "dev": true }, "node_modules/columnify": { "version": "1.6.0", @@ -14976,7 +14905,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.2" @@ -14986,7 +14915,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -21656,7 +21585,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -22862,17 +22791,6 @@ "node": ">=12" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -24694,7 +24612,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -27033,7 +26951,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true + "dev": true }, "node_modules/saxes": { "version": "6.0.0", @@ -29322,7 +29240,7 @@ "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index ba7596460..44f72ee6a 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "@commitlint/cz-commitlint": "^19.5.0", "@commitlint/types": "^19.5.0", "@nodelib/fs.walk": "^2.0.0", - "@nx/eslint-plugin": "21.4.1", + "@nx/eslint": "^21.4.1", + "@nx/eslint-plugin": "^21.4.1", "@nx/js": "21.4.1", "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", From 97e1e6c959fdcf131846f6077e496a3e9887b911 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 11:29:31 +0200 Subject: [PATCH 34/37] chore: adjust lint target --- nx.json | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/nx.json b/nx.json index 0d15ed9d3..50e0ce111 100644 --- a/nx.json +++ b/nx.json @@ -66,13 +66,21 @@ "inputs": ["lint-eslint-inputs"], "outputs": ["{projectRoot}/.eslint/**/*"], "cache": true, + "executor": "nx:run-commands", "options": { - "max-warnings": 0, - "error-on-unmatched-pattern": false, - "//": "replace the formatter path with the released package @code-pushup/eslint-formatter-multi when available", - "//": "this will make the formatter resolve in any target.", - "format": "./tools/eslint-formatter-multi/dist/src/index.js", - "cwd": "{workspaceRoot}" + "command": "eslint", + "args": [ + "{projectRoot}/**/*.ts", + "{projectRoot}/package.json", + "--config={projectRoot}/eslint.config.js", + "--max-warnings=0", + "--error-on-unmatched-pattern=false", + "--format=./tools/eslint-formatter-multi/dist/src/index.js" + ], + "cwd": "{workspaceRoot}", + "env": { + "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" + } } }, "build": { @@ -325,12 +333,6 @@ "releaseTagPattern": "v{version}" }, "plugins": [ - { - "plugin": "@nx/eslint/plugin", - "options": { - "targetName": "lint" - } - }, { "plugin": "@push-based/nx-verdaccio", "options": { @@ -345,12 +347,6 @@ "filterByTags": ["publishable"] } } - }, - { - "plugin": "@nx/eslint/plugin", - "options": { - "targetName": "lint" - } } ], "nxCloudId": "65d4d862d2adb16a45a4bc7c" From 44ddcedd096277ae7a76b51e6533a8a21ee0584a Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 11:31:49 +0200 Subject: [PATCH 35/37] chore: fix pkg install --- package-lock.json | 118 +++++++++++++++++++++++++++++++++++++++------- package.json | 3 +- 2 files changed, 101 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed6437218..53ab456d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,8 +44,7 @@ "@commitlint/cz-commitlint": "^19.5.0", "@commitlint/types": "^19.5.0", "@nodelib/fs.walk": "^2.0.0", - "@nx/eslint": "^21.4.1", - "@nx/eslint-plugin": "^21.4.1", + "@nx/eslint-plugin": "21.4.1", "@nx/js": "21.4.1", "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", @@ -8035,7 +8034,7 @@ "version": "1.13.3", "resolved": "https://registry.npmjs.org/@swc-node/core/-/core-1.13.3.tgz", "integrity": "sha512-OGsvXIid2Go21kiNqeTIn79jcaX4l0G93X2rAnas4LFoDyA9wAwVK7xZdm+QsKoMn5Mus2yFLCc4OtX2dD/PWA==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 10" }, @@ -8052,7 +8051,7 @@ "version": "1.9.2", "resolved": "https://registry.npmjs.org/@swc-node/register/-/register-1.9.2.tgz", "integrity": "sha512-BBjg0QNuEEmJSoU/++JOXhrjWdu3PTyYeJWsvchsI0Aqtj8ICkz/DqlwtXbmZVZ5vuDPpTfFlwDBZe81zgShMA==", - "dev": true, + "devOptional": true, "dependencies": { "@swc-node/core": "^1.13.1", "@swc-node/sourcemap-support": "^0.5.0", @@ -8074,7 +8073,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/@swc-node/sourcemap-support/-/sourcemap-support-0.5.1.tgz", "integrity": "sha512-JxIvIo/Hrpv0JCHSyRpetAdQ6lB27oFYhv0PKCNf1g2gUXOjpeR1exrXccRxLMuAV5WAmGFBwRnNOJqN38+qtg==", - "dev": true, + "devOptional": true, "dependencies": { "source-map-support": "^0.5.21", "tslib": "^2.6.3" @@ -8084,7 +8083,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -8093,7 +8092,7 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, + "devOptional": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8153,7 +8152,7 @@ "version": "1.5.7", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.5.7.tgz", "integrity": "sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "dependencies": { "@swc/counter": "^0.1.2", @@ -8207,7 +8206,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.7.tgz", "integrity": "sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==", - "dev": true, + "devOptional": true, "dependencies": { "@swc/counter": "^0.1.3" } @@ -8216,7 +8215,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", - "dev": true + "devOptional": true }, "node_modules/@swc/helpers": { "version": "0.5.13", @@ -8226,6 +8225,17 @@ "tslib": "^2.4.0" } }, + "node_modules/@swc/types": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.24.tgz", + "integrity": "sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -8238,6 +8248,59 @@ "node": ">=10" } }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@testing-library/dom/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/@testing-library/dom/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@testing-library/jest-dom": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz", @@ -8563,6 +8626,14 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -12284,7 +12355,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "devOptional": true }, "node_modules/build-md": { "version": "0.4.2", @@ -13071,7 +13142,7 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "devOptional": true }, "node_modules/columnify": { "version": "1.6.0", @@ -14905,7 +14976,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.2" @@ -14915,7 +14986,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -21585,7 +21656,7 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -22791,6 +22862,17 @@ "node": ">=12" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.11", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", @@ -24612,7 +24694,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 6" @@ -26951,7 +27033,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "devOptional": true }, "node_modules/saxes": { "version": "6.0.0", @@ -29240,7 +29322,7 @@ "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 44f72ee6a..ba7596460 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,7 @@ "@commitlint/cz-commitlint": "^19.5.0", "@commitlint/types": "^19.5.0", "@nodelib/fs.walk": "^2.0.0", - "@nx/eslint": "^21.4.1", - "@nx/eslint-plugin": "^21.4.1", + "@nx/eslint-plugin": "21.4.1", "@nx/js": "21.4.1", "@nx/plugin": "21.4.1", "@nx/react": "21.4.1", From 8eb075a4d14d54cd93af50e11d76b770bd39c275 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 3 Sep 2025 13:25:58 +0200 Subject: [PATCH 36/37] chore: fix lint --- nx.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nx.json b/nx.json index 50e0ce111..9549d1293 100644 --- a/nx.json +++ b/nx.json @@ -74,10 +74,10 @@ "{projectRoot}/package.json", "--config={projectRoot}/eslint.config.js", "--max-warnings=0", + "--no-warn-ignored", "--error-on-unmatched-pattern=false", "--format=./tools/eslint-formatter-multi/dist/src/index.js" ], - "cwd": "{workspaceRoot}", "env": { "ESLINT_FORMATTER_CONFIG": "{\"outputDir\":\"{projectRoot}/.eslint\"}" } From f56ba9e6a40ab6f5f612ed0cee778216d3e5b589 Mon Sep 17 00:00:00 2001 From: Michael Hladky <10064416+BioPhoton@users.noreply.github.com> Date: Wed, 3 Sep 2025 14:18:42 +0200 Subject: [PATCH 37/37] Update tools/eslint-formatter-multi/package.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Matěj Chalk <34691111+matejchalk@users.noreply.github.com> --- tools/eslint-formatter-multi/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/eslint-formatter-multi/package.json b/tools/eslint-formatter-multi/package.json index 87f93f505..6aaddcec0 100644 --- a/tools/eslint-formatter-multi/package.json +++ b/tools/eslint-formatter-multi/package.json @@ -1,5 +1,5 @@ { - "name": "eslint-formatter-multi", + "name": "@code-pushup/eslint-formatter-multi", "version": "0.0.1", "private": false, "type": "module",