From 87bf6c9bdc594ce8cd735ca91077fa02f4578e55 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Wed, 13 Mar 2024 00:26:03 +0100 Subject: [PATCH] refactor: Manually resolve remaining ESLint errors and correct autofixes --- .../metadataProvider/createMetadataInfo.ts | 2 +- scripts/metadataProvider/model.ts | 1 + src/cli.ts | 2 +- src/cli/base.ts | 33 +++++++---- src/cli/middlewares/base.ts | 7 +-- src/cli/middlewares/logger.ts | 2 +- src/cli/utils/profile.ts | 3 +- .../amd/moduleDeclarationToDefinition.ts | 3 +- .../transpilers/amd/parseModuleDeclaration.ts | 5 +- .../transpilers/amd/replaceNodeInParent.ts | 2 +- .../amd/requireExpressionToTransformation.ts | 3 +- src/detectors/transpilers/xml/Parser.ts | 2 +- .../transpilers/xml/generator/Writer.ts | 2 +- src/detectors/transpilers/xml/transpiler.ts | 5 +- src/detectors/typeChecker/FileLinter.ts | 7 ++- src/detectors/typeChecker/host.ts | 10 +++- src/detectors/typeChecker/index.ts | 4 +- src/formatter/coverage.ts | 2 +- src/formatter/lib/resolveLinks.ts | 4 +- src/formatter/text.ts | 2 +- src/linter/json/ManifestLinter.ts | 13 +++-- src/linter/linter.ts | 4 +- src/untyped.d.ts | 55 ++++++++----------- test/lib/cli.ts | 11 ++-- test/lib/cli/base.integration.ts | 6 +- test/lib/cli/base.ts | 6 +- .../transpilers/amd/parseModuleDeclaration.ts | 24 ++++---- .../detectors/transpilers/amd/transpiler.ts | 2 +- test/lib/formatter/json.ts | 4 +- test/lib/formatter/lib/resolveLinks.ts | 2 +- test/lib/linter/_linterHelper.ts | 10 +++- test/lib/linter/linter.ts | 6 +- 32 files changed, 134 insertions(+), 110 deletions(-) diff --git a/scripts/metadataProvider/createMetadataInfo.ts b/scripts/metadataProvider/createMetadataInfo.ts index 49a396f4d..bee943810 100644 --- a/scripts/metadataProvider/createMetadataInfo.ts +++ b/scripts/metadataProvider/createMetadataInfo.ts @@ -1,5 +1,5 @@ import {writeFile} from "node:fs/promises"; -import MetadataProvider from "./MetadataProvider"; +import MetadataProvider from "./MetadataProvider.js"; import { forEachSymbol, diff --git a/scripts/metadataProvider/model.ts b/scripts/metadataProvider/model.ts index 742bdac58..ad50f7c00 100644 --- a/scripts/metadataProvider/model.ts +++ b/scripts/metadataProvider/model.ts @@ -67,6 +67,7 @@ export async function createSemanticModel(apiJsonsRoot: string): Promise {}; } model = generate({ diff --git a/src/cli.ts b/src/cli.ts index 5a2c1c7b0..5587b9ba2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -34,5 +34,5 @@ export default async function () { // await cli.parse(); // yargs registers a get method on the argv property. // The property needs to be accessed to initialize everything. - cli.argv; + await cli.argv; } diff --git a/src/cli/base.ts b/src/cli/base.ts index 4e3b0e642..0b71a20d5 100644 --- a/src/cli/base.ts +++ b/src/cli/base.ts @@ -1,4 +1,4 @@ -import {Argv, ArgumentsCamelCase} from "yargs"; +import {Argv, ArgumentsCamelCase, CommandModule, MiddlewareFunction} from "yargs"; import path from "node:path"; import {lintProject} from "../linter/linter.js"; import {Text} from "../formatter/text.js"; @@ -10,13 +10,25 @@ import chalk from "chalk"; import {isLogLevelEnabled} from "@ui5/logger"; import ConsoleWriter from "@ui5/logger/writers/Console"; -const lintCommand = { +export interface LinterArg { + coverage: boolean; + filePaths: string[]; + details: boolean; + format: string; +} + +// yargs type defition is missing the "middelwares" property for the CommandModule type +interface FixedCommandModule extends CommandModule { + middlewares: MiddlewareFunction[]; +} + +const lintCommand: FixedCommandModule = { command: "$0", describe: "Runs linter", handler: handleLint, middlewares: [baseMiddleware], - builder: function (cli: Argv) { - cli.usage("Usage: $0 [options]") + builder: function (args: Argv): Argv { + args.usage("Usage: $0 [options]") .option("file-paths", { describe: "", type: "string", @@ -62,7 +74,7 @@ const lintCommand = { .coerce([ // base.js "log-level", - ], (arg) => { + ], (arg: LinterArg[]) => { // If an option is specified multiple times, yargs creates an array for all the values, // independently of whether the option is of type "array" or "string". // This is unexpected for options listed above, which should all only have only one @@ -74,6 +86,7 @@ const lintCommand = { // Note: This is not necessary for options of type "boolean" if (Array.isArray(arg)) { // If the option is specified multiple times, use the value of the last option + // eslint-disable-next-line @typescript-eslint/no-unsafe-return return arg[arg.length - 1]; } return arg; @@ -83,17 +96,17 @@ const lintCommand = { .example("ui5lint --file-paths /path/to/resources", "Execute command with scope of file-paths"); - return cli; + return args as Argv; }, }; -async function handleLint(argv: ArgumentsCamelCase) { +async function handleLint(argv: ArgumentsCamelCase) { const { coverage, filePaths, details, format, - } = (argv as unknown) as {coverage: boolean; filePaths: string[]; details: boolean; format: string}; + } = argv; let profile; if (process.env.UI5LINT_PROFILE) { @@ -103,10 +116,10 @@ async function handleLint(argv: ArgumentsCamelCase) { const res = await lintProject({ rootDir: path.join(process.cwd()), - filePaths: filePaths && filePaths.map((filePath) => path.resolve(process.cwd(), filePath)), + filePaths: filePaths?.map((filePath) => path.resolve(process.cwd(), filePath)), }); - if (process.env.UI5LINT_COVERAGE_REPORT || coverage) { + if (process.env.UI5LINT_COVERAGE_REPORT ?? coverage) { const coverageFormatter = new Coverage(); await writeFile("ui5lint-report.html", await coverageFormatter.format(res)); } diff --git a/src/cli/middlewares/base.ts b/src/cli/middlewares/base.ts index b86276238..6bb8121e3 100644 --- a/src/cli/middlewares/base.ts +++ b/src/cli/middlewares/base.ts @@ -1,14 +1,11 @@ import {initLogger} from "./logger.js"; import type {ArgumentsCamelCase} from "yargs"; +import type {LinterArg} from "../base.ts"; /** * Base middleware for CLI commands. * * This middleware should be executed for every CLI command to enable basic features (e.g. logging). - * - * @param {object} argv The CLI arguments - * @returns {object} */ -export default async function (argv: ArgumentsCamelCase) { +export default async function (argv: ArgumentsCamelCase) { await initLogger(argv); - return {}; } diff --git a/src/cli/middlewares/logger.ts b/src/cli/middlewares/logger.ts index 140c2750f..d910cc72b 100644 --- a/src/cli/middlewares/logger.ts +++ b/src/cli/middlewares/logger.ts @@ -5,8 +5,8 @@ import type {ArgumentsCamelCase} from "yargs"; /** * Logger middleware to enable logging capabilities * - * @param {object} argv logger arguments */ +// eslint-disable-next-line @typescript-eslint/require-await export async function initLogger(argv: ArgumentsCamelCase) { if (argv.silent) { setLogLevel("silent"); diff --git a/src/cli/utils/profile.ts b/src/cli/utils/profile.ts index c99ec3930..96be30860 100644 --- a/src/cli/utils/profile.ts +++ b/src/cli/utils/profile.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */ import {writeFile} from "node:fs/promises"; import {Session, Profiler} from "node:inspector"; import {getLogger} from "@ui5/logger"; @@ -72,7 +73,7 @@ function registerSigHooks() { function createListener(exitCode: number) { return function () { // Gracefully end profiling, then exit - stop().then(() => { + void stop().then(() => { process.exit(exitCode); }); }; diff --git a/src/detectors/transpilers/amd/moduleDeclarationToDefinition.ts b/src/detectors/transpilers/amd/moduleDeclarationToDefinition.ts index bd8f7e88f..ac995a552 100644 --- a/src/detectors/transpilers/amd/moduleDeclarationToDefinition.ts +++ b/src/detectors/transpilers/amd/moduleDeclarationToDefinition.ts @@ -83,7 +83,8 @@ function collectImports( moduleSpecifier = nodeFactory.createStringLiteral(dep.text); // Set pos to the original position to preserve source mapping capability // (cast type to avoid TS error due to modifying a read only property) - (moduleSpecifier.pos) = dep.pos; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + (moduleSpecifier.pos as ts.Node["pos"]) = dep.pos; } else { moduleSpecifier = dep; } diff --git a/src/detectors/transpilers/amd/parseModuleDeclaration.ts b/src/detectors/transpilers/amd/parseModuleDeclaration.ts index 0ccf2d662..756077e88 100644 --- a/src/detectors/transpilers/amd/parseModuleDeclaration.ts +++ b/src/detectors/transpilers/amd/parseModuleDeclaration.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */ import ts from "typescript"; import {getLogger} from "@ui5/logger"; import {UnsupportedModuleError} from "./util.js"; @@ -109,7 +110,7 @@ function assertSupportedTypes(args: (ts.Expression | ts.Declaration)[]): DefineC const enum Param { ModuleName = 0, - Dependencies = 1, + Dependencies = 1, Factory = 2, Export = 3, } @@ -201,7 +202,7 @@ export function _matchArgumentsToParameters(args: DefineCallArgument[]): ModuleD // Compute which parameters the given argument could match with based on it's type // For example an ArrayLiteralExpression could only be the dependencies or the factory parameter function permute(arg: DefineCallArgument, startAt: Param): number[] { - const perm = Array(4).fill(0); + const perm = Array(4).fill(0) as number[]; if (startAt <= Param.ModuleName && canBeModuleName(arg)) { perm[0] = 1; diff --git a/src/detectors/transpilers/amd/replaceNodeInParent.ts b/src/detectors/transpilers/amd/replaceNodeInParent.ts index 17d6043f9..f17a11697 100644 --- a/src/detectors/transpilers/amd/replaceNodeInParent.ts +++ b/src/detectors/transpilers/amd/replaceNodeInParent.ts @@ -368,7 +368,7 @@ function replaceInPropertyDeclaration( node, node.modifiers, node.name, - node.questionToken || node.exclamationToken, + node.questionToken ?? node.exclamationToken, node.type, substitute); } diff --git a/src/detectors/transpilers/amd/requireExpressionToTransformation.ts b/src/detectors/transpilers/amd/requireExpressionToTransformation.ts index bd887aa50..68b4868ec 100644 --- a/src/detectors/transpilers/amd/requireExpressionToTransformation.ts +++ b/src/detectors/transpilers/amd/requireExpressionToTransformation.ts @@ -56,7 +56,8 @@ export function transformAsyncRequireCall( moduleSpecifier = nodeFactory.createStringLiteral(dep.text); // Set pos to the original position to preserve source mapping capability // (cast type to avoid TS error due to modifying a read only property) - (moduleSpecifier.pos) = dep.pos; + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + (moduleSpecifier.pos as ts.Node["pos"]) = dep.pos; } else { moduleSpecifier = dep; } diff --git a/src/detectors/transpilers/xml/Parser.ts b/src/detectors/transpilers/xml/Parser.ts index 92fce349c..9d4a8ffe2 100644 --- a/src/detectors/transpilers/xml/Parser.ts +++ b/src/detectors/transpilers/xml/Parser.ts @@ -542,7 +542,7 @@ export default class Parser { start: toPosition(tag.openStart), end: toPosition(tag.openEnd), }; - if (customDataElements && customDataElements.length) { + if (customDataElements?.length) { node.aggregations.set("customData", { kind: NodeKind.Aggregation, name: "customData", diff --git a/src/detectors/transpilers/xml/generator/Writer.ts b/src/detectors/transpilers/xml/generator/Writer.ts index 440609de5..cdd15a822 100644 --- a/src/detectors/transpilers/xml/generator/Writer.ts +++ b/src/detectors/transpilers/xml/generator/Writer.ts @@ -112,7 +112,7 @@ export default class Writer { #addMapping(sourcePos: Position, targetPos?: Position) { this.#mappings.add({ - generated: targetPos || { + generated: targetPos ?? { line: this.lineOffset, column: this.columnOffset, }, diff --git a/src/detectors/transpilers/xml/transpiler.ts b/src/detectors/transpilers/xml/transpiler.ts index 5207c8239..08ce7bab7 100644 --- a/src/detectors/transpilers/xml/transpiler.ts +++ b/src/detectors/transpilers/xml/transpiler.ts @@ -45,6 +45,7 @@ export async function xmlToJs(resourceName: string, contentStream: ReadStream): let initializing: Promise; async function init() { + // eslint-disable-next-line @typescript-eslint/no-misused-promises if (initializing) { return initializing; } @@ -55,9 +56,9 @@ async function init() { return initializing = Promise.all([ fs.readFile(saxPath), fs.readFile(new URL("../../../../resources/api-extract.json", import.meta.url), {encoding: "utf-8"}), - ]).then(async (results) => { + ]).then((results) => { saxWasmBuffer = results[0]; - apiExtract = JSON.parse(results[1]); + apiExtract = JSON.parse(results[1]) as ApiExtract; taskEnd(); }); } diff --git a/src/detectors/typeChecker/FileLinter.ts b/src/detectors/typeChecker/FileLinter.ts index 7e387a7ba..bd01018f6 100644 --- a/src/detectors/typeChecker/FileLinter.ts +++ b/src/detectors/typeChecker/FileLinter.ts @@ -20,6 +20,7 @@ export default class FileLinter { this.#boundVisitNode = this.visitNode.bind(this); } + // eslint-disable-next-line @typescript-eslint/require-await async getReport(): Promise { try { this.visitNode(this.#sourceFile); @@ -96,7 +97,7 @@ export default class FileLinter { node: prop, severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-deprecated-api", - message: `Use of deprecated property '${propertySymbol.escapedName}' ` + + message: `Use of deprecated property '${propertySymbol.escapedName as string}' ` + `of class '${this.#checker.typeToString(nodeType)}'`, messageDetails: this.extractDeprecatedMessage(propertySymbol), }); @@ -196,7 +197,7 @@ export default class FileLinter { ruleId: "ui5-linter-no-deprecated-api", message: `Call to deprecated function ` + - `'${symbol.escapedName}'${additionalMessage}`, + `'${symbol.escapedName as string}'${additionalMessage}`, messageDetails: this.extractDeprecatedMessage(symbol), }); } @@ -234,7 +235,7 @@ export default class FileLinter { ruleId: "ui5-linter-no-deprecated-property", message: `Access of deprecated property ` + - `'${symbol.escapedName}'`, + `'${symbol.escapedName as string}'`, messageDetails: this.extractDeprecatedMessage(symbol), }); } diff --git a/src/detectors/typeChecker/host.ts b/src/detectors/typeChecker/host.ts index c208c811d..3b54d8e7b 100644 --- a/src/detectors/typeChecker/host.ts +++ b/src/detectors/typeChecker/host.ts @@ -4,6 +4,10 @@ import posixPath from "node:path/posix"; import {fileURLToPath} from "node:url"; import fs from "node:fs/promises"; +interface PackageJson { + dependencies: Record; +} + function notImplemented(methodName: string) { throw new Error(`Not implemented: ${methodName}`); } @@ -15,7 +19,7 @@ function addPathMappingForPackage(pkgName: string, pathMapping: Map): Promise> { const pkgJsonPath = fileURLToPath(import.meta.resolve(`${pkgName}/package.json`)); - const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, "utf8")); + const pkgJson = JSON.parse(await fs.readFile(pkgJsonPath, "utf8")) as PackageJson; if (pkgJson.dependencies) { await Promise.all(Object.keys(pkgJson.dependencies).map(async (depName) => { deps.add(depName); @@ -137,7 +141,7 @@ export async function createVirtualCompilerHost( } return false; }, - getCurrentDirectory: () => options.rootDir || "/", + getCurrentDirectory: () => options.rootDir ?? "/", // eslint-disable-next-line @typescript-eslint/no-unused-vars getDirectories: (directory: string) => { // This function seems to be called only if the "types" option is not set @@ -152,7 +156,7 @@ export async function createVirtualCompilerHost( // This function doesn't seem to be called during normal operations // console.log(`readDirectory: ${dirPath}`); return Array.from(files.keys()).filter((filePath) => { - if (include || exclude || depth || extensions) { + if (include ?? exclude ?? depth ?? extensions) { notImplemented("readDirectory: Optional parameters"); } return posixPath.dirname(filePath) === dirPath; diff --git a/src/detectors/typeChecker/index.ts b/src/detectors/typeChecker/index.ts index 030f1994c..1bb94a0c0 100644 --- a/src/detectors/typeChecker/index.ts +++ b/src/detectors/typeChecker/index.ts @@ -105,7 +105,7 @@ export class TsProjectDetector extends ProjectBasedDetector { try { if (resourcePath.endsWith(".xml")) { resourcePath = resourcePath.replace(/\.xml$/, ".js"); - const resourceContent = await resource.getStream(); + const resourceContent = resource.getStream(); ({source, map, messages} = await xmlToJs(path.basename(originalResourcePath), resourceContent)); } else if (resourcePath.endsWith(".js")) { @@ -193,7 +193,7 @@ export class TsProjectDetector extends ProjectBasedDetector { (and check the resulting path is within the projectPath) */ let resourcePaths: (string | undefined)[]; - if (filePaths && filePaths.length) { + if (filePaths?.length) { const absoluteFilePaths = filePaths.map((filePath) => { if (!path.isAbsolute(filePath)) { // Resolve relative filePaths diff --git a/src/formatter/coverage.ts b/src/formatter/coverage.ts index df67899c3..3021d3eaa 100644 --- a/src/formatter/coverage.ts +++ b/src/formatter/coverage.ts @@ -17,7 +17,7 @@ function formatSeverity(severity: LintMessageSeverity) { } else if (severity === LintMessageSeverity.Warning) { return "warning"; } else { - throw new Error(`Unknown severity: ${severity}`); + throw new Error(`Unknown severity: ${LintMessageSeverity[severity]}`); } } diff --git a/src/formatter/lib/resolveLinks.ts b/src/formatter/lib/resolveLinks.ts index cce436d05..0444bb314 100644 --- a/src/formatter/lib/resolveLinks.ts +++ b/src/formatter/lib/resolveLinks.ts @@ -23,7 +23,7 @@ function JSDocUtil(): /(
)|(<\/pre>)|()|(<\/h[\d+]>)|\{@link\s+([^}\s]+)(?:\s+([^}]*))?\}|((?:\r\n|\r|\n)[ \t]*(?:\r\n|\r|\n))/gi;
 		let inpre = false;
 		src = src || "";
