From bbd864865f56649b9f6ab840de25bd8726379f1e Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Wed, 21 Jan 2026 21:40:18 +0100 Subject: [PATCH 01/24] feat: use jiti for plugin loading --- nx.json | 5 ++--- package-lock.json | 24 ++++++++++++++++++++++++ package.json | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/nx.json b/nx.json index 7e7265dfe..806a8a509 100644 --- a/nx.json +++ b/nx.json @@ -127,15 +127,14 @@ "executor": "nx:run-commands", "dependsOn": ["code-pushup-*"], "options": { - "command": "node packages/cli/src/index.ts", + "command": "npx jiti-tsc packages/cli/src/index.ts", "args": [ "--config={projectRoot}/code-pushup.config.ts", "--cache.read", "--persist.outputDir=.code-pushup/{projectName}" ], "env": { - "NODE_OPTIONS": "--import tsx", - "TSX_TSCONFIG_PATH": "tsconfig.base.json" + "JITI_TS_CONFIG_PATH": "tsconfig.base.json" } } }, diff --git a/package-lock.json b/package-lock.json index b9c0986ff..9bc14cc43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,6 +54,7 @@ "@nx/react": "22.3.3", "@nx/vite": "22.3.3", "@nx/workspace": "22.3.3", + "@push-based/jiti-tsc": "^0.0.2", "@push-based/nx-verdaccio": "0.0.7", "@swc-node/register": "1.9.2", "@swc/cli": "0.6.0", @@ -6316,6 +6317,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@push-based/jiti-tsc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@push-based/jiti-tsc/-/jiti-tsc-0.0.2.tgz", + "integrity": "sha512-9K8IYbZePUzPHDkA6tuOukFcJT6xu6bbFtWaws0CtVsmQaeqyRrKuSYFMl73OIee7oOXUOZS2QMIZp3ky6sh/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansis": "^3.3.2", + "jiti": "^2.4.2", + "ora": "^9.0.0", + "tslib": "^2.8.1", + "typescript": "5.7.3" + }, + "bin": { + "jiti-tsc": "src/bin/bin.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "zod": "^4.0.0" + } + }, "node_modules/@push-based/nx-verdaccio": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/@push-based/nx-verdaccio/-/nx-verdaccio-0.0.7.tgz", diff --git a/package.json b/package.json index a7b55cf4f..ba5389b73 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@nx/react": "22.3.3", "@nx/vite": "22.3.3", "@nx/workspace": "22.3.3", + "@push-based/jiti-tsc": "^0.0.2", "@push-based/nx-verdaccio": "0.0.7", "@swc-node/register": "1.9.2", "@swc/cli": "0.6.0", From cc442d1fb053bffd7f7d3a38441efe399e05a5ca Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Thu, 22 Jan 2026 22:56:40 +0100 Subject: [PATCH 02/24] refactor: move loadTargetConfig into utils --- .../src/lib/runner/ts-runner.ts | 8 +++-- .../plugin-typescript/src/lib/runner/utils.ts | 30 ------------------- packages/utils/package.json | 3 +- packages/utils/src/index.ts | 1 + .../src/lib/load-ts-config.int.test.ts} | 2 +- packages/utils/src/lib/load-ts-config.ts | 29 ++++++++++++++++++ 6 files changed, 39 insertions(+), 34 deletions(-) rename packages/{plugin-typescript/src/lib/runner/utils.int.test.ts => utils/src/lib/load-ts-config.int.test.ts} (97%) create mode 100644 packages/utils/src/lib/load-ts-config.ts diff --git a/packages/plugin-typescript/src/lib/runner/ts-runner.ts b/packages/plugin-typescript/src/lib/runner/ts-runner.ts index 6103b6e1e..d1541f126 100644 --- a/packages/plugin-typescript/src/lib/runner/ts-runner.ts +++ b/packages/plugin-typescript/src/lib/runner/ts-runner.ts @@ -3,8 +3,12 @@ import { createProgram, getPreEmitDiagnostics, } from 'typescript'; -import { logger, pluralizeToken, stringifyError } from '@code-pushup/utils'; -import { loadTargetConfig } from './utils.js'; +import { + loadTargetConfig, + logger, + pluralizeToken, + stringifyError, +} from '@code-pushup/utils'; export type DiagnosticsOptions = { tsconfig: string; diff --git a/packages/plugin-typescript/src/lib/runner/utils.ts b/packages/plugin-typescript/src/lib/runner/utils.ts index 23c3ee67b..48c68560c 100644 --- a/packages/plugin-typescript/src/lib/runner/utils.ts +++ b/packages/plugin-typescript/src/lib/runner/utils.ts @@ -3,9 +3,6 @@ import { type Diagnostic, DiagnosticCategory, flattenDiagnosticMessageText, - parseJsonConfigFileContent, - readConfigFile, - sys, } from 'typescript'; import type { Issue } from '@code-pushup/models'; import { truncateIssueMessage } from '@code-pushup/utils'; @@ -88,30 +85,3 @@ export function getIssueFromDiagnostic(diag: Diagnostic) { }, } satisfies Issue; } - -export function loadTargetConfig(tsConfigPath: string) { - const resolvedConfigPath = path.resolve(tsConfigPath); - const { config, error } = readConfigFile(resolvedConfigPath, sys.readFile); - - if (error) { - throw new Error( - `Error reading TypeScript config file at ${tsConfigPath}:\n${error.messageText}`, - ); - } - - const parsedConfig = parseJsonConfigFileContent( - config, - sys, - path.dirname(resolvedConfigPath), - {}, - resolvedConfigPath, - ); - - if (parsedConfig.fileNames.length === 0) { - throw new Error( - 'No files matched by the TypeScript configuration. Check your "include", "exclude" or "files" settings.', - ); - } - - return parsedConfig; -} diff --git a/packages/utils/package.json b/packages/utils/package.json index aed4bca83..990c0fd69 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -37,7 +37,8 @@ "simple-git": "^3.20.0", "string-width": "^8.1.0", "wrap-ansi": "^9.0.2", - "zod": "^4.2.1" + "zod": "^4.2.1", + "typescript": "5.7.3" }, "files": [ "src", diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index f019b8055..143df490f 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -32,6 +32,7 @@ export { type ProcessObserver, type ProcessResult, } from './lib/execute-process.js'; +export { loadTargetConfig } from './lib/load-ts-config.js'; export { crawlFileSystem, createReportPath, diff --git a/packages/plugin-typescript/src/lib/runner/utils.int.test.ts b/packages/utils/src/lib/load-ts-config.int.test.ts similarity index 97% rename from packages/plugin-typescript/src/lib/runner/utils.int.test.ts rename to packages/utils/src/lib/load-ts-config.int.test.ts index c202d59be..c8f326e58 100644 --- a/packages/plugin-typescript/src/lib/runner/utils.int.test.ts +++ b/packages/utils/src/lib/load-ts-config.int.test.ts @@ -1,7 +1,7 @@ import * as tsModule from 'typescript'; import { describe, expect, vi } from 'vitest'; import { osAgnosticPath } from '@code-pushup/test-utils'; -import { loadTargetConfig } from './utils.js'; +import { loadTargetConfig } from './load-ts-config.js'; describe('loadTargetConfig', () => { const readConfigFileSpy = vi.spyOn(tsModule, 'readConfigFile'); diff --git a/packages/utils/src/lib/load-ts-config.ts b/packages/utils/src/lib/load-ts-config.ts new file mode 100644 index 000000000..010732ebf --- /dev/null +++ b/packages/utils/src/lib/load-ts-config.ts @@ -0,0 +1,29 @@ +import path from 'node:path'; +import { parseJsonConfigFileContent, readConfigFile, sys } from 'typescript'; + +export function loadTargetConfig(tsConfigPath: string) { + const resolvedConfigPath = path.resolve(tsConfigPath); + const { config, error } = readConfigFile(resolvedConfigPath, sys.readFile); + + if (error) { + throw new Error( + `Error reading TypeScript config file at ${tsConfigPath}:\n${error.messageText}`, + ); + } + + const parsedConfig = parseJsonConfigFileContent( + config, + sys, + path.dirname(resolvedConfigPath), + {}, + resolvedConfigPath, + ); + + if (parsedConfig.fileNames.length === 0) { + throw new Error( + 'No files matched by the TypeScript configuration. Check your "include", "exclude" or "files" settings.', + ); + } + + return parsedConfig; +} From c9cb8957630e9381c508c46c8a5f2af115745899 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Thu, 22 Jan 2026 23:06:58 +0100 Subject: [PATCH 03/24] refactor: move importModule into extra file --- packages/utils/src/index.ts | 2 +- packages/utils/src/lib/file-system.ts | 19 ------------------ ....int.test.ts => import-module.int.test.ts} | 2 +- packages/utils/src/lib/import-module.ts | 20 +++++++++++++++++++ 4 files changed, 22 insertions(+), 21 deletions(-) rename packages/utils/src/lib/{file-system.int.test.ts => import-module.int.test.ts} (97%) create mode 100644 packages/utils/src/lib/import-module.ts diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index 143df490f..a06e834b5 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -42,7 +42,6 @@ export { filePathToCliArg, findLineNumberInText, findNearestFile, - importModule, pluginWorkDir, projectToFilename, readJsonFile, @@ -179,3 +178,4 @@ export type { Prettify, WithRequired, } from './lib/types.js'; +export * from './lib/import-module.js'; diff --git a/packages/utils/src/lib/file-system.ts b/packages/utils/src/lib/file-system.ts index 5956dbbff..cbe72f547 100644 --- a/packages/utils/src/lib/file-system.ts +++ b/packages/utils/src/lib/file-system.ts @@ -1,9 +1,7 @@ -import { type Options, bundleRequire } from 'bundle-require'; import { mkdir, readFile, readdir, rm, stat } from 'node:fs/promises'; import path from 'node:path'; import type { Format, PersistConfig } from '@code-pushup/models'; import { logger } from './logger.js'; -import { settlePromise } from './promises.js'; export async function readTextFile(filePath: string): Promise { const buffer = await readFile(filePath); @@ -52,23 +50,6 @@ export async function removeDirectoryIfExists(dir: string) { } } -export async function importModule(options: Options): Promise { - const resolvedStats = await settlePromise(stat(options.filepath)); - if (resolvedStats.status === 'rejected') { - throw new Error(`File '${options.filepath}' does not exist`); - } - if (!resolvedStats.value.isFile()) { - throw new Error(`Expected '${options.filepath}' to be a file`); - } - - const { mod } = await bundleRequire(options); - - if (typeof mod === 'object' && 'default' in mod) { - return mod.default as T; - } - return mod as T; -} - export function createReportPath({ outputDir, filename, diff --git a/packages/utils/src/lib/file-system.int.test.ts b/packages/utils/src/lib/import-module.int.test.ts similarity index 97% rename from packages/utils/src/lib/file-system.int.test.ts rename to packages/utils/src/lib/import-module.int.test.ts index b355e1bb1..e347b423d 100644 --- a/packages/utils/src/lib/file-system.int.test.ts +++ b/packages/utils/src/lib/import-module.int.test.ts @@ -1,6 +1,6 @@ import path from 'node:path'; import { describe, expect, it } from 'vitest'; -import { importModule } from './file-system.js'; +import { importModule } from './import-module.js'; describe('importModule', () => { const mockDir = path.join( diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts new file mode 100644 index 000000000..eaefb187b --- /dev/null +++ b/packages/utils/src/lib/import-module.ts @@ -0,0 +1,20 @@ +import { type Options, bundleRequire } from 'bundle-require'; +import { stat } from 'node:fs/promises'; +import { settlePromise } from './promises.js'; + +export async function importModule(options: Options): Promise { + const resolvedStats = await settlePromise(stat(options.filepath)); + if (resolvedStats.status === 'rejected') { + throw new Error(`File '${options.filepath}' does not exist`); + } + if (!resolvedStats.value.isFile()) { + throw new Error(`Expected '${options.filepath}' to be a file`); + } + + const { mod } = await bundleRequire(options); + + if (typeof mod === 'object' && 'default' in mod) { + return mod.default as T; + } + return mod as T; +} From aee50d950da1d59ec0d84d1bd03800023d7bf442 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 01:02:12 +0100 Subject: [PATCH 04/24] refactor: use jiti to load module --- nx.json | 5 +- package-lock.json | 2 +- package.json | 2 +- .../fixtures/tsconfig-setup/import-alias.ts | 3 + .../fixtures/tsconfig-setup/tsconfig.json | 8 + .../mocks/fixtures/tsconfig-setup/utils.ts | 1 + .../utils/src/lib/import-module.int.test.ts | 61 ++++++- packages/utils/src/lib/import-module.ts | 164 +++++++++++++++++- .../utils/src/lib/import-module.unit.test.ts | 118 +++++++++++++ 9 files changed, 348 insertions(+), 16 deletions(-) create mode 100644 packages/utils/mocks/fixtures/tsconfig-setup/import-alias.ts create mode 100644 packages/utils/mocks/fixtures/tsconfig-setup/tsconfig.json create mode 100644 packages/utils/mocks/fixtures/tsconfig-setup/utils.ts create mode 100644 packages/utils/src/lib/import-module.unit.test.ts diff --git a/nx.json b/nx.json index 806a8a509..7e7265dfe 100644 --- a/nx.json +++ b/nx.json @@ -127,14 +127,15 @@ "executor": "nx:run-commands", "dependsOn": ["code-pushup-*"], "options": { - "command": "npx jiti-tsc packages/cli/src/index.ts", + "command": "node packages/cli/src/index.ts", "args": [ "--config={projectRoot}/code-pushup.config.ts", "--cache.read", "--persist.outputDir=.code-pushup/{projectName}" ], "env": { - "JITI_TS_CONFIG_PATH": "tsconfig.base.json" + "NODE_OPTIONS": "--import tsx", + "TSX_TSCONFIG_PATH": "tsconfig.base.json" } } }, diff --git a/package-lock.json b/package-lock.json index 9bc14cc43..71025c463 100644 --- a/package-lock.json +++ b/package-lock.json @@ -93,7 +93,7 @@ "husky": "^8.0.0", "inquirer": "^9.3.7", "jest-extended": "^6.0.0", - "jiti": "2.4.2", + "jiti": "^2.4.2", "jsdom": "~24.0.0", "jsonc-eslint-parser": "^2.4.0", "knip": "^5.33.3", diff --git a/package.json b/package.json index ba5389b73..b658697aa 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "husky": "^8.0.0", "inquirer": "^9.3.7", "jest-extended": "^6.0.0", - "jiti": "2.4.2", + "jiti": "^2.4.2", "jsdom": "~24.0.0", "jsonc-eslint-parser": "^2.4.0", "knip": "^5.33.3", diff --git a/packages/utils/mocks/fixtures/tsconfig-setup/import-alias.ts b/packages/utils/mocks/fixtures/tsconfig-setup/import-alias.ts new file mode 100644 index 000000000..4488e1aa9 --- /dev/null +++ b/packages/utils/mocks/fixtures/tsconfig-setup/import-alias.ts @@ -0,0 +1,3 @@ +import { name } from '@utils'; + +export default `valid-ts-default-export-${name}`; diff --git a/packages/utils/mocks/fixtures/tsconfig-setup/tsconfig.json b/packages/utils/mocks/fixtures/tsconfig-setup/tsconfig.json new file mode 100644 index 000000000..d22493e7f --- /dev/null +++ b/packages/utils/mocks/fixtures/tsconfig-setup/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "paths": { + "@utils/*": ["./utils.ts"] + } + }, + "include": ["*.ts"] +} diff --git a/packages/utils/mocks/fixtures/tsconfig-setup/utils.ts b/packages/utils/mocks/fixtures/tsconfig-setup/utils.ts new file mode 100644 index 000000000..a7bfb2e45 --- /dev/null +++ b/packages/utils/mocks/fixtures/tsconfig-setup/utils.ts @@ -0,0 +1 @@ +export const name = 'utils-export'; diff --git a/packages/utils/src/lib/import-module.int.test.ts b/packages/utils/src/lib/import-module.int.test.ts index e347b423d..c8ab19fc4 100644 --- a/packages/utils/src/lib/import-module.int.test.ts +++ b/packages/utils/src/lib/import-module.int.test.ts @@ -1,6 +1,6 @@ import path from 'node:path'; -import { describe, expect, it } from 'vitest'; -import { importModule } from './import-module.js'; +import { describe, expect, it, vi } from 'vitest'; +import { deriveTsConfig, importModule } from './import-module.js'; describe('importModule', () => { const mockDir = path.join( @@ -45,6 +45,25 @@ describe('importModule', () => { ).resolves.toBe('valid-ts-default-export'); }); + it('imports module with default tsconfig when tsconfig undefined', async () => { + vi.clearAllMocks(); + await expect( + importModule({ + filepath: path.join(mockDir, 'valid-ts-default-export.ts'), + }), + ).resolves.toBe('valid-ts-default-export'); + }); + + it('imports module with custom tsconfig', async () => { + vi.clearAllMocks(); + await expect( + importModule({ + filepath: path.join(mockDir, 'tsconfig-setup', 'import-alias.ts'), + tsconfig: path.join(mockDir, 'tsconfig-setup', 'tsconfig.json'), + }), + ).resolves.toBe('valid-ts-default-export-utils-export'); + }); + it('should throw if the file does not exist', async () => { await expect( importModule({ filepath: 'path/to/non-existent-export.mjs' }), @@ -57,11 +76,41 @@ describe('importModule', () => { ); }); - it('should throw if file is not valid JS', async () => { + it('should load valid JSON', async () => { await expect( importModule({ filepath: path.join(mockDir, 'invalid-js-file.json') }), - ).rejects.toThrow( - `${path.join(mockDir, 'invalid-js-file.json')} is not a valid JS file`, - ); + ).resolves.toStrictEqual({ key: 'value' }); + }); +}); + +describe('deriveTsConfig', () => { + const mockDir = path.join( + process.cwd(), + 'packages', + 'utils', + 'mocks', + 'fixtures', + ); + + it('should load a valid tsconfig.json file', async () => { + const configPath = path.join(mockDir, 'tsconfig-setup', 'tsconfig.json'); + + await expect(deriveTsConfig(configPath)).resolves.toStrictEqual({ + configFilePath: expect.any(String), + paths: { + '@utils/*': ['./utils.ts'], + }, + pathsBasePath: expect.any(String), + }); + }); + + it('should throw if the path is empty', async () => { + await expect(deriveTsConfig('')).rejects.toThrow(/Tsconfig file not found/); + }); + + it('should throw if the file does not exist', async () => { + await expect( + deriveTsConfig(path.join('non-existent', 'tsconfig.json')), + ).rejects.toThrow(/Tsconfig file not found/); }); }); diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index eaefb187b..a3c927c90 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -1,8 +1,16 @@ -import { type Options, bundleRequire } from 'bundle-require'; +import { type JitiOptions, createJiti as createJitiSource } from 'jiti'; import { stat } from 'node:fs/promises'; +import path from 'node:path'; +import type { CompilerOptions } from 'typescript'; +import { fileExists } from './file-system'; +import { loadTargetConfig } from './load-ts-config'; import { settlePromise } from './promises.js'; -export async function importModule(options: Options): Promise { +export async function importModule( + options: JitiOptions & { filepath: string; tsconfig?: string }, +): Promise { + const { filepath, tsconfig, ...jitiOptions } = options; + const resolvedStats = await settlePromise(stat(options.filepath)); if (resolvedStats.status === 'rejected') { throw new Error(`File '${options.filepath}' does not exist`); @@ -11,10 +19,154 @@ export async function importModule(options: Options): Promise { throw new Error(`Expected '${options.filepath}' to be a file`); } - const { mod } = await bundleRequire(options); + const jitiInstance = await createTsJiti(options.filepath, { + ...jitiOptions, + tsconfigPath: options.tsconfig, + }); + return (await jitiInstance.import(filepath, { default: true })) as T; +} + +/** + * Converts TypeScript paths configuration to jiti alias format + * @param paths TypeScript paths object from compiler options + * @param baseUrl Base URL for resolving relative paths + * @returns Jiti alias object with absolute paths + */ +export function mapTsPathsToJitiAlias( + paths: Record, + baseUrl: string, +): Record { + return Object.entries(paths).reduce( + (aliases, [pathPattern, pathMappings]) => { + if (!Array.isArray(pathMappings) || pathMappings.length === 0) { + return aliases; + } + // Jiti does not support overloads (multiple mappings for the same path pattern) + if (pathMappings.length > 1) { + throw new Error( + `TypeScript path overloads are not supported by jiti. Path pattern '${pathPattern}' has ${pathMappings.length} mappings: ${pathMappings.join(', ')}. Jiti only supports a single alias mapping per pattern.`, + ); + } + const aliasKey = pathPattern.replace(/\/\*$/, ''); + const aliasValue = (pathMappings.at(0) as string).replace(/\/\*$/, ''); + return { + ...aliases, + [aliasKey]: path.isAbsolute(aliasValue) + ? aliasValue + : path.resolve(baseUrl, aliasValue), + }; + }, + {} satisfies Record, + ); +} + +/** + * Maps TypeScript JSX emit mode to Jiti JSX boolean option + * @param tsJsxMode TypeScript JsxEmit enum value (0-5) + * @returns true if JSX processing should be enabled, false otherwise + */ +export const mapTsJsxToJitiJsx = (tsJsxMode: number): boolean => + tsJsxMode !== 0; + +/** + * Possible TS to jiti options mapping + * | Jiti Option | Jiti Type | TS Option | TS Type | Description | + * |-------------------|-------------------------|-----------------------|--------------------------|-------------| + * | alias | Record | paths | Record | Module path aliases for module resolution. | + * | interopDefault | boolean | esModuleInterop | boolean | Enable default import interop. | + * | sourceMaps | boolean | sourceMap | boolean | Enable sourcemap generation. | + * | jsx | boolean | jsx | JsxEmit (0-5) | TS JsxEmit enum (0-5) => boolean JSX processing. | + */ +export type MappableJitiOptions = Partial< + Pick +>; + +/** + * Parse TypeScript compiler options to mappable jiti options + * @param compilerOptions TypeScript compiler options + * @param tsconfigDir Directory of the tsconfig file (for resolving relative baseUrl) + * @returns Mappable jiti options + */ +export function parseTsConfigToJitiConfig( + compilerOptions: CompilerOptions, + tsconfigDir?: string, +): MappableJitiOptions { + const paths = compilerOptions.paths || {}; + const baseUrl = compilerOptions.baseUrl + ? path.isAbsolute(compilerOptions.baseUrl) + ? compilerOptions.baseUrl + : tsconfigDir + ? path.resolve(tsconfigDir, compilerOptions.baseUrl) + : path.resolve(process.cwd(), compilerOptions.baseUrl) + : tsconfigDir || process.cwd(); - if (typeof mod === 'object' && 'default' in mod) { - return mod.default as T; + return { + ...(Object.keys(paths).length > 0 + ? { + alias: mapTsPathsToJitiAlias(paths, baseUrl), + } + : {}), + ...(compilerOptions.esModuleInterop == null + ? {} + : { interopDefault: compilerOptions.esModuleInterop }), + ...(compilerOptions.sourceMap == null + ? {} + : { sourceMaps: compilerOptions.sourceMap }), + ...(compilerOptions.jsx == null + ? {} + : { jsx: mapTsJsxToJitiJsx(compilerOptions.jsx) }), + }; +} + +/** + * Create a jiti instance with options derived from tsconfig. + * Used instead of direct jiti.createJiti to allow tsconfig integration. + * @param filepath + * @param options + * @param jiti + */ +export async function createTsJiti( + filepath: string, + options: JitiOptions & { tsconfigPath?: string }, + createJiti: (typeof import('jiti'))['createJiti'] = createJitiSource, +) { + const { tsconfigPath, ...jitiOptions } = options; + const fallbackTsconfigPath = path.resolve('./tsconfig.json'); + const tsDerivedJitiOptions: MappableJitiOptions = tsconfigPath + ? await jitiOptionsFromTsConfig(tsconfigPath) + : (await fileExists(fallbackTsconfigPath)) + ? await jitiOptionsFromTsConfig(tsconfigPath) + : {}; + return createJiti(filepath, { ...jitiOptions, ...tsDerivedJitiOptions }); +} + +/** + * Read tsconfig file and parse options to jiti options + * @param tsconfigPath + */ +export async function jitiOptionsFromTsConfig( + tsconfigPath: string, +): Promise { + const compilerOptions = await deriveTsConfig(tsconfigPath); + const tsconfigDir = path.dirname(tsconfigPath); + return parseTsConfigToJitiConfig(compilerOptions, tsconfigDir); +} + +/** + * Read tsconfig file by path and return the parsed options as JSON object + * @param tsconfigPath + */ +export async function deriveTsConfig( + tsconfigPath: string, +): Promise { + // check if tsconfig file exists + const exists = await fileExists(tsconfigPath); + if (!exists) { + throw new Error( + `Tsconfig file not found at path: ${tsconfigPath.replace(/\\/g, '/')}`, + ); } - return mod as T; + + const { options } = loadTargetConfig(tsconfigPath); + return options; } diff --git a/packages/utils/src/lib/import-module.unit.test.ts b/packages/utils/src/lib/import-module.unit.test.ts new file mode 100644 index 000000000..1d7f3b8ee --- /dev/null +++ b/packages/utils/src/lib/import-module.unit.test.ts @@ -0,0 +1,118 @@ +import type { CompilerOptions } from 'typescript'; +import { describe, expect, it, vi } from 'vitest'; +import { + deriveTsConfig, + mapTsPathsToJitiAlias, + parseTsConfigToJitiConfig, +} from './import-module.js'; + +describe('mapTsPathsToJitiAlias', () => { + it('returns empty object when paths is empty', () => { + expect(mapTsPathsToJitiAlias({}, '/base')).toStrictEqual({}); + }); + + it('returns empty object when all path mappings are empty arrays', () => { + expect(mapTsPathsToJitiAlias({ '@/*': [] }, '/base')).toStrictEqual({}); + }); + + it('maps single path pattern without wildcards', () => { + expect(mapTsPathsToJitiAlias({ '@': ['src'] }, '/base')).toStrictEqual({ + '@': expect.pathToEndWith('base/src'), + }); + }); + + it('strips /* from path pattern and mapping', () => { + expect(mapTsPathsToJitiAlias({ '@/*': ['src/*'] }, '/base')).toStrictEqual({ + '@': expect.pathToEndWith('base/src'), + }); + }); + + it('resolves relative path mappings to absolute', () => { + expect(mapTsPathsToJitiAlias({ '@/*': ['src/*'] }, '/app')).toStrictEqual({ + '@': expect.pathToEndWith('app/src'), + }); + }); + + it('keeps absolute path mappings as-is', () => { + expect( + mapTsPathsToJitiAlias({ '@/*': ['/absolute/path/*'] }, '/base'), + ).toStrictEqual({ '@': '/absolute/path' }); + }); + + it('throws error when path overloads exist (multiple mappings)', () => { + expect(() => + mapTsPathsToJitiAlias({ '@/*': ['first/*', 'second/*'] }, '/base'), + ).toThrow( + "TypeScript path overloads are not supported by jiti. Path pattern '@/*' has 2 mappings: first/*, second/*. Jiti only supports a single alias mapping per pattern.", + ); + }); + + it('maps multiple path patterns', () => { + expect( + mapTsPathsToJitiAlias( + { + '@/*': ['src/*'], + '~/*': ['lib/*'], + }, + '/base', + ), + ).toStrictEqual({ + '@': expect.pathToEndWith('base/src'), + '~': expect.pathToEndWith('base/lib'), + }); + }); + + it('filters out invalid mappings and keeps valid ones', () => { + expect( + mapTsPathsToJitiAlias( + { + 'invalid/*': [], + '@/*': ['src/*'], + 'also-invalid': [], + }, + '/base', + ), + ).toStrictEqual({ + '@': expect.pathToEndWith('src'), + }); + }); +}); + +describe('parseTsConfigToJitiConfig', () => { + it('returns empty object when compiler options are empty', () => { + expect(parseTsConfigToJitiConfig({})).toStrictEqual({}); + }); + + it('includes all options jiti can use', () => { + const compilerOptions: CompilerOptions = { + paths: { + '@app/*': ['src/*'], + '@lib/*': ['lib/*'], + }, + esModuleInterop: true, + sourceMap: true, + jsx: 2, // JsxEmit.React + include: ['**/*.ts'], + + baseUrl: '/base', + }; + + expect(parseTsConfigToJitiConfig(compilerOptions)).toStrictEqual({ + alias: { + '@app': expect.pathToEndWith('src'), + '@lib': expect.pathToEndWith('lib'), + }, + interopDefault: true, + sourceMaps: true, + jsx: true, + }); + }); +}); + +describe('deriveTsConfig', () => { + it('throws error when tsconfig file does not exist', async () => { + await expect(deriveTsConfig('missing.json')).rejects.toThrow( + 'Tsconfig file not found at path: missing.json', + ); + }); +}); From 4c75af5862cbfe7725e5ad490fcf295e743354b0 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 01:18:15 +0100 Subject: [PATCH 05/24] refactor: fix lint --- packages/utils/package.json | 4 +- .../utils/src/lib/import-module.int.test.ts | 34 +-------------- packages/utils/src/lib/import-module.ts | 41 +++++++------------ .../utils/src/lib/import-module.unit.test.ts | 11 +---- 4 files changed, 18 insertions(+), 72 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index 990c0fd69..8dee27c95 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -30,7 +30,6 @@ "@code-pushup/models": "0.108.1", "ansis": "^3.3.0", "build-md": "^0.4.2", - "bundle-require": "^5.1.0", "esbuild": "^0.25.2", "ora": "^9.0.0", "semver": "^7.6.0", @@ -38,7 +37,8 @@ "string-width": "^8.1.0", "wrap-ansi": "^9.0.2", "zod": "^4.2.1", - "typescript": "5.7.3" + "typescript": "5.7.3", + "jiti": "^2.4.2" }, "files": [ "src", diff --git a/packages/utils/src/lib/import-module.int.test.ts b/packages/utils/src/lib/import-module.int.test.ts index c8ab19fc4..1b30500bf 100644 --- a/packages/utils/src/lib/import-module.int.test.ts +++ b/packages/utils/src/lib/import-module.int.test.ts @@ -1,6 +1,6 @@ import path from 'node:path'; import { describe, expect, it, vi } from 'vitest'; -import { deriveTsConfig, importModule } from './import-module.js'; +import { importModule } from './import-module.js'; describe('importModule', () => { const mockDir = path.join( @@ -82,35 +82,3 @@ describe('importModule', () => { ).resolves.toStrictEqual({ key: 'value' }); }); }); - -describe('deriveTsConfig', () => { - const mockDir = path.join( - process.cwd(), - 'packages', - 'utils', - 'mocks', - 'fixtures', - ); - - it('should load a valid tsconfig.json file', async () => { - const configPath = path.join(mockDir, 'tsconfig-setup', 'tsconfig.json'); - - await expect(deriveTsConfig(configPath)).resolves.toStrictEqual({ - configFilePath: expect.any(String), - paths: { - '@utils/*': ['./utils.ts'], - }, - pathsBasePath: expect.any(String), - }); - }); - - it('should throw if the path is empty', async () => { - await expect(deriveTsConfig('')).rejects.toThrow(/Tsconfig file not found/); - }); - - it('should throw if the file does not exist', async () => { - await expect( - deriveTsConfig(path.join('non-existent', 'tsconfig.json')), - ).rejects.toThrow(/Tsconfig file not found/); - }); -}); diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index a3c927c90..4aaf8e2c7 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -2,8 +2,8 @@ import { type JitiOptions, createJiti as createJitiSource } from 'jiti'; import { stat } from 'node:fs/promises'; import path from 'node:path'; import type { CompilerOptions } from 'typescript'; -import { fileExists } from './file-system'; -import { loadTargetConfig } from './load-ts-config'; +import { fileExists } from './file-system.js'; +import { loadTargetConfig } from './load-ts-config.js'; import { settlePromise } from './promises.js'; export async function importModule( @@ -132,11 +132,17 @@ export async function createTsJiti( ) { const { tsconfigPath, ...jitiOptions } = options; const fallbackTsconfigPath = path.resolve('./tsconfig.json'); - const tsDerivedJitiOptions: MappableJitiOptions = tsconfigPath - ? await jitiOptionsFromTsConfig(tsconfigPath) - : (await fileExists(fallbackTsconfigPath)) - ? await jitiOptionsFromTsConfig(tsconfigPath) - : {}; + + const validPath: null | string = + tsconfigPath == null + ? (await fileExists(fallbackTsconfigPath)) + ? fallbackTsconfigPath + : null + : tsconfigPath; + + const tsDerivedJitiOptions: MappableJitiOptions = validPath + ? await jitiOptionsFromTsConfig(validPath) + : {}; return createJiti(filepath, { ...jitiOptions, ...tsDerivedJitiOptions }); } @@ -147,26 +153,7 @@ export async function createTsJiti( export async function jitiOptionsFromTsConfig( tsconfigPath: string, ): Promise { - const compilerOptions = await deriveTsConfig(tsconfigPath); - const tsconfigDir = path.dirname(tsconfigPath); - return parseTsConfigToJitiConfig(compilerOptions, tsconfigDir); -} - -/** - * Read tsconfig file by path and return the parsed options as JSON object - * @param tsconfigPath - */ -export async function deriveTsConfig( - tsconfigPath: string, -): Promise { - // check if tsconfig file exists - const exists = await fileExists(tsconfigPath); - if (!exists) { - throw new Error( - `Tsconfig file not found at path: ${tsconfigPath.replace(/\\/g, '/')}`, - ); - } - const { options } = loadTargetConfig(tsconfigPath); return options; + return parseTsConfigToJitiConfig(options, path.dirname(tsconfigPath)); } diff --git a/packages/utils/src/lib/import-module.unit.test.ts b/packages/utils/src/lib/import-module.unit.test.ts index 1d7f3b8ee..a5e8e8934 100644 --- a/packages/utils/src/lib/import-module.unit.test.ts +++ b/packages/utils/src/lib/import-module.unit.test.ts @@ -1,7 +1,6 @@ import type { CompilerOptions } from 'typescript'; -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { - deriveTsConfig, mapTsPathsToJitiAlias, parseTsConfigToJitiConfig, } from './import-module.js'; @@ -108,11 +107,3 @@ describe('parseTsConfigToJitiConfig', () => { }); }); }); - -describe('deriveTsConfig', () => { - it('throws error when tsconfig file does not exist', async () => { - await expect(deriveTsConfig('missing.json')).rejects.toThrow( - 'Tsconfig file not found at path: missing.json', - ); - }); -}); From 2f53690a17ff88cae694eeb1a4f306432c9590e7 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 01:30:01 +0100 Subject: [PATCH 06/24] refactor: fix lint --- package-lock.json | 18 ++++++++++++++---- package.json | 2 +- packages/utils/src/lib/import-module.ts | 11 ++++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index 71025c463..72b15fa39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -93,7 +93,7 @@ "husky": "^8.0.0", "inquirer": "^9.3.7", "jest-extended": "^6.0.0", - "jiti": "^2.4.2", + "jiti": "^2.6.1", "jsdom": "~24.0.0", "jsonc-eslint-parser": "^2.4.0", "knip": "^5.33.3", @@ -4618,6 +4618,16 @@ "node": ">=8" } }, + "node_modules/@module-federation/cli/node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/@module-federation/cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -22244,9 +22254,9 @@ } }, "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "devOptional": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index b658697aa..c4455978d 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "husky": "^8.0.0", "inquirer": "^9.3.7", "jest-extended": "^6.0.0", - "jiti": "^2.4.2", + "jiti": "^2.6.1", "jsdom": "~24.0.0", "jsonc-eslint-parser": "^2.4.0", "knip": "^5.33.3", diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index 4aaf8e2c7..d6a3b2f24 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -77,10 +77,12 @@ export const mapTsJsxToJitiJsx = (tsJsxMode: number): boolean => * | sourceMaps | boolean | sourceMap | boolean | Enable sourcemap generation. | * | jsx | boolean | jsx | JsxEmit (0-5) | TS JsxEmit enum (0-5) => boolean JSX processing. | */ -export type MappableJitiOptions = Partial< - Pick ->; - +export type MappableJitiOptions = Partial<{ + alias: Record; + interopDefault: boolean; + sourceMaps: boolean; + jsx: boolean; +}>; /** * Parse TypeScript compiler options to mappable jiti options * @param compilerOptions TypeScript compiler options @@ -154,6 +156,5 @@ export async function jitiOptionsFromTsConfig( tsconfigPath: string, ): Promise { const { options } = loadTargetConfig(tsconfigPath); - return options; return parseTsConfigToJitiConfig(options, path.dirname(tsconfigPath)); } From 3428c501d12e1835e5afa42301a409deb3d1f89d Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 02:12:15 +0100 Subject: [PATCH 07/24] refactor: fix int-test --- .../fixtures/configs/code-pushup.config.js | 43 ++++++++++++++++++ .../fixtures/configs/code-pushup.config.mjs | 43 ++++++++++++++++++ .../fixtures/configs/code-pushup.config.ts | 45 +++++++++++++++++++ .../code-pushup.needs-tsconfig-fail.config.ts | 10 +++++ .../code-pushup.needs-tsconfig.config.ts | 10 +++++ .../mocks/fixtures/configs/custom-plugin.ts | 24 ++++++++++ .../fixtures/configs/tsconfig.alias.json | 7 +++ .../cli/mocks/fixtures/configs/tsconfig.json | 5 +++ .../core-config.middleware.int.test.ts | 27 +++++++---- .../code-pushup.needs-tsconfig.config.ts | 2 +- .../src/lib/fixtures/configs/tsconfig.json | 2 +- 11 files changed, 207 insertions(+), 11 deletions(-) create mode 100644 packages/cli/mocks/fixtures/configs/code-pushup.config.js create mode 100644 packages/cli/mocks/fixtures/configs/code-pushup.config.mjs create mode 100644 packages/cli/mocks/fixtures/configs/code-pushup.config.ts create mode 100644 packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig-fail.config.ts create mode 100644 packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig.config.ts create mode 100644 packages/cli/mocks/fixtures/configs/custom-plugin.ts create mode 100644 packages/cli/mocks/fixtures/configs/tsconfig.alias.json create mode 100644 packages/cli/mocks/fixtures/configs/tsconfig.json diff --git a/packages/cli/mocks/fixtures/configs/code-pushup.config.js b/packages/cli/mocks/fixtures/configs/code-pushup.config.js new file mode 100644 index 000000000..9f1661d4d --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/code-pushup.config.js @@ -0,0 +1,43 @@ +export default { + upload: { + organization: 'code-pushup', + project: 'cli-js', + apiKey: 'e2e-api-key', + server: 'https://e2e.com/api', + }, + categories: [ + { + slug: 'category-1', + title: 'Category 1', + refs: [ + { + type: 'audit', + plugin: 'node', + slug: 'node-version', + weight: 1, + }, + ], + }, + ], + plugins: [ + { + audits: [ + { + slug: 'node-version', + title: 'Node version', + description: 'prints node version to file', + docsUrl: 'https://nodejs.org/', + }, + ], + runner: { + command: 'node', + args: ['-v'], + outputFile: 'output.json', + }, + groups: [], + slug: 'node', + title: 'Node.js', + icon: 'javascript', + }, + ], +}; diff --git a/packages/cli/mocks/fixtures/configs/code-pushup.config.mjs b/packages/cli/mocks/fixtures/configs/code-pushup.config.mjs new file mode 100644 index 000000000..d7f531533 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/code-pushup.config.mjs @@ -0,0 +1,43 @@ +export default { + upload: { + organization: 'code-pushup', + project: 'cli-mjs', + apiKey: 'e2e-api-key', + server: 'https://e2e.com/api', + }, + categories: [ + { + slug: 'category-1', + title: 'Category 1', + refs: [ + { + type: 'audit', + plugin: 'node', + slug: 'node-version', + weight: 1, + }, + ], + }, + ], + plugins: [ + { + audits: [ + { + slug: 'node-version', + title: 'Node version', + description: 'prints node version to file', + docsUrl: 'https://nodejs.org/', + }, + ], + runner: { + command: 'node', + args: ['-v'], + outputFile: 'output.json', + }, + groups: [], + slug: 'node', + title: 'Node.js', + icon: 'javascript', + }, + ], +}; diff --git a/packages/cli/mocks/fixtures/configs/code-pushup.config.ts b/packages/cli/mocks/fixtures/configs/code-pushup.config.ts new file mode 100644 index 000000000..aad20f9b6 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/code-pushup.config.ts @@ -0,0 +1,45 @@ +import { type CoreConfig } from '@code-pushup/models'; + +export default { + upload: { + organization: 'code-pushup', + project: 'cli-ts', + apiKey: 'e2e-api-key', + server: 'https://e2e.com/api', + }, + categories: [ + { + slug: 'category-1', + title: 'Category 1', + refs: [ + { + type: 'audit', + plugin: 'node', + slug: 'node-version', + weight: 1, + }, + ], + }, + ], + plugins: [ + { + audits: [ + { + slug: 'node-version', + title: 'Node version', + description: 'prints node version to file', + docsUrl: 'https://nodejs.org/', + }, + ], + runner: { + command: 'node', + args: ['-v'], + outputFile: 'output.json', + }, + groups: [], + slug: 'node', + title: 'Node.js', + icon: 'javascript', + }, + ], +} satisfies CoreConfig; diff --git a/packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig-fail.config.ts b/packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig-fail.config.ts new file mode 100644 index 000000000..6ef0e8967 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig-fail.config.ts @@ -0,0 +1,10 @@ +// the point is to test runtime import which relies on alias defined in tsconfig.json "paths" +// non-type import from '@example/custom-plugin' wouldn't work without --tsconfig +// eslint-disable-next-line import/no-unresolved +import customPlugin from '@definitely-non-existent-package/custom-plugin'; + +const config = { + plugins: [customPlugin], +}; + +export default config; diff --git a/packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig.config.ts b/packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig.config.ts new file mode 100644 index 000000000..6ef0e8967 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/code-pushup.needs-tsconfig.config.ts @@ -0,0 +1,10 @@ +// the point is to test runtime import which relies on alias defined in tsconfig.json "paths" +// non-type import from '@example/custom-plugin' wouldn't work without --tsconfig +// eslint-disable-next-line import/no-unresolved +import customPlugin from '@definitely-non-existent-package/custom-plugin'; + +const config = { + plugins: [customPlugin], +}; + +export default config; diff --git a/packages/cli/mocks/fixtures/configs/custom-plugin.ts b/packages/cli/mocks/fixtures/configs/custom-plugin.ts new file mode 100644 index 000000000..6afe6bc80 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/custom-plugin.ts @@ -0,0 +1,24 @@ +const customPluginConfig = { + slug: 'good-feels', + title: 'Good feels', + icon: 'javascript', + audits: [ + { + slug: 'always-perfect', + title: 'Always perfect', + }, + ], + runner: () => [ + { + slug: 'always-perfect', + score: 1, + value: 100, + displayValue: '✅ Perfect! 👌', + }, + ], +}; + +export function customPlugin() { + return customPluginConfig; +} +export default customPluginConfig; diff --git a/packages/cli/mocks/fixtures/configs/tsconfig.alias.json b/packages/cli/mocks/fixtures/configs/tsconfig.alias.json new file mode 100644 index 000000000..f7f68cd18 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/tsconfig.alias.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@definitely-non-existent-package/custom-plugin": ["./custom-plugin.ts"] + } + } +} diff --git a/packages/cli/mocks/fixtures/configs/tsconfig.json b/packages/cli/mocks/fixtures/configs/tsconfig.json new file mode 100644 index 000000000..d43aec5e4 --- /dev/null +++ b/packages/cli/mocks/fixtures/configs/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "paths": {} + } +} diff --git a/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts b/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts index 9b37cceb4..e0fa0d567 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts @@ -18,6 +18,16 @@ const configDirPath = path.join( 'configs', ); +const localMocks = path.join( + fileURLToPath(path.dirname(import.meta.url)), + '..', + '..', + '..', + 'mocks', + 'fixtures', + 'configs', +); + describe('coreConfigMiddleware', () => { const CLI_DEFAULTS = { plugins: [], @@ -29,7 +39,7 @@ describe('coreConfigMiddleware', () => { 'should load a valid .%s config', async extension => { const config = await coreConfigMiddleware({ - config: path.join(configDirPath, `code-pushup.config.${extension}`), + config: path.join(localMocks, `code-pushup.config.${extension}`), ...CLI_DEFAULTS, }); expect(config.config).toContain(`code-pushup.config.${extension}`); @@ -46,11 +56,8 @@ describe('coreConfigMiddleware', () => { it('should load config which relies on provided --tsconfig', async () => { await expect( coreConfigMiddleware({ - config: path.join( - configDirPath, - 'code-pushup.needs-tsconfig.config.ts', - ), - tsconfig: path.join(configDirPath, 'tsconfig.json'), + config: path.join(localMocks, 'code-pushup.needs-tsconfig.config.ts'), + tsconfig: path.join(localMocks, 'tsconfig.alias.json'), ...CLI_DEFAULTS, }), ).resolves.toBeTruthy(); @@ -60,11 +67,13 @@ describe('coreConfigMiddleware', () => { await expect( coreConfigMiddleware({ config: path.join( - configDirPath, - 'code-pushup.needs-tsconfig.config.ts', + localMocks, + 'code-pushup.needs-tsconfig-fail.config.ts', ), ...CLI_DEFAULTS, }), - ).rejects.toThrow("Cannot find package '@example/custom-plugin'"); + ).rejects.toThrow( + "Cannot find module '@definitely-non-existent-package/custom-plugin'", + ); }); }); diff --git a/testing/test-fixtures/src/lib/fixtures/configs/code-pushup.needs-tsconfig.config.ts b/testing/test-fixtures/src/lib/fixtures/configs/code-pushup.needs-tsconfig.config.ts index 44b4d0a2d..6ef0e8967 100644 --- a/testing/test-fixtures/src/lib/fixtures/configs/code-pushup.needs-tsconfig.config.ts +++ b/testing/test-fixtures/src/lib/fixtures/configs/code-pushup.needs-tsconfig.config.ts @@ -1,7 +1,7 @@ // the point is to test runtime import which relies on alias defined in tsconfig.json "paths" // non-type import from '@example/custom-plugin' wouldn't work without --tsconfig // eslint-disable-next-line import/no-unresolved -import customPlugin from '@example/custom-plugin'; +import customPlugin from '@definitely-non-existent-package/custom-plugin'; const config = { plugins: [customPlugin], diff --git a/testing/test-fixtures/src/lib/fixtures/configs/tsconfig.json b/testing/test-fixtures/src/lib/fixtures/configs/tsconfig.json index 42976b47b..f7f68cd18 100644 --- a/testing/test-fixtures/src/lib/fixtures/configs/tsconfig.json +++ b/testing/test-fixtures/src/lib/fixtures/configs/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "paths": { - "@example/custom-plugin": ["./custom-plugin.ts"] + "@definitely-non-existent-package/custom-plugin": ["./custom-plugin.ts"] } } } From e477cbcad65ef45c3cb966f9b969f355326d0524 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 02:21:15 +0100 Subject: [PATCH 08/24] refactor: fix unit-test --- .../implementation/read-rc-file.unit.test.ts | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/core/src/lib/implementation/read-rc-file.unit.test.ts b/packages/core/src/lib/implementation/read-rc-file.unit.test.ts index 54387069b..7f051618a 100644 --- a/packages/core/src/lib/implementation/read-rc-file.unit.test.ts +++ b/packages/core/src/lib/implementation/read-rc-file.unit.test.ts @@ -4,32 +4,39 @@ import { CONFIG_FILE_NAME, type CoreConfig } from '@code-pushup/models'; import { MEMFS_VOLUME } from '@code-pushup/test-utils'; import { autoloadRc } from './read-rc-file.js'; -// mock bundleRequire inside importEsmModule used for fetching config -vi.mock('bundle-require', async () => { +// mock jiti used for fetching config +vi.mock('jiti', async () => { const { CORE_CONFIG_MOCK }: Record = await vi.importActual('@code-pushup/test-fixtures'); + const actualJiti = await vi.importActual('jiti'); + return { - bundleRequire: vi - .fn() - .mockImplementation((options: { filepath: string }) => { - const extension = options.filepath.split('.').at(-1); - return { - mod: { - default: { + ...actualJiti, + createJiti: vi.fn().mockImplementation(() => ({ + import: vi + .fn() + .mockImplementation( + (filepath: string, options: { default?: boolean }) => { + const extension = filepath.split('.').at(-1); + const config = { ...CORE_CONFIG_MOCK, upload: { ...CORE_CONFIG_MOCK?.upload, project: extension, // returns loaded file extension to check format precedence }, - }, + }; + + // When default: true is passed, return the config directly + // Otherwise return { default: config } + return options?.default ? config : { default: config }; }, - }; - }), + ), + })), }; }); -// Note: memfs files are only listed to satisfy a system check, value is used from bundle-require mock +// Note: memfs files are only listed to satisfy a system check, value is used from jiti mock describe('autoloadRc', () => { it('prioritise a .ts configuration file', async () => { vol.fromJSON( From 81fd996dcea35c967e13a349e312ba4b6388e483 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 02:27:58 +0100 Subject: [PATCH 09/24] refactor: fix unit-test --- .../implementation/read-rc-file.unit.test.ts | 39 +++--- .../src/lib/nx/coverage-paths.unit.test.ts | 123 +++++++++--------- .../src/lib/runner/utils.unit.test.ts | 20 ++- 3 files changed, 87 insertions(+), 95 deletions(-) diff --git a/packages/core/src/lib/implementation/read-rc-file.unit.test.ts b/packages/core/src/lib/implementation/read-rc-file.unit.test.ts index 7f051618a..5ec8b8861 100644 --- a/packages/core/src/lib/implementation/read-rc-file.unit.test.ts +++ b/packages/core/src/lib/implementation/read-rc-file.unit.test.ts @@ -4,39 +4,30 @@ import { CONFIG_FILE_NAME, type CoreConfig } from '@code-pushup/models'; import { MEMFS_VOLUME } from '@code-pushup/test-utils'; import { autoloadRc } from './read-rc-file.js'; -// mock jiti used for fetching config -vi.mock('jiti', async () => { +vi.mock('@code-pushup/utils', async () => { const { CORE_CONFIG_MOCK }: Record = await vi.importActual('@code-pushup/test-fixtures'); - const actualJiti = await vi.importActual('jiti'); + const actualUtils = await vi.importActual('@code-pushup/utils'); return { - ...actualJiti, - createJiti: vi.fn().mockImplementation(() => ({ - import: vi - .fn() - .mockImplementation( - (filepath: string, options: { default?: boolean }) => { - const extension = filepath.split('.').at(-1); - const config = { - ...CORE_CONFIG_MOCK, - upload: { - ...CORE_CONFIG_MOCK?.upload, - project: extension, // returns loaded file extension to check format precedence - }, - }; - - // When default: true is passed, return the config directly - // Otherwise return { default: config } - return options?.default ? config : { default: config }; + ...actualUtils, + importModule: vi + .fn() + .mockImplementation((options: { filepath: string }) => { + const extension = options.filepath.split('.').at(-1); + return { + ...CORE_CONFIG_MOCK, + upload: { + ...CORE_CONFIG_MOCK?.upload, + project: extension, // returns loaded file extension to check format precedence }, - ), - })), + }; + }), }; }); -// Note: memfs files are only listed to satisfy a system check, value is used from jiti mock +// Note: memfs files are only listed to satisfy a system check, value is used from importModule mock describe('autoloadRc', () => { it('prioritise a .ts configuration file', async () => { vol.fromJSON( diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts index 5bcaaa422..36504f567 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.unit.test.ts @@ -13,74 +13,77 @@ import { getCoveragePathsForTarget, } from './coverage-paths.js'; -vi.mock('bundle-require', () => ({ - bundleRequire: vi.fn().mockImplementation((options: { filepath: string }) => { - const VITEST_VALID: VitestCoverageConfig = { - test: { - coverage: { - reporter: ['lcov'], - reportsDirectory: path.join('coverage', 'cli'), - }, - }, - }; +vi.mock('@code-pushup/utils', async () => { + const actualUtils = await vi.importActual('@code-pushup/utils'); - const VITEST_NO_DIR: VitestCoverageConfig = { - test: { coverage: { reporter: ['lcov'] } }, - }; + return { + ...actualUtils, + importModule: vi + .fn() + .mockImplementation((options: { filepath: string }) => { + const VITEST_VALID: VitestCoverageConfig = { + test: { + coverage: { + reporter: ['lcov'], + reportsDirectory: path.join('coverage', 'cli'), + }, + }, + }; - const VITEST_NO_LCOV: VitestCoverageConfig = { - test: { - coverage: { - reporter: ['json'], - reportsDirectory: 'coverage', - }, - }, - }; + const VITEST_NO_DIR: VitestCoverageConfig = { + test: { coverage: { reporter: ['lcov'] } }, + }; - const JEST_VALID: JestCoverageConfig = { - coverageReporters: ['lcov'], - coverageDirectory: path.join('coverage', 'core'), - }; + const VITEST_NO_LCOV: VitestCoverageConfig = { + test: { + coverage: { + reporter: ['json'], + reportsDirectory: 'coverage', + }, + }, + }; - const JEST_NO_DIR: JestCoverageConfig = { - coverageReporters: ['lcov'], - }; + const JEST_VALID: JestCoverageConfig = { + coverageReporters: ['lcov'], + coverageDirectory: path.join('coverage', 'core'), + }; - const JEST_NO_LCOV: JestCoverageConfig = { - coverageReporters: ['json'], - coverageDirectory: 'coverage', - }; + const JEST_NO_DIR: JestCoverageConfig = { + coverageReporters: ['lcov'], + }; - const JEST_PRESET: JestCoverageConfig & { preset?: string } = { - preset: '../../jest.preset.ts', - coverageDirectory: 'coverage', - }; + const JEST_NO_LCOV: JestCoverageConfig = { + coverageReporters: ['json'], + coverageDirectory: 'coverage', + }; - const wrapReturnValue = ( - value: VitestCoverageConfig | JestCoverageConfig, - ) => ({ mod: { default: value } }); + const JEST_PRESET: JestCoverageConfig & { preset?: string } = { + preset: '../../jest.preset.ts', + coverageDirectory: 'coverage', + }; - const config = options.filepath.split('.')[0]; - switch (config) { - case 'vitest-valid': - return wrapReturnValue(VITEST_VALID); - case 'vitest-no-lcov': - return wrapReturnValue(VITEST_NO_LCOV); - case 'vitest-no-dir': - return wrapReturnValue(VITEST_NO_DIR); - case 'jest-valid': - return wrapReturnValue(JEST_VALID); - case 'jest-no-lcov': - return wrapReturnValue(JEST_NO_LCOV); - case 'jest-no-dir': - return wrapReturnValue(JEST_NO_DIR); - case 'jest-preset': - return wrapReturnValue(JEST_PRESET); - default: - return wrapReturnValue({}); - } - }), -})); + const config = options.filepath.split('.')[0]; + switch (config) { + case 'vitest-valid': + return VITEST_VALID; + case 'vitest-no-lcov': + return VITEST_NO_LCOV; + case 'vitest-no-dir': + return VITEST_NO_DIR; + case 'jest-valid': + return JEST_VALID; + case 'jest-no-lcov': + return JEST_NO_LCOV; + case 'jest-no-dir': + return JEST_NO_DIR; + case 'jest-preset': + return JEST_PRESET; + default: + return {}; + } + }), + }; +}); describe('getCoveragePathForTarget', () => { beforeEach(() => { diff --git a/packages/plugin-lighthouse/src/lib/runner/utils.unit.test.ts b/packages/plugin-lighthouse/src/lib/runner/utils.unit.test.ts index 458efe97d..a914745b2 100644 --- a/packages/plugin-lighthouse/src/lib/runner/utils.unit.test.ts +++ b/packages/plugin-lighthouse/src/lib/runner/utils.unit.test.ts @@ -26,25 +26,23 @@ import { withLocalTmpDir, } from './utils.js'; -// mock bundleRequire inside importEsmModule used for fetching config -vi.mock('bundle-require', async () => { +vi.mock('@code-pushup/utils', async () => { const { CORE_CONFIG_MOCK }: Record = await vi.importActual('@code-pushup/test-utils'); + const actualUtils = await vi.importActual('@code-pushup/utils'); + return { - bundleRequire: vi + ...actualUtils, + importModule: vi .fn() .mockImplementation((options: { filepath: string }) => { const project = options.filepath.split('.').at(-2); return { - mod: { - default: { - ...CORE_CONFIG_MOCK, - upload: { - ...CORE_CONFIG_MOCK?.upload, - project, // returns loaded file extension to check in test - }, - }, + ...CORE_CONFIG_MOCK, + upload: { + ...CORE_CONFIG_MOCK?.upload, + project, // returns loaded file extension to check in test }, }; }), From 23ff44d9740f24487ce01d1ab1434249bf4f5d0e Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 02:41:34 +0100 Subject: [PATCH 10/24] refactor: fix build --- packages/utils/package.json | 2 +- packages/utils/src/lib/import-module.ts | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/utils/package.json b/packages/utils/package.json index 8dee27c95..4af7e2940 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -38,7 +38,7 @@ "wrap-ansi": "^9.0.2", "zod": "^4.2.1", "typescript": "5.7.3", - "jiti": "^2.4.2" + "jiti": "^2.6.1" }, "files": [ "src", diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index d6a3b2f24..c5732f8b5 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -1,4 +1,4 @@ -import { type JitiOptions, createJiti as createJitiSource } from 'jiti'; +import { createJiti as createJitiSource } from 'jiti'; import { stat } from 'node:fs/promises'; import path from 'node:path'; import type { CompilerOptions } from 'typescript'; @@ -6,8 +6,15 @@ import { fileExists } from './file-system.js'; import { loadTargetConfig } from './load-ts-config.js'; import { settlePromise } from './promises.js'; +// For unknown reason, we can't import `JitiOptions` directly in this repository +type JitiOptions = Exclude[1], undefined>; + +export type ImportModuleOptions = JitiOptions & { + filepath: string; + tsconfig?: string; +}; export async function importModule( - options: JitiOptions & { filepath: string; tsconfig?: string }, + options: ImportModuleOptions, ): Promise { const { filepath, tsconfig, ...jitiOptions } = options; @@ -77,12 +84,9 @@ export const mapTsJsxToJitiJsx = (tsJsxMode: number): boolean => * | sourceMaps | boolean | sourceMap | boolean | Enable sourcemap generation. | * | jsx | boolean | jsx | JsxEmit (0-5) | TS JsxEmit enum (0-5) => boolean JSX processing. | */ -export type MappableJitiOptions = Partial<{ - alias: Record; - interopDefault: boolean; - sourceMaps: boolean; - jsx: boolean; -}>; +export type MappableJitiOptions = Partial< + Pick +>; /** * Parse TypeScript compiler options to mappable jiti options * @param compilerOptions TypeScript compiler options From 8447ae20418d4a4601d11879b5599cb33625cc16 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 02:46:51 +0100 Subject: [PATCH 11/24] refactor: fix int-test --- packages/core/src/lib/implementation/read-rc-file.ts | 1 - packages/plugin-coverage/src/lib/nx/coverage-paths.ts | 1 - packages/plugin-lighthouse/src/lib/runner/utils.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/core/src/lib/implementation/read-rc-file.ts b/packages/core/src/lib/implementation/read-rc-file.ts index 090ad2c0e..fb27a0733 100644 --- a/packages/core/src/lib/implementation/read-rc-file.ts +++ b/packages/core/src/lib/implementation/read-rc-file.ts @@ -27,7 +27,6 @@ export async function readRcByPath( const result = await importModule({ filepath: filePath, tsconfig, - format: 'esm', }); return { result, message: `Imported config from ${formattedTarget}` }; }, diff --git a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts index f2a5dd073..638c2d684 100644 --- a/packages/plugin-coverage/src/lib/nx/coverage-paths.ts +++ b/packages/plugin-coverage/src/lib/nx/coverage-paths.ts @@ -165,7 +165,6 @@ export async function getCoveragePathForVitest( const vitestConfig = await importModule({ filepath: config, - format: 'esm', }); const reportsDirectory = diff --git a/packages/plugin-lighthouse/src/lib/runner/utils.ts b/packages/plugin-lighthouse/src/lib/runner/utils.ts index a68ad368e..347c16bb4 100644 --- a/packages/plugin-lighthouse/src/lib/runner/utils.ts +++ b/packages/plugin-lighthouse/src/lib/runner/utils.ts @@ -144,7 +144,6 @@ export async function getConfig( message, result: await importModule({ filepath: configPath, - format: 'esm', }), }; } From 5301aa7b34ec59f8ec3cf6935ab67e66e5f959eb Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 02:50:55 +0100 Subject: [PATCH 12/24] refactor: fix lint --- .../core-config.middleware.int.test.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts b/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts index e0fa0d567..12cb6387e 100644 --- a/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts +++ b/packages/cli/src/lib/implementation/core-config.middleware.int.test.ts @@ -3,21 +3,6 @@ import { fileURLToPath } from 'node:url'; import { describe, expect } from 'vitest'; import { coreConfigMiddleware } from './core-config.middleware.js'; -const configDirPath = path.join( - fileURLToPath(path.dirname(import.meta.url)), - '..', - '..', - '..', - '..', - '..', - 'testing', - 'test-fixtures', - 'src', - 'lib', - 'fixtures', - 'configs', -); - const localMocks = path.join( fileURLToPath(path.dirname(import.meta.url)), '..', From bf7dd0ae35c9b0a0889f3cc757e087567c3ecbb9 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 03:04:23 +0100 Subject: [PATCH 13/24] refactor: fix jiti context --- packages/utils/src/lib/import-module.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index c5732f8b5..0e11191c9 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -18,17 +18,17 @@ export async function importModule( ): Promise { const { filepath, tsconfig, ...jitiOptions } = options; - const resolvedStats = await settlePromise(stat(options.filepath)); + const resolvedStats = await settlePromise(stat(filepath)); if (resolvedStats.status === 'rejected') { - throw new Error(`File '${options.filepath}' does not exist`); + throw new Error(`File '${filepath}' does not exist`); } if (!resolvedStats.value.isFile()) { - throw new Error(`Expected '${options.filepath}' to be a file`); + throw new Error(`Expected '${filepath}' to be a file`); } - const jitiInstance = await createTsJiti(options.filepath, { + const jitiInstance = await createTsJiti(process.cwd(), { ...jitiOptions, - tsconfigPath: options.tsconfig, + tsconfigPath: tsconfig, }); return (await jitiInstance.import(filepath, { default: true })) as T; } From a5319d84b8225fa8b4d24966d11f501b53ab2d6b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 03:27:46 +0100 Subject: [PATCH 14/24] refactor: fix jiti context --- .../utils/src/lib/import-module.int.test.ts | 4 +++- packages/utils/src/lib/import-module.ts | 24 +++++++++++-------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/packages/utils/src/lib/import-module.int.test.ts b/packages/utils/src/lib/import-module.int.test.ts index 1b30500bf..bfbe51934 100644 --- a/packages/utils/src/lib/import-module.int.test.ts +++ b/packages/utils/src/lib/import-module.int.test.ts @@ -67,7 +67,9 @@ describe('importModule', () => { it('should throw if the file does not exist', async () => { await expect( importModule({ filepath: 'path/to/non-existent-export.mjs' }), - ).rejects.toThrow("File 'path/to/non-existent-export.mjs' does not exist"); + ).rejects.toThrow( + `File '${path.resolve('path/to/non-existent-export.mjs')}' does not exist`, + ); }); it('should throw if path is a directory', async () => { diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index 0e11191c9..46ac8359a 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -18,19 +18,21 @@ export async function importModule( ): Promise { const { filepath, tsconfig, ...jitiOptions } = options; - const resolvedStats = await settlePromise(stat(filepath)); + const absoluteFilePath = path.resolve(process.cwd(), filepath); + const resolvedStats = await settlePromise(stat(absoluteFilePath)); if (resolvedStats.status === 'rejected') { - throw new Error(`File '${filepath}' does not exist`); + throw new Error(`File '${absoluteFilePath}' does not exist`); } if (!resolvedStats.value.isFile()) { throw new Error(`Expected '${filepath}' to be a file`); } - const jitiInstance = await createTsJiti(process.cwd(), { + const jitiInstance = await createTsJiti(import.meta.url, { ...jitiOptions, tsconfigPath: tsconfig, }); - return (await jitiInstance.import(filepath, { default: true })) as T; + + return (await jitiInstance.import(absoluteFilePath, { default: true })) as T; } /** @@ -127,29 +129,31 @@ export function parseTsConfigToJitiConfig( /** * Create a jiti instance with options derived from tsconfig. * Used instead of direct jiti.createJiti to allow tsconfig integration. - * @param filepath + * @param id * @param options * @param jiti */ export async function createTsJiti( - filepath: string, - options: JitiOptions & { tsconfigPath?: string }, + id: string, + options: JitiOptions & { tsconfigPath?: string } = {}, createJiti: (typeof import('jiti'))['createJiti'] = createJitiSource, ) { const { tsconfigPath, ...jitiOptions } = options; - const fallbackTsconfigPath = path.resolve('./tsconfig.json'); + + const fallbackTsconfigPath = path.resolve(process.cwd(), 'tsconfig.json'); const validPath: null | string = tsconfigPath == null ? (await fileExists(fallbackTsconfigPath)) ? fallbackTsconfigPath : null - : tsconfigPath; + : path.resolve(process.cwd(), tsconfigPath); const tsDerivedJitiOptions: MappableJitiOptions = validPath ? await jitiOptionsFromTsConfig(validPath) : {}; - return createJiti(filepath, { ...jitiOptions, ...tsDerivedJitiOptions }); + + return createJiti(id, { ...jitiOptions, ...tsDerivedJitiOptions }); } /** From 5a6732818127c9ef4fd4ae28a641277d9e210c7e Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 03:37:50 +0100 Subject: [PATCH 15/24] refactor: fix int test --- .../core/src/lib/implementation/read-rc-file.int.test.ts | 4 +++- packages/utils/src/lib/import-module.ts | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/core/src/lib/implementation/read-rc-file.int.test.ts b/packages/core/src/lib/implementation/read-rc-file.int.test.ts index 006ea0a7a..1631d2948 100644 --- a/packages/core/src/lib/implementation/read-rc-file.int.test.ts +++ b/packages/core/src/lib/implementation/read-rc-file.int.test.ts @@ -55,7 +55,9 @@ describe('readRcByPath', () => { }); it('should throw if the path is empty', async () => { - await expect(readRcByPath('')).rejects.toThrow("File '' does not exist"); + await expect(readRcByPath('')).rejects.toThrow( + "Importing module failed. File '' does not exist", + ); }); it('should throw if the file does not exist', async () => { diff --git a/packages/utils/src/lib/import-module.ts b/packages/utils/src/lib/import-module.ts index 46ac8359a..326f63fa8 100644 --- a/packages/utils/src/lib/import-module.ts +++ b/packages/utils/src/lib/import-module.ts @@ -18,6 +18,12 @@ export async function importModule( ): Promise { const { filepath, tsconfig, ...jitiOptions } = options; + if (!filepath) { + throw new Error( + `Importing module failed. File '${filepath}' does not exist`, + ); + } + const absoluteFilePath = path.resolve(process.cwd(), filepath); const resolvedStats = await settlePromise(stat(absoluteFilePath)); if (resolvedStats.status === 'rejected') { From 11c493b32392f4e2a4b23014595814be06e11a17 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 03:49:36 +0100 Subject: [PATCH 16/24] refactor: fix e2e test --- e2e/cli-e2e/tests/print-config.e2e.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/cli-e2e/tests/print-config.e2e.test.ts b/e2e/cli-e2e/tests/print-config.e2e.test.ts index 630d3bb2a..60d03704e 100644 --- a/e2e/cli-e2e/tests/print-config.e2e.test.ts +++ b/e2e/cli-e2e/tests/print-config.e2e.test.ts @@ -47,7 +47,7 @@ describe('CLI print-config', () => { 'print-config', '--output=config.json', `--config=${configFilePath(ext)}`, - '--tsconfig=tsconfig.base.json', + `--tsconfig=${path.join(process.cwd(), 'tsconfig.base.json')}`, '--persist.outputDir=output-dir', '--persist.format=md', `--persist.filename=${ext}-report`, From 1b679b80c06ff25b0e7f3755b633c1dff51dc52c Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 04:18:39 +0100 Subject: [PATCH 17/24] refactor: move mocks --- .../src/0-no-diagnostics/constants.ts | 1 + .../basic-setup/tsconfig.extends-base.json | 7 ++ .../tsconfig.extends-extending.json | 8 ++ .../fixtures/basic-setup/tsconfig.init.json | 103 ++++++++++++++++++ .../utils/src/lib/load-ts-config.int.test.ts | 4 +- 5 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 packages/utils/mocks/fixtures/basic-setup/src/0-no-diagnostics/constants.ts create mode 100644 packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-base.json create mode 100644 packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-extending.json create mode 100644 packages/utils/mocks/fixtures/basic-setup/tsconfig.init.json diff --git a/packages/utils/mocks/fixtures/basic-setup/src/0-no-diagnostics/constants.ts b/packages/utils/mocks/fixtures/basic-setup/src/0-no-diagnostics/constants.ts new file mode 100644 index 000000000..9cbbe8809 --- /dev/null +++ b/packages/utils/mocks/fixtures/basic-setup/src/0-no-diagnostics/constants.ts @@ -0,0 +1 @@ +export const TEST = 'test'; diff --git a/packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-base.json b/packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-base.json new file mode 100644 index 000000000..d98091ca6 --- /dev/null +++ b/packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-base.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "rootDir": "${configDir}", + "verbatimModuleSyntax": false + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-extending.json b/packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-extending.json new file mode 100644 index 000000000..f1b970c13 --- /dev/null +++ b/packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-extending.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.extends-base.json", + "compilerOptions": { + "verbatimModuleSyntax": true, + "module": "CommonJS" + }, + "exclude": ["src/*-errors/**/*.ts"] +} diff --git a/packages/utils/mocks/fixtures/basic-setup/tsconfig.init.json b/packages/utils/mocks/fixtures/basic-setup/tsconfig.init.json new file mode 100644 index 000000000..ba648354a --- /dev/null +++ b/packages/utils/mocks/fixtures/basic-setup/tsconfig.init.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/packages/utils/src/lib/load-ts-config.int.test.ts b/packages/utils/src/lib/load-ts-config.int.test.ts index c8f326e58..fd4bc5842 100644 --- a/packages/utils/src/lib/load-ts-config.int.test.ts +++ b/packages/utils/src/lib/load-ts-config.int.test.ts @@ -14,7 +14,7 @@ describe('loadTargetConfig', () => { expect( loadTargetConfig( osAgnosticPath( - 'packages/plugin-typescript/mocks/fixtures/basic-setup/tsconfig.init.json', + 'packages/utils/mocks/fixtures/basic-setup/tsconfig.init.json', ), ), ).toStrictEqual( @@ -42,7 +42,7 @@ describe('loadTargetConfig', () => { it('should return the parsed content of a tsconfig file that extends another config', () => { expect( loadTargetConfig( - 'packages/plugin-typescript/mocks/fixtures/basic-setup/tsconfig.extends-extending.json', + 'packages/utils/mocks/fixtures/basic-setup/tsconfig.extends-extending.json', ), ).toStrictEqual( expect.objectContaining({ From 933daf1cb36621d36af4580b63ce5cfb6498613f Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 04:18:57 +0100 Subject: [PATCH 18/24] refactor: adjust path resolution --- e2e/cli-e2e/tests/print-config.e2e.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/cli-e2e/tests/print-config.e2e.test.ts b/e2e/cli-e2e/tests/print-config.e2e.test.ts index 60d03704e..5cb346701 100644 --- a/e2e/cli-e2e/tests/print-config.e2e.test.ts +++ b/e2e/cli-e2e/tests/print-config.e2e.test.ts @@ -64,7 +64,7 @@ describe('CLI print-config', () => { expect(JSON.parse(output)).toEqual( expect.objectContaining({ config: expect.stringContaining(`code-pushup.config.${ext}`), - tsconfig: 'tsconfig.base.json', + tsconfig: path.join(process.cwd(), 'tsconfig.base.json'), plugins: [ expect.objectContaining({ slug: 'dummy-plugin', From 1a51ca9944464cd708b50091af9b75e34fa69c7c Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 07:10:59 +0100 Subject: [PATCH 19/24] refactor: fix axe --- packages/plugin-axe/src/lib/meta/transform.ts | 1 + packages/plugin-axe/src/lib/polyfills.dom.ts | 81 +++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 packages/plugin-axe/src/lib/polyfills.dom.ts diff --git a/packages/plugin-axe/src/lib/meta/transform.ts b/packages/plugin-axe/src/lib/meta/transform.ts index f4e8ad03e..8429c793c 100644 --- a/packages/plugin-axe/src/lib/meta/transform.ts +++ b/packages/plugin-axe/src/lib/meta/transform.ts @@ -7,6 +7,7 @@ import { CATEGORY_GROUPS, getWcagPresetTags, } from '../groups.js'; +import '../polyfills.dom.js'; /** Loads Axe rules filtered by the specified preset. */ export function loadAxeRules(preset: AxePreset): axe.RuleMetadata[] { diff --git a/packages/plugin-axe/src/lib/polyfills.dom.ts b/packages/plugin-axe/src/lib/polyfills.dom.ts new file mode 100644 index 000000000..285f1bc4e --- /dev/null +++ b/packages/plugin-axe/src/lib/polyfills.dom.ts @@ -0,0 +1,81 @@ +// Polyfills for axe-core DOM access in Node.js environment +// This must be imported before any axe-core imports + +if (typeof global.window === 'undefined') { + const mockElement = { + style: {}, + addEventListener: () => {}, + removeEventListener: () => {}, + appendChild: () => {}, + setAttribute: () => {}, + getAttribute: () => null, + textContent: '', + innerHTML: '', + className: '', + id: '', + tagName: 'DIV', + parentNode: null, + childNodes: [], + firstChild: null, + lastChild: null, + nextSibling: null, + previousSibling: null, + ownerDocument: null, + }; + + // Mock document + const mockDocument = { + createElement: tagName => ({ + ...mockElement, + tagName: tagName.toUpperCase(), + }), + createElementNS: (ns, tagName) => ({ + ...mockElement, + tagName: tagName.toUpperCase(), + }), + createTextNode: text => ({ ...mockElement, textContent: text }), + body: { ...mockElement, tagName: 'BODY' }, + documentElement: { ...mockElement, tagName: 'HTML' }, + head: { ...mockElement, tagName: 'HEAD' }, + addEventListener: () => {}, + removeEventListener: () => {}, + querySelector: () => null, + querySelectorAll: () => [], + getElementById: () => null, + getElementsByTagName: () => [mockElement], + getElementsByClassName: () => [], + createDocumentFragment: () => ({}), + createComment: () => ({}), + implementation: { + createHTMLDocument: () => mockDocument, + }, + }; + + // Set up global objects + global.window = global; + global.document = mockDocument; + + // Only set navigator if it doesn't exist or isn't read-only + try { + if (typeof global.navigator === 'undefined') { + global.navigator = { + userAgent: 'Node.js', + platform: 'Node.js', + appVersion: 'Node.js', + }; + } + } catch (e) { + // navigator is read-only, skip setting it + } + + // Also set on globalThis for consistency + globalThis.window = global.window; + globalThis.document = global.document; + try { + if (typeof globalThis.navigator === 'undefined') { + globalThis.navigator = global.navigator; + } + } catch (e) { + // navigator is read-only, skip setting it + } +} From 51106e9eae13b3254a87ed19734dfdcf1ddf8c4f Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 08:10:47 +0100 Subject: [PATCH 20/24] refactor: fix eslint --- e2e/ci-e2e/eslint.config.js | 6 +- e2e/cli-e2e/eslint.config.js | 6 +- e2e/create-cli-e2e/eslint.config.js | 6 +- e2e/nx-plugin-e2e/eslint.config.js | 6 +- e2e/plugin-axe-e2e/eslint.config.js | 6 +- e2e/plugin-coverage-e2e/eslint.config.js | 6 +- e2e/plugin-eslint-e2e/eslint.config.js | 6 +- e2e/plugin-js-packages-e2e/eslint.config.js | 6 +- e2e/plugin-jsdocs-e2e/eslint.config.js | 6 +- e2e/plugin-lighthouse-e2e/eslint.config.js | 6 +- e2e/plugin-typescript-e2e/eslint.config.js | 6 +- eslint.config.js | 325 +++++++++--------- examples/plugins/eslint.config.js | 6 +- nx.json | 7 +- package-lock.json | 17 +- package.json | 2 +- packages/ci/eslint.config.js | 6 +- packages/cli/eslint.config.js | 6 +- packages/core/eslint.config.js | 6 +- packages/create-cli/eslint.config.js | 6 +- packages/models/eslint.config.js | 6 +- packages/nx-plugin/eslint.config.js | 96 +++--- packages/plugin-axe/eslint.config.js | 6 +- packages/plugin-axe/src/index.ts | 1 + packages/plugin-axe/src/lib/meta/transform.ts | 1 - packages/plugin-coverage/eslint.config.js | 6 +- packages/plugin-eslint/eslint.config.js | 6 +- packages/plugin-js-packages/eslint.config.js | 6 +- packages/plugin-jsdocs/eslint.config.js | 6 +- packages/plugin-lighthouse/eslint.config.js | 6 +- packages/plugin-typescript/eslint.config.js | 6 +- packages/utils/eslint.config.js | 6 +- project.json | 10 + testing/test-fixtures/eslint.config.js | 6 +- testing/test-nx-utils/eslint.config.js | 6 +- testing/test-setup-config/eslint.config.js | 6 +- testing/test-setup/eslint.config.js | 6 +- testing/test-utils/eslint.config.js | 6 +- tools/eslint-formatter-multi/eslint.config.js | 6 +- tools/zod2md-jsdocs/eslint.config.js | 22 +- 40 files changed, 407 insertions(+), 260 deletions(-) diff --git a/e2e/ci-e2e/eslint.config.js b/e2e/ci-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/ci-e2e/eslint.config.js +++ b/e2e/ci-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/cli-e2e/eslint.config.js b/e2e/cli-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/cli-e2e/eslint.config.js +++ b/e2e/cli-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/create-cli-e2e/eslint.config.js b/e2e/create-cli-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/create-cli-e2e/eslint.config.js +++ b/e2e/create-cli-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/nx-plugin-e2e/eslint.config.js b/e2e/nx-plugin-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/nx-plugin-e2e/eslint.config.js +++ b/e2e/nx-plugin-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-axe-e2e/eslint.config.js b/e2e/plugin-axe-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-axe-e2e/eslint.config.js +++ b/e2e/plugin-axe-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-coverage-e2e/eslint.config.js b/e2e/plugin-coverage-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-coverage-e2e/eslint.config.js +++ b/e2e/plugin-coverage-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-eslint-e2e/eslint.config.js b/e2e/plugin-eslint-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-eslint-e2e/eslint.config.js +++ b/e2e/plugin-eslint-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-js-packages-e2e/eslint.config.js b/e2e/plugin-js-packages-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-js-packages-e2e/eslint.config.js +++ b/e2e/plugin-js-packages-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-jsdocs-e2e/eslint.config.js b/e2e/plugin-jsdocs-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-jsdocs-e2e/eslint.config.js +++ b/e2e/plugin-jsdocs-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-lighthouse-e2e/eslint.config.js b/e2e/plugin-lighthouse-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-lighthouse-e2e/eslint.config.js +++ b/e2e/plugin-lighthouse-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/e2e/plugin-typescript-e2e/eslint.config.js b/e2e/plugin-typescript-e2e/eslint.config.js index 2656b27cb..57069812e 100644 --- a/e2e/plugin-typescript-e2e/eslint.config.js +++ b/e2e/plugin-typescript-e2e/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/eslint.config.js b/eslint.config.js index 7397d95d0..ad54c05d0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -5,176 +5,183 @@ import fs from 'node:fs'; import tseslint from 'typescript-eslint'; import node from '@code-pushup/eslint-config/node.js'; import typescript from '@code-pushup/eslint-config/typescript.js'; -import vitest from '@code-pushup/eslint-config/vitest.js'; -export default tseslint.config( - ...typescript, - ...node, - ...vitest, - { - settings: { - 'import/resolver': { typescript: { project: 'tsconfig.base.json' } }, +export default async () => { + const { default: vitest } = await import( + '@code-pushup/eslint-config/vitest.js' + ); + + const vitestConfig = typeof vitest === 'function' ? await vitest() : vitest; + + return tseslint.config( + ...typescript, + ...node, + ...vitestConfig, + { + settings: { + 'import/resolver': { typescript: { project: 'tsconfig.base.json' } }, + }, }, - }, - { plugins: { '@nx': nxEslintPlugin } }, - { - files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], - rules: { - '@nx/enforce-module-boundaries': [ - 'error', - { - enforceBuildableLibDependency: true, - allow: [ - String.raw`^.*/eslint(\.base)?\.config\.[cm]?js$`, - String.raw`^.*/code-pushup\.(config|preset)(\.m?[jt]s)?$`, - '^[./]+/tools/.*$', - String.raw`^[./]+/(testing/)?test-setup-config/src/index\.js$`, - ], - depConstraints: [ - { - sourceTag: 'scope:shared', - onlyDependOnLibsWithTags: ['scope:shared'], - }, - { - sourceTag: 'scope:core', - onlyDependOnLibsWithTags: ['scope:core', 'scope:shared'], - }, - { - sourceTag: 'scope:plugin', - onlyDependOnLibsWithTags: ['scope:shared'], - }, - { - sourceTag: 'scope:tooling', - onlyDependOnLibsWithTags: ['scope:tooling', 'scope:shared'], - }, - { - sourceTag: 'type:e2e', - onlyDependOnLibsWithTags: [ - 'type:app', - 'type:feature', - 'type:util', - 'type:testing', - ], - }, - { - sourceTag: 'type:app', - onlyDependOnLibsWithTags: [ - 'type:feature', - 'type:util', - 'type:testing', - ], - }, - { - sourceTag: 'type:feature', - onlyDependOnLibsWithTags: [ - 'type:feature', - 'type:util', - 'type:testing', - ], - }, - { - sourceTag: 'type:util', - onlyDependOnLibsWithTags: ['type:util', 'type:testing'], - }, - { - sourceTag: 'type:testing', - onlyDependOnLibsWithTags: ['type:util', 'type:testing'], - }, - ], - }, - ], + { plugins: { '@nx': nxEslintPlugin } }, + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: [ + String.raw`^.*/eslint(\.base)?\.config\.[cm]?js$`, + String.raw`^.*/code-pushup\.(config|preset)(\.m?[jt]s)?$`, + '^[./]+/tools/.*$', + String.raw`^[./]+/(testing/)?test-setup-config/src/index\.js$`, + ], + depConstraints: [ + { + sourceTag: 'scope:shared', + onlyDependOnLibsWithTags: ['scope:shared'], + }, + { + sourceTag: 'scope:core', + onlyDependOnLibsWithTags: ['scope:core', 'scope:shared'], + }, + { + sourceTag: 'scope:plugin', + onlyDependOnLibsWithTags: ['scope:shared'], + }, + { + sourceTag: 'scope:tooling', + onlyDependOnLibsWithTags: ['scope:tooling', 'scope:shared'], + }, + { + sourceTag: 'type:e2e', + onlyDependOnLibsWithTags: [ + 'type:app', + 'type:feature', + 'type:util', + 'type:testing', + ], + }, + { + sourceTag: 'type:app', + onlyDependOnLibsWithTags: [ + 'type:feature', + 'type:util', + 'type:testing', + ], + }, + { + sourceTag: 'type:feature', + onlyDependOnLibsWithTags: [ + 'type:feature', + 'type:util', + 'type:testing', + ], + }, + { + sourceTag: 'type:util', + onlyDependOnLibsWithTags: ['type:util', 'type:testing'], + }, + { + sourceTag: 'type:testing', + onlyDependOnLibsWithTags: ['type:util', 'type:testing'], + }, + ], + }, + ], + }, }, - }, - { - files: ['**/*.test.ts', '**/*.spec.ts'], - plugins: { 'jest-extended': jestExtendedPlugin }, - rules: { - 'vitest/consistent-test-filename': [ - 'warn', - { - pattern: String.raw`.*\.(bench|type|unit|int|e2e)\.test\.[tj]sx?$`, - }, - ], - 'jest-extended/prefer-to-be-array': 'warn', - 'jest-extended/prefer-to-be-false': 'warn', - 'jest-extended/prefer-to-be-object': 'warn', - 'jest-extended/prefer-to-be-true': 'warn', - 'jest-extended/prefer-to-have-been-called-once': 'warn', + { + files: ['**/*.test.ts', '**/*.spec.ts'], + plugins: { 'jest-extended': jestExtendedPlugin }, + rules: { + 'vitest/consistent-test-filename': [ + 'warn', + { + pattern: String.raw`.*\.(bench|type|unit|int|e2e)\.test\.[tj]sx?$`, + }, + ], + 'jest-extended/prefer-to-be-array': 'warn', + 'jest-extended/prefer-to-be-false': 'warn', + 'jest-extended/prefer-to-be-object': 'warn', + 'jest-extended/prefer-to-be-true': 'warn', + 'jest-extended/prefer-to-have-been-called-once': 'warn', + }, }, - }, - { - files: ['**/*.type.test.ts'], - rules: { - 'vitest/expect-expect': 'off', + { + files: ['**/*.type.test.ts'], + rules: { + 'vitest/expect-expect': 'off', + }, }, - }, - { - files: ['**/*.json'], - languageOptions: { parser: jsoncParser }, - }, - { - files: ['**/*.ts', '**/*.js'], - rules: { - 'n/file-extension-in-import': ['error', 'always'], - 'unicorn/number-literal-case': 'off', + { + files: ['**/*.json'], + languageOptions: { parser: jsoncParser }, }, - }, - { - files: ['**/perf/**/*.ts'], - rules: { - '@typescript-eslint/no-magic-numbers': 'off', - 'sonarjs/no-duplicate-string': 'off', + { + files: ['**/*.ts', '**/*.js'], + rules: { + 'n/file-extension-in-import': ['error', 'always'], + 'unicorn/number-literal-case': 'off', + }, }, - }, - { - // tests need only be compatible with local Node version - // publishable packages should pick up version range from "engines" in their package.json - files: ['e2e/**/*.ts', 'testing/**/*.ts', '**/*.test.ts'], - settings: { - node: { - version: fs.readFileSync('.node-version', 'utf8'), + { + files: ['**/perf/**/*.ts'], + rules: { + '@typescript-eslint/no-magic-numbers': 'off', + 'sonarjs/no-duplicate-string': 'off', }, }, - }, - { - ignores: [ - '**/*.mock.*', - '**/code-pushup.config.ts', - '**/mocks/fixtures/**', - '**/__snapshots__/**', - '**/dist', - '**/*.md', - ], - }, - { - files: ['packages/**/*.ts'], - rules: { - 'no-restricted-imports': [ - 'error', - { - paths: [ - { - name: '@nx/devkit', - importNames: ['logger'], - message: 'Please use logger from @code-pushup/utils instead.', - }, - ], + { + // tests need only be compatible with local Node version + // publishable packages should pick up version range from "engines" in their package.json + files: ['e2e/**/*.ts', 'testing/**/*.ts', '**/*.test.ts'], + settings: { + node: { + version: fs.readFileSync('.node-version', 'utf8'), }, + }, + }, + { + ignores: [ + '**/*.mock.*', + '**/code-pushup.config.ts', + '**/mocks/fixtures/**', + '**/__snapshots__/**', + '**/dist', + '**/*.md', ], }, - }, - { - // in bin files, imports with side effects are allowed - files: ['**/bin/**/*.ts', '**/bin/**/*.js'], - rules: { - 'import/no-unassigned-import': 'off', + { + files: ['packages/**/*.ts'], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: '@nx/devkit', + importNames: ['logger'], + message: 'Please use logger from @code-pushup/utils instead.', + }, + ], + }, + ], + }, + }, + { + // in bin files, imports with side effects are allowed + files: ['**/bin/**/*.ts', '**/bin/**/*.js'], + rules: { + 'import/no-unassigned-import': 'off', + }, }, - }, - { - // in *nx-plugin.ts files path imports cant be default export style (@TODO understand relation to swc) - files: ['**/*nx-plugin.ts'], - rules: { - 'unicorn/import-style': 'off', + { + // in *nx-plugin.ts files path imports cant be default export style (@TODO understand relation to swc) + files: ['**/*nx-plugin.ts'], + rules: { + 'unicorn/import-style': 'off', + }, }, - }, -); + ); +}; diff --git a/examples/plugins/eslint.config.js b/examples/plugins/eslint.config.js index 2656b27cb..57069812e 100644 --- a/examples/plugins/eslint.config.js +++ b/examples/plugins/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/nx.json b/nx.json index 7e7265dfe..64fa582c5 100644 --- a/nx.json +++ b/nx.json @@ -38,7 +38,6 @@ ], "code-pushup-inputs": [ "{workspaceRoot}/code-pushup.preset.ts", - { "env": "NODE_OPTIONS" }, { "env": "TSX_TSCONFIG_PATH" } ], "sharedGlobals": [{ "runtime": "node -v" }, { "runtime": "npm -v" }] @@ -127,15 +126,15 @@ "executor": "nx:run-commands", "dependsOn": ["code-pushup-*"], "options": { - "command": "node packages/cli/src/index.ts", + "command": "npx @push-based/jiti-tsc packages/cli/src/index.ts", "args": [ "--config={projectRoot}/code-pushup.config.ts", "--cache.read", "--persist.outputDir=.code-pushup/{projectName}" ], "env": { - "NODE_OPTIONS": "--import tsx", - "TSX_TSCONFIG_PATH": "tsconfig.base.json" + "JITI_TSCONFIG_PATH": "tsconfig.base.json", + "JITI_DEBUG": "0" } } }, diff --git a/package-lock.json b/package-lock.json index 72b15fa39..5ac2d5be1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,7 +54,7 @@ "@nx/react": "22.3.3", "@nx/vite": "22.3.3", "@nx/workspace": "22.3.3", - "@push-based/jiti-tsc": "^0.0.2", + "@push-based/jiti-tsc": "^0.1.1", "@push-based/nx-verdaccio": "0.0.7", "@swc-node/register": "1.9.2", "@swc/cli": "0.6.0", @@ -6328,26 +6328,21 @@ } }, "node_modules/@push-based/jiti-tsc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@push-based/jiti-tsc/-/jiti-tsc-0.0.2.tgz", - "integrity": "sha512-9K8IYbZePUzPHDkA6tuOukFcJT6xu6bbFtWaws0CtVsmQaeqyRrKuSYFMl73OIee7oOXUOZS2QMIZp3ky6sh/g==", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@push-based/jiti-tsc/-/jiti-tsc-0.1.1.tgz", + "integrity": "sha512-2pi6jyxwr0DMFbsmgosfTUh1AEDWScyw97/KnTAfrKf9q33abtoqRHqF69+MJYex9O2Vlq8gye0XTkEy6dCPFA==", "dev": true, "license": "MIT", "dependencies": { - "ansis": "^3.3.2", "jiti": "^2.4.2", - "ora": "^9.0.0", - "tslib": "^2.8.1", + "tslib": "^2.6.2", "typescript": "5.7.3" }, "bin": { - "jiti-tsc": "src/bin/bin.js" + "jiti-tsc": "src/cli.js" }, "engines": { "node": ">=20.0.0" - }, - "peerDependencies": { - "zod": "^4.0.0" } }, "node_modules/@push-based/nx-verdaccio": { diff --git a/package.json b/package.json index c4455978d..969d24982 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "@nx/react": "22.3.3", "@nx/vite": "22.3.3", "@nx/workspace": "22.3.3", - "@push-based/jiti-tsc": "^0.0.2", + "@push-based/jiti-tsc": "^0.1.1", "@push-based/nx-verdaccio": "0.0.7", "@swc-node/register": "1.9.2", "@swc/cli": "0.6.0", diff --git a/packages/ci/eslint.config.js b/packages/ci/eslint.config.js index 13888c2a8..57f083758 100644 --- a/packages/ci/eslint.config.js +++ b/packages/ci/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/cli/eslint.config.js b/packages/cli/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/cli/eslint.config.js +++ b/packages/cli/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/core/eslint.config.js b/packages/core/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/core/eslint.config.js +++ b/packages/core/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/create-cli/eslint.config.js b/packages/create-cli/eslint.config.js index 22fda2e40..9bf249f2c 100644 --- a/packages/create-cli/eslint.config.js +++ b/packages/create-cli/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/models/eslint.config.js b/packages/models/eslint.config.js index 48fd0b2be..f8da0d4cd 100644 --- a/packages/models/eslint.config.js +++ b/packages/models/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['/**/*.ts'], languageOptions: { diff --git a/packages/nx-plugin/eslint.config.js b/packages/nx-plugin/eslint.config.js index f0ea93505..2b6994dc4 100644 --- a/packages/nx-plugin/eslint.config.js +++ b/packages/nx-plugin/eslint.config.js @@ -1,53 +1,59 @@ const tseslint = require('typescript-eslint'); const baseConfig = require('../../eslint.config.js').default; -module.exports = tseslint.config( - ...baseConfig, - { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: __dirname, +module.exports = (async () => { + const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + + return tseslint.config( + ...resolvedBaseConfig, + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: __dirname, + }, }, }, - }, - { - files: ['**/*.ts'], - rules: { - // Nx plugins don't yet support ESM: https://github.com/nrwl/nx/issues/15682 - 'unicorn/prefer-module': 'off', - // used instead of verbatimModuleSyntax tsconfig flag (requires ESM) - '@typescript-eslint/consistent-type-imports': [ - 'warn', - { - fixStyle: 'inline-type-imports', - disallowTypeAnnotations: false, - }, - ], - '@typescript-eslint/consistent-type-exports': [ - 'warn', - { fixMixedExportsWithInlineTypeSpecifier: true }, - ], - // `import path from 'node:path'` incompatible with CJS runtime, prefer `import * as path from 'node:path'` - 'unicorn/import-style': [ - 'warn', - { styles: { 'node:path': { namespace: true } } }, - ], - // `import { logger } from '@nx/devkit' is OK here - 'no-restricted-imports': 'off', + { + files: ['**/*.ts'], + rules: { + // Nx plugins don't yet support ESM: https://github.com/nrwl/nx/issues/15682 + 'unicorn/prefer-module': 'off', + // used instead of verbatimModuleSyntax tsconfig flag (requires ESM) + '@typescript-eslint/consistent-type-imports': [ + 'warn', + { + fixStyle: 'inline-type-imports', + disallowTypeAnnotations: false, + }, + ], + '@typescript-eslint/consistent-type-exports': [ + 'warn', + { fixMixedExportsWithInlineTypeSpecifier: true }, + ], + // `import path from 'node:path'` incompatible with CJS runtime, prefer `import * as path from 'node:path'` + 'unicorn/import-style': [ + 'warn', + { styles: { 'node:path': { namespace: true } } }, + ], + // `import { logger } from '@nx/devkit' is OK here + 'no-restricted-imports': 'off', + }, }, - }, - { - files: ['**/*.json'], - rules: { - '@nx/dependency-checks': 'error', + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': 'error', + }, }, - }, - { - files: ['**/package.json', '**/generators.json'], - rules: { - '@nx/nx-plugin-checks': 'error', + { + files: ['**/package.json', '**/generators.json'], + rules: { + '@nx/nx-plugin-checks': 'error', + }, }, - }, -); + ); +})(); diff --git a/packages/plugin-axe/eslint.config.js b/packages/plugin-axe/eslint.config.js index 2656b27cb..57069812e 100644 --- a/packages/plugin-axe/eslint.config.js +++ b/packages/plugin-axe/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/packages/plugin-axe/src/index.ts b/packages/plugin-axe/src/index.ts index fc6a6c5b6..1c724a283 100644 --- a/packages/plugin-axe/src/index.ts +++ b/packages/plugin-axe/src/index.ts @@ -1,4 +1,5 @@ import { axePlugin } from './lib/axe-plugin.js'; +import './lib/polyfills.dom.js'; export default axePlugin; diff --git a/packages/plugin-axe/src/lib/meta/transform.ts b/packages/plugin-axe/src/lib/meta/transform.ts index 8429c793c..f4e8ad03e 100644 --- a/packages/plugin-axe/src/lib/meta/transform.ts +++ b/packages/plugin-axe/src/lib/meta/transform.ts @@ -7,7 +7,6 @@ import { CATEGORY_GROUPS, getWcagPresetTags, } from '../groups.js'; -import '../polyfills.dom.js'; /** Loads Axe rules filtered by the specified preset. */ export function loadAxeRules(preset: AxePreset): axe.RuleMetadata[] { diff --git a/packages/plugin-coverage/eslint.config.js b/packages/plugin-coverage/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/plugin-coverage/eslint.config.js +++ b/packages/plugin-coverage/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-eslint/eslint.config.js b/packages/plugin-eslint/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/plugin-eslint/eslint.config.js +++ b/packages/plugin-eslint/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-js-packages/eslint.config.js b/packages/plugin-js-packages/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/plugin-js-packages/eslint.config.js +++ b/packages/plugin-js-packages/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-jsdocs/eslint.config.js b/packages/plugin-jsdocs/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/plugin-jsdocs/eslint.config.js +++ b/packages/plugin-jsdocs/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-lighthouse/eslint.config.js b/packages/plugin-lighthouse/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/plugin-lighthouse/eslint.config.js +++ b/packages/plugin-lighthouse/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-typescript/eslint.config.js b/packages/plugin-typescript/eslint.config.js index 40165321a..5fc1041b1 100644 --- a/packages/plugin-typescript/eslint.config.js +++ b/packages/plugin-typescript/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/packages/utils/eslint.config.js b/packages/utils/eslint.config.js index 1ad01224a..3877c6503 100644 --- a/packages/utils/eslint.config.js +++ b/packages/utils/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/project.json b/project.json index 48e03fd94..c40f924ce 100644 --- a/project.json +++ b/project.json @@ -2,6 +2,16 @@ "name": "workspace", "$schema": "node_modules/nx/schemas/project-schema.json", "targets": { + "jiti-test": { + "executor": "nx:run-commands", + "options": { + "command": "node -e \"console.log('Testing jiti path aliases:'); console.log('NODE_OPTIONS:', process.env.NODE_OPTIONS); console.log('JITI_TSCONFIG_PATH:', process.env.JITI_TSCONFIG_PATH); console.log('Testing import of @push-based/jiti-tsc...'); try { require('@push-based/jiti-tsc'); console.log('✓ jiti-tsc imported successfully'); } catch (e) { console.log('✗ Failed to import jiti-tsc:', e.message); }\"", + "env": { + "NODE_OPTIONS": "--import @push-based/jiti-tsc", + "JITI_TSCONFIG_PATH": "tsconfig.base.json" + } + } + }, "code-pushup": { "dependsOn": [], "options": { diff --git a/testing/test-fixtures/eslint.config.js b/testing/test-fixtures/eslint.config.js index 2656b27cb..57069812e 100644 --- a/testing/test-fixtures/eslint.config.js +++ b/testing/test-fixtures/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/testing/test-nx-utils/eslint.config.js b/testing/test-nx-utils/eslint.config.js index 2656b27cb..57069812e 100644 --- a/testing/test-nx-utils/eslint.config.js +++ b/testing/test-nx-utils/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/testing/test-setup-config/eslint.config.js b/testing/test-setup-config/eslint.config.js index 2656b27cb..57069812e 100644 --- a/testing/test-setup-config/eslint.config.js +++ b/testing/test-setup-config/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/testing/test-setup/eslint.config.js b/testing/test-setup/eslint.config.js index 2656b27cb..57069812e 100644 --- a/testing/test-setup/eslint.config.js +++ b/testing/test-setup/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/testing/test-utils/eslint.config.js b/testing/test-utils/eslint.config.js index 2656b27cb..57069812e 100644 --- a/testing/test-utils/eslint.config.js +++ b/testing/test-utils/eslint.config.js @@ -1,7 +1,11 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -export default tseslint.config(...baseConfig, { +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + +export default tseslint.config(...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { parserOptions: { diff --git a/tools/eslint-formatter-multi/eslint.config.js b/tools/eslint-formatter-multi/eslint.config.js index 29bda515b..9a8020157 100644 --- a/tools/eslint-formatter-multi/eslint.config.js +++ b/tools/eslint-formatter-multi/eslint.config.js @@ -1,8 +1,12 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; +const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + export default tseslint.config( - ...baseConfig, + ...resolvedBaseConfig, { files: ['**/*.ts'], languageOptions: { diff --git a/tools/zod2md-jsdocs/eslint.config.js b/tools/zod2md-jsdocs/eslint.config.js index 467b6c94b..8c16b0290 100644 --- a/tools/zod2md-jsdocs/eslint.config.js +++ b/tools/zod2md-jsdocs/eslint.config.js @@ -1,11 +1,17 @@ const baseConfig = require('../../eslint.config.js').default; -module.exports = [ - ...baseConfig, - { - files: ['**/*.json'], - rules: { - '@nx/dependency-checks': 'error', +module.exports = (async () => { + const resolvedBaseConfig = await (typeof baseConfig === 'function' + ? baseConfig() + : baseConfig); + + return [ + ...resolvedBaseConfig, + { + files: ['**/*.json'], + rules: { + '@nx/dependency-checks': 'error', + }, }, - }, -]; + ]; +})(); From 7c3341b283d31e7b9db3c48e03d8cd77a9a8c952 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 08:21:20 +0100 Subject: [PATCH 21/24] refactor: fix eslint --- e2e/ci-e2e/eslint.config.js | 21 +++++++++---------- e2e/cli-e2e/eslint.config.js | 21 +++++++++---------- e2e/create-cli-e2e/eslint.config.js | 21 +++++++++---------- e2e/nx-plugin-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-axe-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-coverage-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-eslint-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-js-packages-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-jsdocs-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-lighthouse-e2e/eslint.config.js | 21 +++++++++---------- e2e/plugin-typescript-e2e/eslint.config.js | 21 +++++++++---------- examples/plugins/eslint.config.js | 21 +++++++++---------- packages/ci/eslint.config.js | 6 +----- packages/cli/eslint.config.js | 6 +----- packages/core/eslint.config.js | 6 +----- packages/create-cli/eslint.config.js | 6 +----- packages/models/eslint.config.js | 6 +----- packages/nx-plugin/eslint.config.js | 6 +----- packages/plugin-axe/eslint.config.js | 21 +++++++++---------- packages/plugin-axe/src/index.ts | 1 + packages/plugin-coverage/eslint.config.js | 6 +----- packages/plugin-eslint/eslint.config.js | 6 +----- packages/plugin-js-packages/eslint.config.js | 6 +----- packages/plugin-jsdocs/eslint.config.js | 6 +----- packages/plugin-lighthouse/eslint.config.js | 6 +----- packages/plugin-typescript/eslint.config.js | 6 +----- packages/utils/eslint.config.js | 6 +----- testing/test-fixtures/eslint.config.js | 21 +++++++++---------- testing/test-nx-utils/eslint.config.js | 21 +++++++++---------- testing/test-setup-config/eslint.config.js | 21 +++++++++---------- testing/test-setup/eslint.config.js | 21 +++++++++---------- testing/test-utils/eslint.config.js | 21 +++++++++---------- tools/eslint-formatter-multi/eslint.config.js | 6 +----- tools/zod2md-jsdocs/eslint.config.js | 6 +----- 34 files changed, 196 insertions(+), 273 deletions(-) diff --git a/e2e/ci-e2e/eslint.config.js b/e2e/ci-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/ci-e2e/eslint.config.js +++ b/e2e/ci-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/cli-e2e/eslint.config.js b/e2e/cli-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/cli-e2e/eslint.config.js +++ b/e2e/cli-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/create-cli-e2e/eslint.config.js b/e2e/create-cli-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/create-cli-e2e/eslint.config.js +++ b/e2e/create-cli-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/nx-plugin-e2e/eslint.config.js b/e2e/nx-plugin-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/nx-plugin-e2e/eslint.config.js +++ b/e2e/nx-plugin-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-axe-e2e/eslint.config.js b/e2e/plugin-axe-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-axe-e2e/eslint.config.js +++ b/e2e/plugin-axe-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-coverage-e2e/eslint.config.js b/e2e/plugin-coverage-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-coverage-e2e/eslint.config.js +++ b/e2e/plugin-coverage-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-eslint-e2e/eslint.config.js b/e2e/plugin-eslint-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-eslint-e2e/eslint.config.js +++ b/e2e/plugin-eslint-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-js-packages-e2e/eslint.config.js b/e2e/plugin-js-packages-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-js-packages-e2e/eslint.config.js +++ b/e2e/plugin-js-packages-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-jsdocs-e2e/eslint.config.js b/e2e/plugin-jsdocs-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-jsdocs-e2e/eslint.config.js +++ b/e2e/plugin-jsdocs-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-lighthouse-e2e/eslint.config.js b/e2e/plugin-lighthouse-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-lighthouse-e2e/eslint.config.js +++ b/e2e/plugin-lighthouse-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/e2e/plugin-typescript-e2e/eslint.config.js b/e2e/plugin-typescript-e2e/eslint.config.js index 57069812e..05c619c08 100644 --- a/e2e/plugin-typescript-e2e/eslint.config.js +++ b/e2e/plugin-typescript-e2e/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/examples/plugins/eslint.config.js b/examples/plugins/eslint.config.js index 57069812e..05c619c08 100644 --- a/examples/plugins/eslint.config.js +++ b/examples/plugins/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/packages/ci/eslint.config.js b/packages/ci/eslint.config.js index 57f083758..8af358cd9 100644 --- a/packages/ci/eslint.config.js +++ b/packages/ci/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/cli/eslint.config.js b/packages/cli/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/cli/eslint.config.js +++ b/packages/cli/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/core/eslint.config.js b/packages/core/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/core/eslint.config.js +++ b/packages/core/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/create-cli/eslint.config.js b/packages/create-cli/eslint.config.js index 9bf249f2c..72617ff9a 100644 --- a/packages/create-cli/eslint.config.js +++ b/packages/create-cli/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/models/eslint.config.js b/packages/models/eslint.config.js index f8da0d4cd..602a07662 100644 --- a/packages/models/eslint.config.js +++ b/packages/models/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['/**/*.ts'], languageOptions: { diff --git a/packages/nx-plugin/eslint.config.js b/packages/nx-plugin/eslint.config.js index 2b6994dc4..b46dc4e22 100644 --- a/packages/nx-plugin/eslint.config.js +++ b/packages/nx-plugin/eslint.config.js @@ -2,12 +2,8 @@ const tseslint = require('typescript-eslint'); const baseConfig = require('../../eslint.config.js').default; module.exports = (async () => { - const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - return tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-axe/eslint.config.js b/packages/plugin-axe/eslint.config.js index 57069812e..05c619c08 100644 --- a/packages/plugin-axe/eslint.config.js +++ b/packages/plugin-axe/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/packages/plugin-axe/src/index.ts b/packages/plugin-axe/src/index.ts index 1c724a283..6c0c3c439 100644 --- a/packages/plugin-axe/src/index.ts +++ b/packages/plugin-axe/src/index.ts @@ -1,4 +1,5 @@ import { axePlugin } from './lib/axe-plugin.js'; +import './lib/polyfills.dom'; import './lib/polyfills.dom.js'; export default axePlugin; diff --git a/packages/plugin-coverage/eslint.config.js b/packages/plugin-coverage/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/plugin-coverage/eslint.config.js +++ b/packages/plugin-coverage/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-eslint/eslint.config.js b/packages/plugin-eslint/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/plugin-eslint/eslint.config.js +++ b/packages/plugin-eslint/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-js-packages/eslint.config.js b/packages/plugin-js-packages/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/plugin-js-packages/eslint.config.js +++ b/packages/plugin-js-packages/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-jsdocs/eslint.config.js b/packages/plugin-jsdocs/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/plugin-jsdocs/eslint.config.js +++ b/packages/plugin-jsdocs/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-lighthouse/eslint.config.js b/packages/plugin-lighthouse/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/plugin-lighthouse/eslint.config.js +++ b/packages/plugin-lighthouse/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/plugin-typescript/eslint.config.js b/packages/plugin-typescript/eslint.config.js index 5fc1041b1..ca61d55f3 100644 --- a/packages/plugin-typescript/eslint.config.js +++ b/packages/plugin-typescript/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/packages/utils/eslint.config.js b/packages/utils/eslint.config.js index 3877c6503..702cfae12 100644 --- a/packages/utils/eslint.config.js +++ b/packages/utils/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/testing/test-fixtures/eslint.config.js b/testing/test-fixtures/eslint.config.js index 57069812e..05c619c08 100644 --- a/testing/test-fixtures/eslint.config.js +++ b/testing/test-fixtures/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/testing/test-nx-utils/eslint.config.js b/testing/test-nx-utils/eslint.config.js index 57069812e..05c619c08 100644 --- a/testing/test-nx-utils/eslint.config.js +++ b/testing/test-nx-utils/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/testing/test-setup-config/eslint.config.js b/testing/test-setup-config/eslint.config.js index 57069812e..05c619c08 100644 --- a/testing/test-setup-config/eslint.config.js +++ b/testing/test-setup-config/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/testing/test-setup/eslint.config.js b/testing/test-setup/eslint.config.js index 57069812e..05c619c08 100644 --- a/testing/test-setup/eslint.config.js +++ b/testing/test-setup/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/testing/test-utils/eslint.config.js b/testing/test-utils/eslint.config.js index 57069812e..05c619c08 100644 --- a/testing/test-utils/eslint.config.js +++ b/testing/test-utils/eslint.config.js @@ -1,16 +1,15 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - -export default tseslint.config(...resolvedBaseConfig, { - files: ['**/*.ts'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, +export default tseslint.config( + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), + { + files: ['**/*.ts'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, }, }, -}); +); diff --git a/tools/eslint-formatter-multi/eslint.config.js b/tools/eslint-formatter-multi/eslint.config.js index 9a8020157..0779f9a35 100644 --- a/tools/eslint-formatter-multi/eslint.config.js +++ b/tools/eslint-formatter-multi/eslint.config.js @@ -1,12 +1,8 @@ import tseslint from 'typescript-eslint'; import baseConfig from '../../eslint.config.js'; -const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - export default tseslint.config( - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.ts'], languageOptions: { diff --git a/tools/zod2md-jsdocs/eslint.config.js b/tools/zod2md-jsdocs/eslint.config.js index 8c16b0290..5eee51048 100644 --- a/tools/zod2md-jsdocs/eslint.config.js +++ b/tools/zod2md-jsdocs/eslint.config.js @@ -1,12 +1,8 @@ const baseConfig = require('../../eslint.config.js').default; module.exports = (async () => { - const resolvedBaseConfig = await (typeof baseConfig === 'function' - ? baseConfig() - : baseConfig); - return [ - ...resolvedBaseConfig, + ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), { files: ['**/*.json'], rules: { From 03ff1f26d67aedf03b75371e4b336a6a644ddee4 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 08:49:03 +0100 Subject: [PATCH 22/24] refactor: fix axe --- packages/plugin-axe/src/_index.ts | 12 ++++++++++++ packages/plugin-axe/src/index.ts | 12 +----------- 2 files changed, 13 insertions(+), 11 deletions(-) create mode 100644 packages/plugin-axe/src/_index.ts diff --git a/packages/plugin-axe/src/_index.ts b/packages/plugin-axe/src/_index.ts new file mode 100644 index 000000000..de44ccb07 --- /dev/null +++ b/packages/plugin-axe/src/_index.ts @@ -0,0 +1,12 @@ +export { axePlugin } from './lib/axe-plugin.js'; + +export type { AxePluginOptions, AxePreset } from './lib/config.js'; +export type { AxeGroupSlug } from './lib/groups.js'; + +export { + axeAuditRef, + axeAuditRefs, + axeGroupRef, + axeGroupRefs, +} from './lib/utils.js'; +export { axeCategories } from './lib/categories.js'; diff --git a/packages/plugin-axe/src/index.ts b/packages/plugin-axe/src/index.ts index 6c0c3c439..4071af50b 100644 --- a/packages/plugin-axe/src/index.ts +++ b/packages/plugin-axe/src/index.ts @@ -1,16 +1,6 @@ import { axePlugin } from './lib/axe-plugin.js'; -import './lib/polyfills.dom'; import './lib/polyfills.dom.js'; export default axePlugin; -export type { AxePluginOptions, AxePreset } from './lib/config.js'; -export type { AxeGroupSlug } from './lib/groups.js'; - -export { - axeAuditRef, - axeAuditRefs, - axeGroupRef, - axeGroupRefs, -} from './lib/utils.js'; -export { axeCategories } from './lib/categories.js'; +export * from './_index.js'; From 481b5364b5bb687dd98e5b46e5a36d9dde936f1b Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 08:52:11 +0100 Subject: [PATCH 23/24] refactor: fix import order --- packages/plugin-axe/src/index.ts | 2 +- .../plugin-axe/src/lib/{polyfills.dom.ts => _polyfills.dom.ts} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/plugin-axe/src/lib/{polyfills.dom.ts => _polyfills.dom.ts} (100%) diff --git a/packages/plugin-axe/src/index.ts b/packages/plugin-axe/src/index.ts index 4071af50b..f45d40ece 100644 --- a/packages/plugin-axe/src/index.ts +++ b/packages/plugin-axe/src/index.ts @@ -1,5 +1,5 @@ +import './lib/_polyfills.dom.js'; import { axePlugin } from './lib/axe-plugin.js'; -import './lib/polyfills.dom.js'; export default axePlugin; diff --git a/packages/plugin-axe/src/lib/polyfills.dom.ts b/packages/plugin-axe/src/lib/_polyfills.dom.ts similarity index 100% rename from packages/plugin-axe/src/lib/polyfills.dom.ts rename to packages/plugin-axe/src/lib/_polyfills.dom.ts From d5125c330d58039b2fb4866da69d1c1c9cd6bbd5 Mon Sep 17 00:00:00 2001 From: Michael Hladky Date: Fri, 23 Jan 2026 09:05:28 +0100 Subject: [PATCH 24/24] refactor: fix lint --- packages/nx-plugin/eslint.config.js | 1 + packages/plugin-axe/src/index.ts | 1 + packages/plugin-axe/src/lib/_polyfills.dom.ts | 23 ++++++++++--------- tools/zod2md-jsdocs/eslint.config.js | 1 + 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/nx-plugin/eslint.config.js b/packages/nx-plugin/eslint.config.js index b46dc4e22..73bd854a1 100644 --- a/packages/nx-plugin/eslint.config.js +++ b/packages/nx-plugin/eslint.config.js @@ -1,6 +1,7 @@ const tseslint = require('typescript-eslint'); const baseConfig = require('../../eslint.config.js').default; +// eslint-disable-next-line unicorn/prefer-top-level-await, arrow-body-style module.exports = (async () => { return tseslint.config( ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)), diff --git a/packages/plugin-axe/src/index.ts b/packages/plugin-axe/src/index.ts index f45d40ece..ad8199791 100644 --- a/packages/plugin-axe/src/index.ts +++ b/packages/plugin-axe/src/index.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line import/no-unassigned-import import './lib/_polyfills.dom.js'; import { axePlugin } from './lib/axe-plugin.js'; diff --git a/packages/plugin-axe/src/lib/_polyfills.dom.ts b/packages/plugin-axe/src/lib/_polyfills.dom.ts index 285f1bc4e..f6e2b0a8a 100644 --- a/packages/plugin-axe/src/lib/_polyfills.dom.ts +++ b/packages/plugin-axe/src/lib/_polyfills.dom.ts @@ -1,6 +1,7 @@ // Polyfills for axe-core DOM access in Node.js environment // This must be imported before any axe-core imports +/* eslint-disable functional/immutable-data, @typescript-eslint/no-explicit-any, unicorn/prefer-global-this, n/no-unsupported-features/node-builtins, unicorn/no-typeof-undefined, @typescript-eslint/no-empty-function */ if (typeof global.window === 'undefined') { const mockElement = { style: {}, @@ -25,15 +26,15 @@ if (typeof global.window === 'undefined') { // Mock document const mockDocument = { - createElement: tagName => ({ + createElement: (tagName: string) => ({ ...mockElement, tagName: tagName.toUpperCase(), }), - createElementNS: (ns, tagName) => ({ + createElementNS: (_ns: string, tagName: string) => ({ ...mockElement, tagName: tagName.toUpperCase(), }), - createTextNode: text => ({ ...mockElement, textContent: text }), + createTextNode: (text: string) => ({ ...mockElement, textContent: text }), body: { ...mockElement, tagName: 'BODY' }, documentElement: { ...mockElement, tagName: 'HTML' }, head: { ...mockElement, tagName: 'HEAD' }, @@ -52,30 +53,30 @@ if (typeof global.window === 'undefined') { }; // Set up global objects - global.window = global; - global.document = mockDocument; + (global as any).window = global; + (global as any).document = mockDocument; // Only set navigator if it doesn't exist or isn't read-only try { if (typeof global.navigator === 'undefined') { - global.navigator = { + (global as any).navigator = { userAgent: 'Node.js', platform: 'Node.js', appVersion: 'Node.js', }; } - } catch (e) { + } catch { // navigator is read-only, skip setting it } // Also set on globalThis for consistency - globalThis.window = global.window; - globalThis.document = global.document; + (globalThis as any).window = (global as any).window; + (globalThis as any).document = (global as any).document; try { if (typeof globalThis.navigator === 'undefined') { - globalThis.navigator = global.navigator; + (globalThis as any).navigator = (global as any).navigator; } - } catch (e) { + } catch { // navigator is read-only, skip setting it } } diff --git a/tools/zod2md-jsdocs/eslint.config.js b/tools/zod2md-jsdocs/eslint.config.js index 5eee51048..4bfdd9419 100644 --- a/tools/zod2md-jsdocs/eslint.config.js +++ b/tools/zod2md-jsdocs/eslint.config.js @@ -1,5 +1,6 @@ const baseConfig = require('../../eslint.config.js').default; +// eslint-disable-next-line unicorn/prefer-top-level-await, arrow-body-style module.exports = (async () => { return [ ...(await (typeof baseConfig === 'function' ? baseConfig() : baseConfig)),