From e9992532a1978b6e3e2adf8a68ff5933030c7dc1 Mon Sep 17 00:00:00 2001 From: Rainer Hahnekamp Date: Wed, 11 Sep 2024 21:44:43 +0200 Subject: [PATCH] fix(core): process static imports Enable static imports resolution using `baseUrl` in `tsconfig.json` This update allows resolving static imports when the `baseUrl` property is set in `tsconfig.json`. For example, `import { foo } from 'app/main.ts'` can be resolved easily. - If `baseUrl` is set to `src`, the path resolves to `./src/app/main.ts`. - If `baseUrl` is not defined, resolution falls back to checking `node_modules`. --- .release-please-manifest.json | 4 - package.json | 3 +- .../src/lib/file-info/generate-ts-data.ts | 6 +- .../generate-unassigned-file-info.ts | 2 +- ...d-root-dir.ts => get-ts-config-context.ts} | 41 ++- .../get-ts-paths-and-root-dir.spec.ts | 137 ---------- .../lib/file-info/{ => tests}/fs-path.spec.ts | 10 +- .../{ => tests}/generate-ts-data.spec.ts | 14 +- .../generate-unassigned-file-info.spec.ts | 16 +- .../tests/get-ts-config-context.spec.ts | 258 ++++++++++++++++++ .../{ => tests}/traverse-filesystem.spec.ts | 98 ++++--- .../{ => tests}/unassigned-file-info.spec.ts | 8 +- .../src/lib/file-info/traverse-filesystem.ts | 15 +- packages/core/src/lib/file-info/ts-data.ts | 5 +- packages/core/src/lib/log/log.module.spec.ts | 12 +- .../core/src/lib/test/fixtures/ts-config.ts | 23 +- .../lib/rules/{ => tests}/create-rule.spec.ts | 2 +- .../lib/rules/{ => tests}/deep-import.spec.ts | 2 +- .../rules/{ => tests}/dependency-rule.spec.ts | 2 +- sonar-project.properties | 1 + vitest.config.ts | 3 +- yarn.lock | 165 +++++------ 22 files changed, 475 insertions(+), 352 deletions(-) delete mode 100644 .release-please-manifest.json rename packages/core/src/lib/file-info/{get-ts-paths-and-root-dir.ts => get-ts-config-context.ts} (61%) delete mode 100644 packages/core/src/lib/file-info/get-ts-paths-and-root-dir.spec.ts rename packages/core/src/lib/file-info/{ => tests}/fs-path.spec.ts (75%) rename packages/core/src/lib/file-info/{ => tests}/generate-ts-data.spec.ts (80%) rename packages/core/src/lib/file-info/{ => tests}/generate-unassigned-file-info.spec.ts (91%) create mode 100644 packages/core/src/lib/file-info/tests/get-ts-config-context.spec.ts rename packages/core/src/lib/file-info/{ => tests}/traverse-filesystem.spec.ts (67%) rename packages/core/src/lib/file-info/{ => tests}/unassigned-file-info.spec.ts (89%) rename packages/eslint-plugin/src/lib/rules/{ => tests}/create-rule.spec.ts (97%) rename packages/eslint-plugin/src/lib/rules/{ => tests}/deep-import.spec.ts (97%) rename packages/eslint-plugin/src/lib/rules/{ => tests}/dependency-rule.spec.ts (96%) create mode 100644 sonar-project.properties diff --git a/.release-please-manifest.json b/.release-please-manifest.json deleted file mode 100644 index 6f0275c..0000000 --- a/.release-please-manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "packages/core": "0.13.1", - "packages/eslint-plugin": "0.13.1" -} diff --git a/package.json b/package.json index b9a34ec..1991e74 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@types/eslint": "^8.4.6", "@types/estree": "^1.0.0", "@types/node": "18.19.14", + "@typescript-eslint/rule-tester": "^8.5.0", "@vitest/coverage-v8": "^2.0.3", "eslint": "^9.6.0", "eslint-config-prettier": "^9.1.0", @@ -38,7 +39,7 @@ "prettier": "^3.2.5", "ts-node": "10.9.1", "typescript": "5.5.3", - "typescript-eslint": "8.0.0-alpha.41", + "typescript-eslint": "^8.5.0", "vitest": "^2.0.3" } } diff --git a/packages/core/src/lib/file-info/generate-ts-data.ts b/packages/core/src/lib/file-info/generate-ts-data.ts index dcfc39b..b6ec199 100644 --- a/packages/core/src/lib/file-info/generate-ts-data.ts +++ b/packages/core/src/lib/file-info/generate-ts-data.ts @@ -1,7 +1,7 @@ import getFs, { isFsVirtualised } from '../fs/getFs'; import * as ts from 'typescript'; import { TsData } from './ts-data'; -import { getTsPathsAndRootDir } from './get-ts-paths-and-root-dir'; +import { getTsConfigContext } from './get-ts-config-context'; import { FsPath, toFsPath } from './fs-path'; /** @@ -23,7 +23,7 @@ import { FsPath, toFsPath } from './fs-path'; * This will return a paths property of `{'app/*': './src/app'}` */ export const generateTsData = (tsConfigPath: FsPath): TsData => { - const { paths, rootDir } = getTsPathsAndRootDir(tsConfigPath); + const configContext = getTsConfigContext(tsConfigPath); const fs = getFs(); const cwd = fs.getParent(tsConfigPath); @@ -38,7 +38,7 @@ export const generateTsData = (tsConfigPath: FsPath): TsData => { const sys = getTsSys(); - return { paths, configObject, cwd, sys, rootDir }; + return { ...configContext, configObject, cwd, sys}; }; function getTsSys(): ts.System { diff --git a/packages/core/src/lib/file-info/generate-unassigned-file-info.ts b/packages/core/src/lib/file-info/generate-unassigned-file-info.ts index b2a0aa6..b08c80d 100644 --- a/packages/core/src/lib/file-info/generate-unassigned-file-info.ts +++ b/packages/core/src/lib/file-info/generate-unassigned-file-info.ts @@ -1,9 +1,9 @@ import UnassignedFileInfo from './unassigned-file-info'; -import traverseFilesystem from './traverse-filesystem'; import { FsPath } from './fs-path'; import { formatFileInfo } from './format-file-info'; import { logger } from '../log'; import { TsData } from './ts-data'; +import { traverseFilesystem } from "./traverse-filesystem"; const log = logger('core.file-info.generate-and-root-dir'); diff --git a/packages/core/src/lib/file-info/get-ts-paths-and-root-dir.ts b/packages/core/src/lib/file-info/get-ts-config-context.ts similarity index 61% rename from packages/core/src/lib/file-info/get-ts-paths-and-root-dir.ts rename to packages/core/src/lib/file-info/get-ts-config-context.ts index c3236d6..255b252 100644 --- a/packages/core/src/lib/file-info/get-ts-paths-and-root-dir.ts +++ b/packages/core/src/lib/file-info/get-ts-config-context.ts @@ -4,22 +4,35 @@ import { FsPath, toFsPath } from './fs-path'; import { TsConfig } from './ts-config'; import { InvalidPathError } from '../error/user-error'; +export type TsConfigContext = { + paths: Record; + rootDir: FsPath; + baseUrl?: FsPath; +}; + /** - * Retrieves the paths variable from a tsconfig and also traverses through - * potential parent configs. + * Parses the tsconfig.json file and returns specific information for + * further processing. + * + * Maps paths from the tsconfig.json to `FilePath` where possible. + * It also traverses through potential parent configs. + * It also resolves the `baseUrl` - if present - to an `FsPath`. * * If there are wildcards, the wildcard will be removed from their path value. - * This is necessary to keep up the FsPath type + * This is necessary to keep up the FsPath type. + * + * It matters, if a `baseUrl` exists or not. It is not by default set to + * the root directory of the tsconfig.json. That has implications for the + * TypeScript resolution because static imports only work with a `baseUrl`. * * @param tsConfigPath path of the tsconfig.json */ -export const getTsPathsAndRootDir = ( - tsConfigPath: FsPath, -): { paths: Record; rootDir: FsPath } => { +export function getTsConfigContext(tsConfigPath: FsPath): TsConfigContext { const fs = getFs(); let currentTsConfigPath = tsConfigPath; let currentTsConfigDir = fs.getParent(currentTsConfigPath); const paths: Record = {}; + let baseUrl: FsPath | undefined = undefined; while (currentTsConfigPath) { const configRawContent = fs.readFile(currentTsConfigPath); @@ -29,16 +42,18 @@ export const getTsPathsAndRootDir = ( ); const config = configContent.config as TsConfig; - const baseUrl = config.compilerOptions?.baseUrl ?? './'; + currentTsConfigDir = fs.getParent(currentTsConfigPath); + if (baseUrl === undefined && config.compilerOptions?.baseUrl) { + baseUrl = toFsPath(fs.join(currentTsConfigDir, config.compilerOptions.baseUrl)) + } const newPaths: Record = config.compilerOptions?.paths ?? {}; - currentTsConfigDir = fs.getParent(currentTsConfigPath); for (const [key, [value]] of Object.entries(newPaths)) { const valueForFsPath = value.endsWith('/*') ? value.slice(0, -2) : value; const potentialFilename = fs.join( currentTsConfigDir, - baseUrl, + config.compilerOptions?.baseUrl ?? './', valueForFsPath, ); if (fs.exists(potentialFilename)) { @@ -62,5 +77,9 @@ export const getTsPathsAndRootDir = ( } } - return { paths, rootDir: currentTsConfigDir }; -}; + return { + paths, + rootDir: currentTsConfigDir, + baseUrl + }; +} diff --git a/packages/core/src/lib/file-info/get-ts-paths-and-root-dir.spec.ts b/packages/core/src/lib/file-info/get-ts-paths-and-root-dir.spec.ts deleted file mode 100644 index b34c848..0000000 --- a/packages/core/src/lib/file-info/get-ts-paths-and-root-dir.spec.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { describe, expect, test } from 'vitest'; -import { createProject } from '../test/project-creator'; -import { toFsPath } from './fs-path'; -import { getTsPathsAndRootDir } from './get-ts-paths-and-root-dir'; -import { InvalidPathError } from '../error/user-error'; -import '../test/expect.extensions'; -import { tsConfig } from '../test/fixtures/ts-config'; - -describe('get ts paths and root dir', () => { - for (const { name, tsPaths, fsPaths } of [ - { - name: 'default paths', - tsPaths: { - '@app/*': ['src/app'], - '@customers': ['src/app/customers/index.ts'], - '@holidays': ['src/app/holidays/index.ts'], - }, - fsPaths: { - '@app/*': '/project/src/app', - '@customers': '/project/src/app/customers/index.ts', - '@holidays': '/project/src/app/holidays/index.ts', - }, - }, - { - name: 'directory path', - tsPaths: { - '@customers': ['src/app/customers'], - }, - fsPaths: { - '@customers': '/project/src/app/customers', - }, - }, - { - name: 'file without extension path', - tsPaths: { - '@customers': ['src/app/customers/index'], - }, - fsPaths: { - '@customers': '/project/src/app/customers/index.ts', - }, - }, - ]) { - test(name, () => { - createProject({ - 'tsconfig.json': tsConfig({ paths: tsPaths }), - src: { - app: { - 'main.ts': [], - customers: { - 'index.ts': [], - }, - holidays: { - 'index.ts': [], - }, - }, - }, - }); - - expect( - getTsPathsAndRootDir(toFsPath('/project/tsconfig.json')).paths, - ).toEqual(fsPaths); - }); - } - - for (const { name, tsPaths, errorParams } of [ - { - name: 'not existing path', - tsPaths: { - '@app': ['src/app/sdf'], - }, - errorParams: ['@app', 'src/app/sdf'], - }, - { - name: 'not existing file', - tsPaths: { - '@main': ['src/app/index'], - }, - errorParams: ['@main', 'src/app/index'], - }, - { - name: 'not existing path with wildcard', - tsPaths: { - '@app/*': ['src/app/somewhere'], - }, - errorParams: ['@app/*', 'src/app/somewhere'], - }, - ]) { - test(name, () => { - createProject({ - 'tsconfig.json': tsConfig({ paths: tsPaths }), - src: { - app: { - 'main.ts': [], - customers: { - 'index.ts': [], - }, - holidays: { - 'index.ts': [], - }, - }, - }, - }); - - const [pathAlias, path] = errorParams; - - expect(() => - getTsPathsAndRootDir(toFsPath('/project/tsconfig.json')), - ).toThrowUserError(new InvalidPathError(pathAlias, path)); - }); - } - - describe('baseUrl', () => { - test('different baseUrl', () => { - createProject({ - 'tsconfig.json': tsConfig({ - paths: { '@app/*': ['app'] }, - baseUrl: './src', - }), - src: { - app: { - 'main.ts': [], - customers: { - 'index.ts': [], - }, - holidays: { - 'index.ts': [], - }, - }, - }, - }); - - expect( - getTsPathsAndRootDir(toFsPath('/project/tsconfig.json')).paths, - ).toEqual({ '@app/*': '/project/src/app' }); - }); - }); -}); diff --git a/packages/core/src/lib/file-info/fs-path.spec.ts b/packages/core/src/lib/file-info/tests/fs-path.spec.ts similarity index 75% rename from packages/core/src/lib/file-info/fs-path.spec.ts rename to packages/core/src/lib/file-info/tests/fs-path.spec.ts index d0c81e8..d2b147b 100644 --- a/packages/core/src/lib/file-info/fs-path.spec.ts +++ b/packages/core/src/lib/file-info/tests/fs-path.spec.ts @@ -1,7 +1,7 @@ -import { beforeAll, beforeEach, describe, expect, it } from 'vitest'; -import getFs, { useDefaultFs, useVirtualFs } from '../fs/getFs'; -import { Fs } from '../fs/fs'; -import { isFsPath, toFsPath } from './fs-path'; +import getFs, { useDefaultFs, useVirtualFs } from '../../fs/getFs'; +import { Fs } from '../../fs/fs'; +import { isFsPath, toFsPath } from '../fs-path'; +import { describe, beforeEach, beforeAll, it, expect } from 'vitest'; describe('FsPath', () => { describe('VirtualFs', () => { @@ -37,6 +37,6 @@ describe('FsPath', () => { it('should also allow a directory', () => { useDefaultFs(); const fs = getFs(); - expect(isFsPath(fs.join(__dirname, '../test'))).toBe(true); + expect(isFsPath(fs.join(__dirname, '../tests'))).toBe(true); }); }); diff --git a/packages/core/src/lib/file-info/generate-ts-data.spec.ts b/packages/core/src/lib/file-info/tests/generate-ts-data.spec.ts similarity index 80% rename from packages/core/src/lib/file-info/generate-ts-data.spec.ts rename to packages/core/src/lib/file-info/tests/generate-ts-data.spec.ts index 55f0452..7dccde5 100644 --- a/packages/core/src/lib/file-info/generate-ts-data.spec.ts +++ b/packages/core/src/lib/file-info/tests/generate-ts-data.spec.ts @@ -1,10 +1,10 @@ -import { createProject } from '../test/project-creator'; -import { generateTsData } from './generate-ts-data'; -import { describe, it, test, expect } from 'vitest'; -import { FileTree } from '../test/project-configurator'; -import { toFsPath } from './fs-path'; -import { TsPaths } from './ts-data'; -import { tsConfig } from '../test/fixtures/ts-config'; +import { createProject } from '../../test/project-creator'; +import { generateTsData } from '../generate-ts-data'; +import { FileTree } from '../../test/project-configurator'; +import { toFsPath } from '../fs-path'; +import { TsPaths } from '../ts-data'; +import { tsConfig } from '../../test/fixtures/ts-config'; +import { describe, it, expect, test } from 'vitest'; describe('generateTsData', () => { function setup( diff --git a/packages/core/src/lib/file-info/generate-unassigned-file-info.spec.ts b/packages/core/src/lib/file-info/tests/generate-unassigned-file-info.spec.ts similarity index 91% rename from packages/core/src/lib/file-info/generate-unassigned-file-info.spec.ts rename to packages/core/src/lib/file-info/tests/generate-unassigned-file-info.spec.ts index efe050a..fef87f6 100644 --- a/packages/core/src/lib/file-info/generate-unassigned-file-info.spec.ts +++ b/packages/core/src/lib/file-info/tests/generate-unassigned-file-info.spec.ts @@ -1,11 +1,11 @@ -import { describe, expect, it } from 'vitest'; -import { generateUnassignedFileInfo } from './generate-unassigned-file-info'; -import { createProject } from '../test/project-creator'; -import { inVfs } from '../test/in-vfs'; -import { toFsPath } from './fs-path'; -import { generateTsData } from './generate-ts-data'; -import getFs from '../fs/getFs'; -import { tsConfig } from '../test/fixtures/ts-config'; +import { generateUnassignedFileInfo } from '../generate-unassigned-file-info'; +import { createProject } from '../../test/project-creator'; +import { inVfs } from '../../test/in-vfs'; +import { toFsPath } from '../fs-path'; +import { generateTsData } from '../generate-ts-data'; +import getFs from '../../fs/getFs'; +import { tsConfig } from '../../test/fixtures/ts-config'; +import { describe, it, expect } from 'vitest'; describe('Generate File Info', () => { const getTsData = () => diff --git a/packages/core/src/lib/file-info/tests/get-ts-config-context.spec.ts b/packages/core/src/lib/file-info/tests/get-ts-config-context.spec.ts new file mode 100644 index 0000000..12d45f8 --- /dev/null +++ b/packages/core/src/lib/file-info/tests/get-ts-config-context.spec.ts @@ -0,0 +1,258 @@ +import { createProject } from "../../test/project-creator"; +import { toFsPath } from "../fs-path"; +import { getTsConfigContext } from "../get-ts-config-context"; +import { InvalidPathError } from "../../error/user-error"; +import { fullTsConfig, tsConfig } from "../../test/fixtures/ts-config"; +import { describe, it, expect, test } from 'vitest'; + +describe("getTsConfigContext", () => { + for (const { name, tsPaths, fsPaths } of [ + { + name: "default paths", + tsPaths: { + "@app/*": ["src/app"], + "@customers": ["src/app/customers/index.ts"], + "@holidays": ["src/app/holidays/index.ts"] + }, + fsPaths: { + "@app/*": "/project/src/app", + "@customers": "/project/src/app/customers/index.ts", + "@holidays": "/project/src/app/holidays/index.ts" + } + }, + { + name: "directory path", + tsPaths: { + "@customers": ["src/app/customers"] + }, + fsPaths: { + "@customers": "/project/src/app/customers" + } + }, + { + name: "file without extension path", + tsPaths: { + "@customers": ["src/app/customers/index"] + }, + fsPaths: { + "@customers": "/project/src/app/customers/index.ts" + } + } + ]) { + test(name, () => { + createProject({ + "tsconfig.json": tsConfig({ paths: tsPaths }), + src: { + app: { + "main.ts": [], + customers: { + "index.ts": [] + }, + holidays: { + "index.ts": [] + } + } + } + }); + + expect( + getTsConfigContext(toFsPath("/project/tsconfig.json")).paths + ).toEqual(fsPaths); + }); + } + + for (const { name, tsPaths, errorParams } of [ + { + name: "not existing path", + tsPaths: { + "@app": ["src/app/sdf"] + }, + errorParams: ["@app", "src/app/sdf"] + }, + { + name: "not existing file", + tsPaths: { + "@main": ["src/app/index"] + }, + errorParams: ["@main", "src/app/index"] + }, + { + name: "not existing path with wildcard", + tsPaths: { + "@app/*": ["src/app/somewhere"] + }, + errorParams: ["@app/*", "src/app/somewhere"] + } + ]) { + test(name, () => { + createProject({ + "tsconfig.json": tsConfig({ paths: tsPaths }), + src: { + app: { + "main.ts": [], + customers: { + "index.ts": [] + }, + holidays: { + "index.ts": [] + } + } + } + }); + + const [pathAlias, path] = errorParams; + + expect(() => + getTsConfigContext(toFsPath("/project/tsconfig.json")) + ).toThrowUserError(new InvalidPathError(pathAlias, path)); + }); + } + + describe("baseUrl", () => { + it("should be undefined if not set", () => { + createProject({ + "tsconfig.json": tsConfig({}), + "main.ts": [] + }); + + const context = getTsConfigContext(toFsPath("/project/tsconfig.json")); + + expect(context.baseUrl).toBeUndefined(); + }); + + it("should provide the FsPath if set", () => { + createProject({ + "tsconfig.json": tsConfig({ + baseUrl: "." + }), + "main.ts": [] + }); + + const context = getTsConfigContext(toFsPath("/project/tsconfig.json")); + + expect(context.baseUrl).toBe('/project'); + }); + + it("should be inferred from a parent if not available", () => { + createProject({ + "tsconfig.base.json": tsConfig({ + baseUrl: "app/src" + }), + app: { + src: { + "tsconfig.json": fullTsConfig({ + extends: "../../tsconfig.base.json" + }), + "main.ts": [] + } + } + }); + + const context = getTsConfigContext(toFsPath("/project/app/src/tsconfig.json")); + + expect(context.baseUrl).toBe('/project/app/src'); + }) + + it("should override parent", () => { + createProject({ + "tsconfig.base.json": tsConfig({ + baseUrl: "." + }), + app: { + "tsconfig.json": fullTsConfig({ + extends: "../tsconfig.base.json", + compilerOptions: { + baseUrl: "." + } + }), + src: { + "main.ts": [] + } + } + }); + + const context = getTsConfigContext(toFsPath("/project/app/tsconfig.json")); + + expect(context.baseUrl).toBe('/project/app'); + }); + + + it(`should consider the baseUrl's value for path resolution`, () => { + createProject({ + "tsconfig.json": tsConfig({ + paths: { "@app/*": ["app"] }, + baseUrl: "./src" + }), + src: { + app: { + "main.ts": [], + customers: { + "index.ts": [] + }, + holidays: { + "index.ts": [] + } + } + } + }); + + expect( + getTsConfigContext(toFsPath("/project/tsconfig.json")).paths + ).toEqual({ "@app/*": "/project/src/app" }); + }); + + it("should have nested paths with different baseUrls", () => { + createProject({ + "tsconfig.base.json": tsConfig({ + paths: { "@root/*": ["."] }, + }), + app: { + "tsconfig.sub-base.json": fullTsConfig({ + extends: "../tsconfig.base.json", + compilerOptions: { + baseUrl: "./src", + paths: { "@app/*": ["."] } + } + }), + src: { + "tsconfig.json": fullTsConfig({ + extends: "../tsconfig.sub-base.json", + compilerOptions: { + baseUrl: ".", + paths: { "@customers/*": ["customers"] } + } + }), + "main.ts": ['@customers'], + customers: { + "index.ts": [] + }, + } + } + }); + + const context = getTsConfigContext(toFsPath("/project/app/src/tsconfig.json")); + + expect(context.baseUrl).toBe('/project/app/src'); + expect(context.paths).toEqual({ + "@root/*": "/project", + "@app/*": "/project/app/src", + "@customers/*": "/project/app/src/customers" + }); + }); + }); + + test("no compilerOptions", () => { + createProject({ + "tsconfig.json": JSON.stringify({}), + src: { + app: { + "main.ts": [] + } + } + }); + + expect( + getTsConfigContext(toFsPath("/project/tsconfig.json")).rootDir + ).toEqual("/project"); + }); +}); diff --git a/packages/core/src/lib/file-info/traverse-filesystem.spec.ts b/packages/core/src/lib/file-info/tests/traverse-filesystem.spec.ts similarity index 67% rename from packages/core/src/lib/file-info/traverse-filesystem.spec.ts rename to packages/core/src/lib/file-info/tests/traverse-filesystem.spec.ts index 118b344..8112b9d 100644 --- a/packages/core/src/lib/file-info/traverse-filesystem.spec.ts +++ b/packages/core/src/lib/file-info/tests/traverse-filesystem.spec.ts @@ -1,34 +1,25 @@ -import { beforeEach, describe, expect, it } from 'vitest'; -import { FileTree } from '../test/project-configurator'; -import { createProject } from '../test/project-creator'; -import traverseFilesystem, { - ResolveFn, - resolvePotentialTsPath, -} from './traverse-filesystem'; -import { FsPath, toFsPath } from './fs-path'; -import UnassignedFileInfo, { buildFileInfo } from './unassigned-file-info'; -import { generateTsData } from './generate-ts-data'; -import { ResolvedModuleFull } from 'typescript'; -import { tsConfig } from '../test/fixtures/ts-config'; - -function setup(fileTree: FileTree) { +import { FileTree } from '../../test/project-configurator'; +import { createProject } from "../../test/project-creator"; +import { generateTsData } from "../generate-ts-data"; +import { FsPath, toFsPath } from "../fs-path"; +import UnassignedFileInfo, { buildFileInfo } from "../unassigned-file-info"; +import { tsConfig } from "../../test/fixtures/ts-config"; +import { ResolveFn, resolvePotentialTsPath, traverseFilesystem } from "../traverse-filesystem"; +import { ResolvedModuleFull } from "typescript"; +import { describe, it, expect } from 'vitest'; + +function setup(fileTree: FileTree): UnassignedFileInfo { createProject(fileTree); const tsData = generateTsData(toFsPath('/project/tsconfig.json')); const mainPath = toFsPath('/project/src/main.ts'); - return { tsData, mainPath }; + return traverseFilesystem(mainPath, new Map(), tsData); } -describe('traverse file-system', () => { - let fileInfoDict: Map; - - beforeEach(() => { - fileInfoDict = new Map(); - }); - +describe('traverse filesystem', () => { it('should find a single import', () => { - const { tsData, mainPath } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig(), src: { 'main.ts': ['./app/app.component'], @@ -40,7 +31,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [ @@ -50,7 +40,7 @@ describe('traverse file-system', () => { }); it('should work with paths', () => { - const { tsData, mainPath } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig({ paths: { '@customers': ['/src/app/customers/index.ts'], @@ -66,7 +56,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [ @@ -76,7 +65,7 @@ describe('traverse file-system', () => { }); it('should pick up dynamic imports', () => { - const { mainPath, tsData } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig(), src: { 'main.ts': `const routes = {[path: 'customers', loadChildren: () => import('./customers/index.ts')]};`, @@ -85,7 +74,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [['./customers/index.ts', []]]), @@ -93,7 +81,7 @@ describe('traverse file-system', () => { }); it('should pick index.ts automatically if path is a directory', () => { - const { tsData, mainPath } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig({ paths: { '@customers': ['/src/app/customers'] }, }), @@ -107,7 +95,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [ @@ -117,7 +104,7 @@ describe('traverse file-system', () => { }); it('should automatically pick the file extension if missing in path', () => { - const { tsData, mainPath } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig({ paths: { '@customers': ['/src/app/customers/index'] }, }), @@ -131,7 +118,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [ @@ -141,7 +127,7 @@ describe('traverse file-system', () => { }); it('should ignore an import if a non-wildcard path is used like a wildcard', () => { - const { tsData, mainPath } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig({ paths: { '@customers': ['/src/app/customers'] }, }), @@ -156,7 +142,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [['./app/app.component.ts', []]]), @@ -164,7 +149,7 @@ describe('traverse file-system', () => { }); it('should find a path with wildcards', () => { - const { tsData, mainPath } = setup({ + const fileInfo = setup({ 'tsconfig.json': tsConfig({ paths: { '@app/*': ['/src/app/*'] } }), src: { 'main.ts': ['@app/app.component'], @@ -176,7 +161,6 @@ describe('traverse file-system', () => { }, }, }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); expect(fileInfo).toEqual( buildFileInfo('/project/src/main.ts', [ @@ -185,24 +169,36 @@ describe('traverse file-system', () => { ); }); - it('should use a non-standard baseUrl', () => { - const { tsData, mainPath } = setup({ - 'tsconfig.json': tsConfig({ - paths: { '@app/*': ['app/*'] }, - baseUrl: 'src', - }), - src: { - 'main.ts': ['@app/app.component.ts'], - app: { - 'app.component.ts': [], + describe('base url', () => { + it('should resolve static imports', () => { + const fileInfo = setup({ + 'tsconfig.json': tsConfig({ baseUrl: 'src' }), + src: { + 'main.ts': ['app/app.component.ts'], + app: { + 'app.component.ts': [], + }, }, - }, + }); + + expect(fileInfo).toEqual( + buildFileInfo('/project/src/main.ts', [['./app/app.component.ts', []]]), + ); }); - const fileInfo = traverseFilesystem(mainPath, fileInfoDict, tsData); - expect(fileInfo).toEqual( - buildFileInfo('/project/src/main.ts', [['./app/app.component.ts', []]]), - ); + it('cannot resolve static imports if baseUrl is not set', () => { + const fileInfo = setup({ + 'tsconfig.json': tsConfig({baseUrl: undefined}), + src: { + 'main.ts': ['src/app/app.component.ts'], + app: { + 'app.component.ts': [], + }, + }, + }); + + expect(fileInfo).toEqual(buildFileInfo('/project/src/main.ts', [])); + }); }); it('should throw an error in resolvePotentialTsPath when path is a nodeJs dependency', () => { diff --git a/packages/core/src/lib/file-info/unassigned-file-info.spec.ts b/packages/core/src/lib/file-info/tests/unassigned-file-info.spec.ts similarity index 89% rename from packages/core/src/lib/file-info/unassigned-file-info.spec.ts rename to packages/core/src/lib/file-info/tests/unassigned-file-info.spec.ts index 90bd63b..6742d8d 100644 --- a/packages/core/src/lib/file-info/unassigned-file-info.spec.ts +++ b/packages/core/src/lib/file-info/tests/unassigned-file-info.spec.ts @@ -1,7 +1,7 @@ -import UnassignedFileInfo, { buildFileInfo } from './unassigned-file-info'; -import { beforeAll, beforeEach, describe, expect, it } from 'vitest'; -import { toFsPath } from './fs-path'; -import getFs, { useVirtualFs } from '../fs/getFs'; +import UnassignedFileInfo, { buildFileInfo } from '../unassigned-file-info'; +import { toFsPath } from '../fs-path'; +import getFs, { useVirtualFs } from '../../fs/getFs'; +import { describe, beforeEach, beforeAll, it, expect } from 'vitest'; const fi = (path: string, imports: UnassignedFileInfo[] = []) => new UnassignedFileInfo(toFsPath(path), imports); diff --git a/packages/core/src/lib/file-info/traverse-filesystem.ts b/packages/core/src/lib/file-info/traverse-filesystem.ts index ce2006d..a0d9bd2 100644 --- a/packages/core/src/lib/file-info/traverse-filesystem.ts +++ b/packages/core/src/lib/file-info/traverse-filesystem.ts @@ -31,21 +31,24 @@ export type ResolveFn = ( * @param fileContent if passed, is used instead the content of @fsPath. * necessary for unsaved files inESLint */ -const traverseFilesystem = ( +export function traverseFilesystem( fsPath: FsPath, fileInfoDict: Map, tsData: TsData, runOnce = false, fileContent?: string, -): UnassignedFileInfo => { - const { paths, configObject, sys, rootDir } = tsData; +): UnassignedFileInfo { + const { paths, sys, rootDir, baseUrl, configObject } = tsData; const fileInfo: UnassignedFileInfo = new UnassignedFileInfo(fsPath, []); fileInfoDict.set(fsPath, fileInfo); const fs = getFs(); fileContent = fileContent ?? fs.readFile(fsPath); const preProcessedFile = ts.preProcessFile(fileContent); + + const config = {...configObject.options, baseUrl}; + const resolveFn: ResolveFn = (moduleName: string) => - ts.resolveModuleName(moduleName, fsPath, configObject.options, sys); + ts.resolveModuleName(moduleName, fsPath, config, sys); for (const importedFile of preProcessedFile.importedFiles) { const { fileName } = importedFile; @@ -102,7 +105,7 @@ const traverseFilesystem = ( } return fileInfo; -}; +} export function resolvePotentialTsPath( moduleName: string, @@ -191,5 +194,3 @@ function isPathFile(path: string): boolean { const fs = getFs(); return fs.exists(path) && isFsPath(path) && fs.isFile(path); } - -export default traverseFilesystem; diff --git a/packages/core/src/lib/file-info/ts-data.ts b/packages/core/src/lib/file-info/ts-data.ts index 92d8945..21d825d 100644 --- a/packages/core/src/lib/file-info/ts-data.ts +++ b/packages/core/src/lib/file-info/ts-data.ts @@ -1,15 +1,14 @@ import type * as ts from 'typescript'; import { FsPath } from './fs-path'; +import { TsConfigContext } from "./get-ts-config-context"; export type TsPaths = Record; /** * Contains data needed by `traverseFilesystem`. */ -export interface TsData { +export type TsData = TsConfigContext & { configObject: ReturnType; - paths: TsPaths; cwd: string; sys: typeof ts.sys; - rootDir: FsPath; } diff --git a/packages/core/src/lib/log/log.module.spec.ts b/packages/core/src/lib/log/log.module.spec.ts index 0296638..942f68b 100644 --- a/packages/core/src/lib/log/log.module.spec.ts +++ b/packages/core/src/lib/log/log.module.spec.ts @@ -1,12 +1,3 @@ -import { - afterEach, - beforeAll, - describe, - expect, - it, - SpyInstance, - vitest, -} from 'vitest'; import { logger } from './logger'; import getFs, { useVirtualFs } from '../fs/getFs'; import { init } from '../main/init'; @@ -16,10 +7,11 @@ import { sheriffConfig } from '../test/project-configurator'; import { reset } from './log'; import { Fs } from '../fs/fs'; import { tsConfig } from '../test/fixtures/ts-config'; +import { MockInstance, describe, it, expect, beforeAll, afterEach, vitest } from "vitest"; describe('log', () => { let fs: Fs; - let appendSpy: SpyInstance; + let appendSpy: MockInstance; const setup = (enableLog: boolean) => { createProject( diff --git a/packages/core/src/lib/test/fixtures/ts-config.ts b/packages/core/src/lib/test/fixtures/ts-config.ts index e0d6f07..9c9a3bc 100644 --- a/packages/core/src/lib/test/fixtures/ts-config.ts +++ b/packages/core/src/lib/test/fixtures/ts-config.ts @@ -1,19 +1,32 @@ const defaultTsConfig = { compilerOptions: { - target: 'es2016', - module: 'commonjs', + target: "es2016", + module: "commonjs", strict: true, - skipLibCheck: true, - }, + skipLibCheck: true + } }; + export interface TsConfig { baseUrl?: string; paths?: Record; } +export interface FullTsConfig { + extends?: string; + compilerOptions?: TsConfig; +} + export function tsConfig(config: Partial = {}) { return JSON.stringify({ - compilerOptions: { ...defaultTsConfig.compilerOptions, ...config }, + compilerOptions: { ...defaultTsConfig.compilerOptions, ...config } }); } + +export function fullTsConfig(config: Partial = {}) { + return JSON.stringify({ + extends: config.extends, + compilerOptions: { ...defaultTsConfig.compilerOptions, ...(config.compilerOptions ?? {}) } + }) +} diff --git a/packages/eslint-plugin/src/lib/rules/create-rule.spec.ts b/packages/eslint-plugin/src/lib/rules/tests/create-rule.spec.ts similarity index 97% rename from packages/eslint-plugin/src/lib/rules/create-rule.spec.ts rename to packages/eslint-plugin/src/lib/rules/tests/create-rule.spec.ts index a839bc8..2758387 100644 --- a/packages/eslint-plugin/src/lib/rules/create-rule.spec.ts +++ b/packages/eslint-plugin/src/lib/rules/tests/create-rule.spec.ts @@ -1,6 +1,6 @@ import { RuleTester } from 'eslint'; import { afterEach, describe, expect, it, vitest } from 'vitest'; -import { createRule } from './create-rule'; +import { createRule } from '../create-rule'; import { UserError } from '@softarc/sheriff-core'; import { parser } from 'typescript-eslint'; diff --git a/packages/eslint-plugin/src/lib/rules/deep-import.spec.ts b/packages/eslint-plugin/src/lib/rules/tests/deep-import.spec.ts similarity index 97% rename from packages/eslint-plugin/src/lib/rules/deep-import.spec.ts rename to packages/eslint-plugin/src/lib/rules/tests/deep-import.spec.ts index afc56ed..b5d43fb 100644 --- a/packages/eslint-plugin/src/lib/rules/deep-import.spec.ts +++ b/packages/eslint-plugin/src/lib/rules/tests/deep-import.spec.ts @@ -1,6 +1,6 @@ import { RuleTester } from 'eslint'; import { afterEach, describe, expect, it, vitest } from 'vitest'; -import { deepImport } from './deep-import'; +import { deepImport } from '../deep-import'; import * as sheriffCore from '@softarc/sheriff-core'; import { parser } from "typescript-eslint"; diff --git a/packages/eslint-plugin/src/lib/rules/dependency-rule.spec.ts b/packages/eslint-plugin/src/lib/rules/tests/dependency-rule.spec.ts similarity index 96% rename from packages/eslint-plugin/src/lib/rules/dependency-rule.spec.ts rename to packages/eslint-plugin/src/lib/rules/tests/dependency-rule.spec.ts index b7449f0..5cf905f 100644 --- a/packages/eslint-plugin/src/lib/rules/dependency-rule.spec.ts +++ b/packages/eslint-plugin/src/lib/rules/tests/dependency-rule.spec.ts @@ -1,7 +1,7 @@ import { RuleTester } from 'eslint'; import { afterEach, describe, expect, it, vitest } from 'vitest'; import * as sheriffCore from '@softarc/sheriff-core'; -import { dependencyRule } from './dependency-rule'; +import { dependencyRule } from '../dependency-rule'; import { parser } from 'typescript-eslint'; const tester = new RuleTester({ diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..9a59ed6 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1 @@ +sonar.javascript.lcov.reportPaths=./coverage/lcov.info diff --git a/vitest.config.ts b/vitest.config.ts index e58444d..784912b 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -5,7 +5,8 @@ export default defineConfig({ test: { coverage: { provider: 'v8', - reporter: ['text', 'html'], + reporter: ['text', 'html', 'lcov'], + include: ['packages/*/src/lib/**/*.ts'], }, include: ['packages/**/*.spec.ts'], setupFiles: ['packages/core/src/lib/test/expect.extensions.ts'], diff --git a/yarn.lock b/yarn.lock index a56ffb5..4e8f545 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1802,85 +1802,97 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== -"@typescript-eslint/eslint-plugin@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.0.0-alpha.41.tgz#8dfb0416c802cf53d9b8ba2688bb5d87c3b5a5ba" - integrity sha512-WePtbzWMaQO4qtGAXp3zzEN8yYZCEuAHVCERCUXgoSUTQ80F5UB7T5lYyA9ySpFDB7rqJ2ev98DtnbS4U3Ms+w== +"@typescript-eslint/eslint-plugin@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.5.0.tgz#7c1863693a98371703686e1c0fac64ffc576cdb1" + integrity sha512-lHS5hvz33iUFQKuPFGheAB84LwcJ60G8vKnEhnfcK1l8kGVLro2SFYW6K0/tj8FUhRJ0VHyg1oAfg50QGbPPHw== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "8.0.0-alpha.41" - "@typescript-eslint/type-utils" "8.0.0-alpha.41" - "@typescript-eslint/utils" "8.0.0-alpha.41" - "@typescript-eslint/visitor-keys" "8.0.0-alpha.41" + "@typescript-eslint/scope-manager" "8.5.0" + "@typescript-eslint/type-utils" "8.5.0" + "@typescript-eslint/utils" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" ts-api-utils "^1.3.0" -"@typescript-eslint/parser@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.0.0-alpha.41.tgz#d6b5f3a869a78d490c94628bc119a9a38c5842a8" - integrity sha512-7HMXwy/q/59ZASBXz2FtdIsR7LgABrR8j2dTKq9GMR8OkjjdO4klxWSY/uOBozVt4UxlMRYsBdBDhEq4/tHRiw== +"@typescript-eslint/parser@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.5.0.tgz#d590e1ef9f31f26d423999ad3f687723247e6bcc" + integrity sha512-gF77eNv0Xz2UJg/NbpWJ0kqAm35UMsvZf1GHj8D9MRFTj/V3tAciIWXfmPLsAAF/vUlpWPvUDyH1jjsr0cMVWw== dependencies: - "@typescript-eslint/scope-manager" "8.0.0-alpha.41" - "@typescript-eslint/types" "8.0.0-alpha.41" - "@typescript-eslint/typescript-estree" "8.0.0-alpha.41" - "@typescript-eslint/visitor-keys" "8.0.0-alpha.41" + "@typescript-eslint/scope-manager" "8.5.0" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/typescript-estree" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.0.0-alpha.41.tgz#7729d129d966cc34a3b37c12cf08ba1b0467d516" - integrity sha512-iNxuQ0TMVfFiMJ2al4bGd/mY9+aLtBxnHfo7B2xoVzR6cRFgUdBLlMa//MSIjSmVRpCEqNLQnkxpJb96tFG+xw== +"@typescript-eslint/rule-tester@^8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/rule-tester/-/rule-tester-8.5.0.tgz#d475106e06c2f80dd6226d72a6f35da5633fb305" + integrity sha512-ySLDyc7rktaTLcAICIKf5MG6tjc20g9e6oud4oG1OlsBLZlV9Yl4iuCnmBILojjST8/iYs5o1qebYhF1r97EfA== dependencies: - "@typescript-eslint/types" "8.0.0-alpha.41" - "@typescript-eslint/visitor-keys" "8.0.0-alpha.41" + "@typescript-eslint/typescript-estree" "8.5.0" + "@typescript-eslint/utils" "8.5.0" + ajv "^6.12.6" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "4.6.2" + semver "^7.6.0" + +"@typescript-eslint/scope-manager@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.5.0.tgz#385341de65b976f02b295b8aca54bb4ffd6b5f07" + integrity sha512-06JOQ9Qgj33yvBEx6tpC8ecP9o860rsR22hWMEd12WcTRrfaFgHr2RB/CA/B+7BMhHkXT4chg2MyboGdFGawYg== + dependencies: + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" -"@typescript-eslint/type-utils@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.0.0-alpha.41.tgz#6da1e44d9ce1e060e66feaa45f73a792965a0e69" - integrity sha512-+QIA1z/jrox6bbvqlyqBQjotpevieLTycfiuoKuqGcKoskFZV5Rma51BV8LCJacnOafwJtSi+7b8zDo8OsXUvA== +"@typescript-eslint/type-utils@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.5.0.tgz#6215b23aa39dbbd8dde0a4ef9ee0f745410c29b1" + integrity sha512-N1K8Ix+lUM+cIDhL2uekVn/ZD7TZW+9/rwz8DclQpcQ9rk4sIL5CAlBC0CugWKREmDjBzI/kQqU4wkg46jWLYA== dependencies: - "@typescript-eslint/typescript-estree" "8.0.0-alpha.41" - "@typescript-eslint/utils" "8.0.0-alpha.41" + "@typescript-eslint/typescript-estree" "8.5.0" + "@typescript-eslint/utils" "8.5.0" debug "^4.3.4" ts-api-utils "^1.3.0" -"@typescript-eslint/types@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.0.0-alpha.41.tgz#c1f8dacfb118e4d9febdff2f065802c4db69beae" - integrity sha512-n0P2FP3YC3pD3yoiCf4lHqbUP45xlnOk8HkjB+LtKSUZZWLLJ8k1ZXZtQj7MEX22tytCMj//Bmq403xFuCwfIg== +"@typescript-eslint/types@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.5.0.tgz#4465d99331d1276f8fb2030e4f9c73fe01a05bf9" + integrity sha512-qjkormnQS5wF9pjSi6q60bKUHH44j2APxfh9TQRXK8wbYVeDYYdYJGIROL87LGZZ2gz3Rbmjc736qyL8deVtdw== -"@typescript-eslint/typescript-estree@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.0.0-alpha.41.tgz#c78c96d6b3f39355aac2bdf2f999abfd9333121f" - integrity sha512-adCr+vbLYTFhwhIwjIjjMxTdUYiPA2Jlyuhnbj092IzgLHtT79bvuwcgPWeTyLbFb/13SMKmOEka00xHiqLpig== +"@typescript-eslint/typescript-estree@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.5.0.tgz#6e5758cf2f63aa86e9ddfa4e284e2e0b81b87557" + integrity sha512-vEG2Sf9P8BPQ+d0pxdfndw3xIXaoSjliG0/Ejk7UggByZPKXmJmw3GW5jV2gHNQNawBUyfahoSiCFVov0Ruf7Q== dependencies: - "@typescript-eslint/types" "8.0.0-alpha.41" - "@typescript-eslint/visitor-keys" "8.0.0-alpha.41" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/visitor-keys" "8.5.0" debug "^4.3.4" - globby "^11.1.0" + fast-glob "^3.3.2" is-glob "^4.0.3" minimatch "^9.0.4" semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.0.0-alpha.41.tgz#de7d1fb1856773c7343028352cf326a668aa43b9" - integrity sha512-DTxc9VdERS6iloiw1P5tgRDqRArmp/sIuvgdHBvGh2SiltEFc3VjLGnHHGSTr6GfH7tjFWvcCnCtxx+pjWfp5Q== +"@typescript-eslint/utils@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.5.0.tgz#4d4ffed96d0654546a37faa5b84bdce16d951634" + integrity sha512-6yyGYVL0e+VzGYp60wvkBHiqDWOpT63pdMV2CVG4LVDd5uR6q1qQN/7LafBZtAtNIn/mqXjsSeS5ggv/P0iECw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "8.0.0-alpha.41" - "@typescript-eslint/types" "8.0.0-alpha.41" - "@typescript-eslint/typescript-estree" "8.0.0-alpha.41" + "@typescript-eslint/scope-manager" "8.5.0" + "@typescript-eslint/types" "8.5.0" + "@typescript-eslint/typescript-estree" "8.5.0" -"@typescript-eslint/visitor-keys@8.0.0-alpha.41": - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.0.0-alpha.41.tgz#6ddefe0a08a36683e2e8db4b161d6b67374b7757" - integrity sha512-uetCAUBVC+YarBdZnWzDDgX11PpAEGV8Cw31I3d1xNrhx6/bJGThKX+holEmd3amMdnr4w/XUKH/4YuQOgtjDA== +"@typescript-eslint/visitor-keys@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.5.0.tgz#13028df3b866d2e3e2e2cc4193cf2c1e0e04c4bf" + integrity sha512-yTPqMnbAZJNy2Xq2XU8AdtOW9tJIr+UQb64aXB9f3B1498Zx9JorVgFJcZpEc9UBuCCrdzKID2RGAMkYcDtZOw== dependencies: - "@typescript-eslint/types" "8.0.0-alpha.41" + "@typescript-eslint/types" "8.5.0" eslint-visitor-keys "^3.4.3" "@vitest/coverage-v8@^2.0.3": @@ -2003,7 +2015,7 @@ address@^1.0.1: resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== -ajv@^6.12.4: +ajv@^6.12.4, ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -2091,11 +2103,6 @@ array-ify@^1.0.0: resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng== -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" @@ -2514,13 +2521,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -2813,7 +2813,7 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.2.9: +fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -3022,18 +3022,6 @@ globals@^14.0.0: resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -3442,7 +3430,7 @@ lodash.kebabcase@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== -lodash.merge@^4.6.2: +lodash.merge@4.6.2, lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== @@ -3542,7 +3530,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -4149,11 +4137,6 @@ signal-exit@^4.0.1, signal-exit@^4.1.0: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" @@ -4434,14 +4417,14 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typescript-eslint@8.0.0-alpha.41: - version "8.0.0-alpha.41" - resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.0.0-alpha.41.tgz#b88af15dfbfa08051f4697698193fcae04ee147f" - integrity sha512-+e7D2XDZeHLe9D3bP7S0Va8YdLHzn3YcesoxMS9SjMWhtaSb5ylxk2txqT84sUS0WIDQetZlvDg2/UmY5B/ycg== +typescript-eslint@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.5.0.tgz#041f6c302d0e9a8e116a33d60b0bb19f34036dd7" + integrity sha512-uD+XxEoSIvqtm4KE97etm32Tn5MfaZWgWfMMREStLxR6JzvHkc2Tkj7zhTEK5XmtpTmKHNnG8Sot6qDfhHtR1Q== dependencies: - "@typescript-eslint/eslint-plugin" "8.0.0-alpha.41" - "@typescript-eslint/parser" "8.0.0-alpha.41" - "@typescript-eslint/utils" "8.0.0-alpha.41" + "@typescript-eslint/eslint-plugin" "8.5.0" + "@typescript-eslint/parser" "8.5.0" + "@typescript-eslint/utils" "8.5.0" typescript@5.5.3: version "5.5.3"