-		src = src.replace(r, function (match, pre, endpre, header, endheader, linkTarget, linkText) {
+		src = src.replace(r, function (match, pre, endpre, header, endheader, linkTarget: string, linkText: string) {
 			if (pre) {
 				inpre = true;
 			} else if (endpre) {
@@ -252,7 +252,7 @@ function _preProcessLinksInTextBlock(sText: string, ui5Url: string): string {
 		const aTarget = sTarget.split(".");
 		if (aTarget.length >= 3) {
 			const constructorName = aTarget.find((el) => el.toLowerCase() !== el);
-			let index = aTarget.indexOf(constructorName || "");
+			let index = aTarget.indexOf(constructorName ?? "");
 			index = (index === -1) ? aTarget.length : (index + 1);
 			// Lacking of complimentary information for the type, then construct the
 			// link to the class name, so the user could find the information on their own.
diff --git a/src/formatter/text.ts b/src/formatter/text.ts
index 395b62467..7cdaf7746 100644
--- a/src/formatter/text.ts
+++ b/src/formatter/text.ts
@@ -7,7 +7,7 @@ function formatSeverity(severity: LintMessageSeverity) {
 	} else if (severity === LintMessageSeverity.Warning) {
 		return chalk.yellow("warning");
 	} else {
-		throw new Error(`Unknown severity: ${severity}`);
+		throw new Error(`Unknown severity: ${LintMessageSeverity[severity]}`);
 	}
 }
 
diff --git a/src/linter/json/ManifestLinter.ts b/src/linter/json/ManifestLinter.ts
index 08783ec7e..185a78bb9 100644
--- a/src/linter/json/ManifestLinter.ts
+++ b/src/linter/json/ManifestLinter.ts
@@ -35,6 +35,7 @@ export default class ManifestLinter {
 		this.#path = path;
 	}
 
+	// eslint-disable-next-line @typescript-eslint/require-await
 	async getReport(): Promise {
 		const source = this.#parseManifest(this.#content);
 		this.#reporter = new ManifestReporter(this.#path, source);
@@ -45,12 +46,12 @@ export default class ManifestLinter {
 	}
 
 	#parseManifest(manifest: string): jsonSourceMapType {
-		return jsonMap.parse(manifest);
+		return jsonMap.parse(manifest);
 	}
 
 	#analyzeManifest(manifest: SAPJSONSchemaForWebApplicationManifestFile) {
-		const {resources, models} = manifest["sap.ui5"]! ?? {};
-		const {dataSources} = manifest["sap.app"] ?? {};
+		const {resources, models} = (manifest["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace);
+		const {dataSources} = (manifest["sap.app"] ?? {} as JSONSchemaForSAPAPPNamespace);
 
 		if (resources?.js) {
 			this.#reporter?.addMessage({
@@ -61,13 +62,13 @@ export default class ManifestLinter {
 			});
 		}
 
-		const modelKeys: string[] = (models && Object.keys(models)) || [];
+		const modelKeys: string[] = (models && Object.keys(models)) ?? [];
 		modelKeys.forEach((modelKey: string) => {
-			const curModel: ManifestModel = (models?.[modelKey])) || {};
+			const curModel: ManifestModel = (models?.[modelKey]) ?? {};
 
 			if (!curModel.type) {
 				const curDataSource = dataSources && curModel.dataSource &&
-					dataSources[curModel.dataSource];
+					dataSources[curModel.dataSource] as ManifestDataSource | undefined;
 
 				if (curDataSource &&
 					/* if not provided dataSource.type="OData" */
diff --git a/src/linter/linter.ts b/src/linter/linter.ts
index 5828d95ca..a6058e5ef 100644
--- a/src/linter/linter.ts
+++ b/src/linter/linter.ts
@@ -4,6 +4,7 @@ import {TsFileDetector, TsProjectDetector} from "../detectors/typeChecker/index.
 import {taskStart} from "../detectors/util/perf.js";
 import path from "node:path";
 import {stat} from "node:fs/promises";
+import {ProjectGraph} from "@ui5/project";
 
 interface LinterOptions {
 	rootDir: string;
@@ -16,6 +17,7 @@ async function fsStat(fsPath: string) {
 		// eslint-disable-next-line @typescript-eslint/no-explicit-any
 	} catch (err: any) {
 		// "File or directory does not exist"
+		// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
 		if (err.code === "ENOENT") {
 			return false;
 		} else {
@@ -34,7 +36,7 @@ async function fileExists(dirPath: string) {
 	return stats && stats.isFile();
 }
 
-async function getProjectGraph(rootDir: string) {
+async function getProjectGraph(rootDir: string): Promise {
 	let rootConfigPath, rootConfiguration;
 	const ui5YamlPath = path.join(rootDir, "ui5.yaml");
 	if (await fileExists(ui5YamlPath)) {
diff --git a/src/untyped.d.ts b/src/untyped.d.ts
index 218ed982a..548a0dad3 100644
--- a/src/untyped.d.ts
+++ b/src/untyped.d.ts
@@ -1,18 +1,11 @@
-declare module "@ui5/to-esm" {
-	interface Result {
-		source: string;
-		map: string;
-	}
-	export default function ui5ToESM(content: string, options: object): Result;
-}
+// Note: Do not use import declarations in this file, otherwise the modules are no longer treated
+// as ambient (global) but local. Use inline import() instead.
 
 declare module "@ui5/project" {
-	import {AbstractReader} from "@ui5/fs";
-
 	type ProjectNamespace = string;
 	interface Project {
 		getNamespace: () => ProjectNamespace;
-		getReader: (options: ReaderOptions) => AbstractReader;
+		getReader: (options: import("@ui5/fs").ReaderOptions) => import("@ui5/fs").AbstractReader;
 		getRootPath: () => string;
 	}
 	interface ProjectGraph {
@@ -38,31 +31,30 @@ declare module "@ui5/project/ui5Framework/maven/CacheMode" {
 }
 
 declare module "@ui5/project/graph" {
-	import type CacheMode from "@ui5/project/ui5Framework/maven/CacheMode";
-
 	interface GraphFromObjectOptions {
-		dependencyTree: DependencyTreeNode;
+		dependencyTree: import("@ui5/project").DependencyTreeNode;
 		cwd?: string;
 		rootConfiguration?: object;
 		rootConfigPath?: string;
 		versionOverride?: string;
-		cacheMode?: CacheMode;
+		cacheMode?: import("@ui5/project/ui5Framework/maven/CacheMode").default;
 		resolveFrameworkDependencies?: boolean;
 	}
-	export function graphFromObject(options: GraphFromObjectOptions): Promise;
+	export function graphFromObject(options: GraphFromObjectOptions): Promise;
 
 	interface GraphFromPackageDependenciesOptions {
 		cwd?: string;
 		rootConfiguration?: object;
 		rootConfigPath?: string;
 		versionOverride?: string;
-		cacheMode?: CacheMode;
+		cacheMode?: import("@ui5/project/ui5Framework/maven/CacheMode").default;
 		resolveFrameworkDependencies?: boolean;
 		workspaceName?: string;
 		workspaceConfiguration?: object;
 		workspaceConfigPath?: string;
 	}
-	export function graphFromPackageDependencies(options?: GraphFromPackageDependenciesOptions): Promise;
+	export function graphFromPackageDependencies(options?: GraphFromPackageDependenciesOptions):
+	Promise;
 }
 
 declare module "@ui5/fs" {
@@ -73,34 +65,33 @@ declare module "@ui5/fs" {
 	interface Resource {
 		getBuffer: () => Promise;
 		getString: () => Promise;
-		getStream: () => stream.Readable;
+		getStream: () => import("node:fs").ReadStream;
 		getName: () => string;
 		getPath: () => ResourcePath;
-		getProject: () => Project;
+		getProject: () => import("@ui5/project").Project;
 		getSourceMetadata: () => ResourceSourceMetadata;
 	}
-	enum ReaderStyles {
-		buildtime = "buildtime",
-		dist = "dist",
-		runtime = "runtime",
-		flat = "flat",
-	}
+	type ReaderStyles = "buildtime" | "dist" | "runtime" | "flat";
+
 	interface ReaderOptions {
 		style: ReaderStyles;
 	}
 	interface GlobOptions {
 		nodir?: boolean;
 	}
-	interface AbstractReader {
+	export interface AbstractReader {
 		byGlob: (virPattern: string | string[], options?: GlobOptions) => Promise;
 	}
-	interface AbstractAdapter extends AbstractReader {
-
+	export interface AbstractAdapter extends AbstractReader {
+		write: (resource: Resource) => Promise;
 	}
 }
+
 declare module "@ui5/fs/resourceFactory" {
-	export function createAdapter({fsBasePath: string, virBasePath: string}): AbstractAdapter;
-	export function createResource({path: string, string: string}): Resource;
+	export function createAdapter(parameters: {fsBasePath: string; virBasePath: string}):
+	import("@ui5/fs").AbstractAdapter;
+	export function createResource(parameters: {path: string; string: string}):
+	import("@ui5/fs").Resource;
 }
 
 declare module "@ui5/logger" {
@@ -126,4 +117,6 @@ declare module "@ui5/logger/writers/Console" {
 }
 
 // There are no TS Types for json-source-map
-declare module "json-source-map";
+declare module "json-source-map" {
+	export function parse(content: string): T;
+}
diff --git a/test/lib/cli.ts b/test/lib/cli.ts
index 451b49ba9..7f770a548 100644
--- a/test/lib/cli.ts
+++ b/test/lib/cli.ts
@@ -1,13 +1,13 @@
 import anyTest, {TestFn} from "ava";
 import sinon, {SinonStub} from "sinon";
-import yargs from "yargs";
+import {Argv} from "yargs";
 import esmock, {MockFunction} from "esmock";
 import {fileURLToPath} from "node:url";
 import {readFileSync} from "node:fs";
 
 const test = anyTest as TestFn<{
 	argvGetter: SinonStub;
-	yargsInstance: yargs.Argv & {
+	yargsInstance: Argv & {
 		parserConfiguration: SinonStub;
 		version: SinonStub;
 		scriptName: SinonStub;
@@ -37,9 +37,10 @@ test.beforeEach(async (t) => {
 		wrap: sinon.stub(),
 		get argv() {
 			t.context.argvGetter();
-			return undefined;
+			// eslint-disable-next-line @typescript-eslint/no-explicit-any
+			return {} as any;
 		},
-	};
+	} as typeof t.context.yargsInstance;
 
 	t.context.yargs = sinon.stub().returns(t.context.yargsInstance).named("yargs");
 
@@ -70,7 +71,7 @@ test.serial("CLI", async (t) => {
 		setVersion, cliBase,
 	} = t.context;
 
-	await cli();
+	await cli("module");
 
 	t.is(yargs.callCount, 1);
 	t.deepEqual(yargs.getCall(0).args, [[]]);
diff --git a/test/lib/cli/base.integration.ts b/test/lib/cli/base.integration.ts
index c82da948a..be9b1ce29 100644
--- a/test/lib/cli/base.integration.ts
+++ b/test/lib/cli/base.integration.ts
@@ -1,6 +1,6 @@
 import anyTest, {TestFn} from "ava";
 import sinon, {SinonStub} from "sinon";
-import yargs from "yargs";
+import yargs, {Argv} from "yargs";
 import path from "node:path";
 import cliBase from "../../../src/cli/base.js";
 import {fileURLToPath} from "node:url";
@@ -13,10 +13,10 @@ const test = anyTest as TestFn<{
 	consoleLogStub: SinonStub;
 	processCwdStub: SinonStub;
 	processStdoutWriteStub: SinonStub;
-	cli: yargs.Argv;
+	cli: Argv;
 }>;
 
-test.beforeEach(async (t) => {
+test.beforeEach((t) => {
 	t.context.consoleLogStub = sinon.stub(console, "log");
 	t.context.processCwdStub = sinon.stub(process, "cwd").returns(sampleProjectPath);
 	t.context.processStdoutWriteStub = sinon.stub(process.stdout, "write").returns(true);
diff --git a/test/lib/cli/base.ts b/test/lib/cli/base.ts
index 4f44aa99f..cf0221fa4 100644
--- a/test/lib/cli/base.ts
+++ b/test/lib/cli/base.ts
@@ -1,8 +1,9 @@
+/* eslint-disable @typescript-eslint/require-await */
 import anyTest, {TestFn} from "ava";
 import sinon, {SinonStub} from "sinon";
 import esmock from "esmock";
 import chalk from "chalk";
-import yargs from "yargs";
+import yargs, {Argv} from "yargs";
 import path from "node:path";
 import type {LintResult} from "../../../src/detectors/AbstractDetector.js";
 import type Base from "../../../src/cli/base.js";
@@ -17,7 +18,7 @@ const test = anyTest as TestFn<{
 	processErrWrite: SinonStub;
 	formatText: SinonStub;
 	formatJson: SinonStub;
-	cli: yargs.Argv;
+	cli: Argv;
 	base: typeof Base;
 }>;
 
@@ -154,6 +155,7 @@ test.serial("Yargs error handling", async (t) => {
 	cli.command({
 		command: "foo",
 		describe: "This is a task",
+		// eslint-disable-next-line @typescript-eslint/no-empty-function
 		handler: async function () {},
 	});
 
diff --git a/test/lib/detectors/transpilers/amd/parseModuleDeclaration.ts b/test/lib/detectors/transpilers/amd/parseModuleDeclaration.ts
index cd3749caf..f32d2e482 100644
--- a/test/lib/detectors/transpilers/amd/parseModuleDeclaration.ts
+++ b/test/lib/detectors/transpilers/amd/parseModuleDeclaration.ts
@@ -1,12 +1,10 @@
-import anyTest, {TestFn} from "ava";
+import test from "ava";
 import ts from "typescript";
 import {ModuleDeclaration, DefineCallArgument, _matchArgumentsToParameters} from
 	"../../../../../src/detectors/transpilers/amd/parseModuleDeclaration.js";
 const {SyntaxKind} = ts;
 
-const test = anyTest;
-
-test("All parameters provided directly", async (t) => {
+test("All parameters provided directly", (t) => {
 	const args = [{
 		kind: SyntaxKind.StringLiteral,
 	}, {
@@ -33,7 +31,7 @@ test("All parameters provided directly", async (t) => {
 	}, "Matched parameters correctly");
 });
 
-test("Factory provided", async (t) => {
+test("Factory provided", (t) => {
 	const args = [{
 		kind: SyntaxKind.FunctionExpression,
 	}] as DefineCallArgument[];
@@ -45,7 +43,7 @@ test("Factory provided", async (t) => {
 	}, "Matched parameters correctly");
 });
 
-test("Dependencies and Factory provided", async (t) => {
+test("Dependencies and Factory provided", (t) => {
 	const args = [{
 		kind: SyntaxKind.ArrayLiteralExpression,
 	}, {
@@ -62,7 +60,7 @@ test("Dependencies and Factory provided", async (t) => {
 	}, "Matched parameters correctly");
 });
 
-test("Module Name, Dependencies and Factory provided", async (t) => {
+test("Module Name, Dependencies and Factory provided", (t) => {
 	const args = [{
 		kind: SyntaxKind.StringLiteral,
 	}, {
@@ -84,7 +82,7 @@ test("Module Name, Dependencies and Factory provided", async (t) => {
 	}, "Matched parameters correctly");
 });
 
-test("Dependencies, Factory and Export provided", async (t) => {
+test("Dependencies, Factory and Export provided", (t) => {
 	const args = [{
 		kind: SyntaxKind.ArrayLiteralExpression,
 	}, {
@@ -110,7 +108,8 @@ interface TestArguments {
 	args: DefineCallArgument[];
 	expected: ModuleDeclaration;
 }
-function generateArguments(possibleParameterTypes) {
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function generateArguments(possibleParameterTypes: any) {
 	const permutations: TestArguments[] = [];
 	for (const moduleNameKind of possibleParameterTypes.moduleName) {
 		for (const dependenciesKind of possibleParameterTypes.dependencies) {
@@ -169,8 +168,9 @@ function generateArguments(possibleParameterTypes) {
 function resolveSyntaxKind(decl: ModuleDeclaration) {
 	const res = Object.create(null);
 	for (const key in decl) {
-		if (decl[key]?.kind) {
-			res[key] = ts.SyntaxKind[decl[key].kind];
+		const prop = decl[key as keyof ModuleDeclaration];
+		if (prop?.kind) {
+			res[key] = ts.SyntaxKind[prop.kind];
 		}
 	}
 	return res;
@@ -190,7 +190,7 @@ function declToString(decl: ModuleDeclaration): string {
 	return argsToString(args);
 }
 
-test("All combinations", async (t) => {
+test("All combinations", (t) => {
 	const permutations = generateArguments({
 		moduleName: [SyntaxKind.StringLiteral, null],
 		dependencies: [SyntaxKind.ArrayLiteralExpression, null],
diff --git a/test/lib/detectors/transpilers/amd/transpiler.ts b/test/lib/detectors/transpilers/amd/transpiler.ts
index 3bd33ed42..4735707a1 100644
--- a/test/lib/detectors/transpilers/amd/transpiler.ts
+++ b/test/lib/detectors/transpilers/amd/transpiler.ts
@@ -14,7 +14,7 @@ const test = anyTest as TestFn<{
 	createdFiles: object;
 }>;
 
-test.beforeEach(async (t) => {
+test.beforeEach((t) => {
 	t.context.sinon = sinonGlobal.createSandbox();
 	t.context.createdFiles = {};
 });
diff --git a/test/lib/formatter/json.ts b/test/lib/formatter/json.ts
index 6822964a7..e7d476e9b 100644
--- a/test/lib/formatter/json.ts
+++ b/test/lib/formatter/json.ts
@@ -1,6 +1,6 @@
 import anyTest, {TestFn} from "ava";
-import {Json} from "../../../src/formatter/json.ts";
-import {LintResult} from "../../../src/detectors/AbstractDetector.ts";
+import {Json} from "../../../src/formatter/json.js";
+import {LintResult} from "../../../src/detectors/AbstractDetector.js";
 
 const test = anyTest as TestFn<{
 	lintResults: LintResult[];
diff --git a/test/lib/formatter/lib/resolveLinks.ts b/test/lib/formatter/lib/resolveLinks.ts
index 4a37e765a..fc03349b4 100644
--- a/test/lib/formatter/lib/resolveLinks.ts
+++ b/test/lib/formatter/lib/resolveLinks.ts
@@ -1,4 +1,4 @@
-import anyTest, {TestFn} from "ava";
+import anyTest from "ava";
 import {resolveLinks} from "../../../../src/formatter/lib/resolveLinks.js";
 
 const test = anyTest;
diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts
index ad4527067..2531d4de5 100644
--- a/test/lib/linter/_linterHelper.ts
+++ b/test/lib/linter/_linterHelper.ts
@@ -4,7 +4,8 @@ import util from "util";
 import {readdirSync} from "node:fs";
 import esmock from "esmock";
 import {LintResult} from "../../../src/detectors/AbstractDetector.js";
-import FileLinter from "../../../src/detectors/typeChecker/FileLinter.ts";
+import FileLinter from "../../../src/detectors/typeChecker/FileLinter.js";
+import {SourceFile, TypeChecker} from "typescript";
 
 util.inspect.defaultOptions.depth = 4; // Increase AVA's printing depth since coverageInfo objects are on level 4
 
@@ -23,7 +24,10 @@ test.before(async (t) => {
 export async function esmockMessageDetails() {
 	const checkerModule = await esmock("../../../src/detectors/typeChecker/index.js", {
 		"../../../src/detectors/typeChecker/FileLinter.js":
-		function (rootDir, filePath, sourceFile, sourceMap, checker) {
+		function (
+			rootDir: string, filePath: string, sourceFile: SourceFile,
+			sourceMap: string | undefined, checker: TypeChecker
+		) {
 			// Don't use sinon's stubs as it's hard to clean after them in this case and it leaks memory.
 			const linter = new FileLinter(rootDir, filePath, sourceFile, sourceMap, checker);
 			linter.extractDeprecatedMessage = () => "Deprecated test message";
@@ -83,7 +87,7 @@ export function createTestsForFixtures(fixturesPath: string) {
 					filePaths,
 				});
 				assertExpectedLintResults(t, res, fixturesPath, filePaths);
-				res.forEach((results) => {
+				res.forEach((results: {filePath: string}) => {
 					results.filePath = testName;
 				});
 				t.snapshot(res);
diff --git a/test/lib/linter/linter.ts b/test/lib/linter/linter.ts
index d489e58a3..f46f63b25 100644
--- a/test/lib/linter/linter.ts
+++ b/test/lib/linter/linter.ts
@@ -37,7 +37,7 @@ test.serial("lint: All files of com.ui5.troublesome.app", async (t) => {
 		filePaths: [],
 	});
 
-	res = res.sort((a, b) => {
+	res = res.sort((a: {filePath: string}, b: {filePath: string}) => {
 		return a.filePath.localeCompare(b.filePath);
 	});
 
@@ -58,7 +58,7 @@ test.serial("lint: Some files of com.ui5.troublesome.app", async (t) => {
 		filePaths,
 	});
 
-	res = res.sort((a, b) => {
+	res = res.sort((a: {filePath: string}, b: {filePath: string}) => {
 		return a.filePath.localeCompare(b.filePath);
 	});
 
@@ -79,7 +79,7 @@ test.serial("lint: All files of library.with.custom.paths", async (t) => {
 		filePaths: [],
 	});
 
-	res = res.sort((a, b) => {
+	res = res.sort((a: {filePath: string}, b: {filePath: string}) => {
 		return a.filePath.localeCompare(b.filePath);
 	});