From a5bd5c72c9ecb941f36366f126d07334bd592633 Mon Sep 17 00:00:00 2001 From: Daniil Sapa Date: Mon, 30 Dec 2024 23:10:57 +0200 Subject: [PATCH 1/3] Nest FSD roots in some test cases --- .../src/_lib/collect-related-ts-configs.ts | 10 +- .../src/_lib/index-source-files.ts | 59 ++++++----- .../src/ambiguous-slice-names/index.spec.ts | 27 +++-- .../src/excessive-slicing/index.spec.ts | 25 +++-- .../src/forbidden-imports/index.spec.ts | 83 ++++++++------- .../src/import-locality/index.spec.ts | 70 +++++++----- .../src/inconsistent-naming/index.spec.ts | 29 +++-- .../src/insignificant-slice/index.spec.ts | 81 ++++++++------ .../src/no-file-segments/index.spec.ts | 27 +++-- .../src/no-layer-public-api/index.spec.ts | 24 +++-- .../src/no-processes/index.spec.ts | 19 +++- .../src/no-public-api-sidestep/index.spec.ts | 100 +++++++++++------- .../no-reserved-folder-names/index.spec.ts | 18 ++-- .../src/no-segmentless-slices/index.spec.ts | 18 ++-- .../index.spec.ts | 22 ++-- .../src/no-ui-in-app/index.spec.ts | 16 ++- .../src/public-api/index.spec.ts | 44 +++++--- .../src/repetitive-naming/index.spec.ts | 54 +++++++--- .../src/segments-by-purpose/index.spec.ts | 24 +++-- .../src/shared-lib-grouping/index.spec.ts | 23 ++-- .../src/typo-in-layer-name/index.spec.ts | 46 +++++--- 21 files changed, 514 insertions(+), 305 deletions(-) diff --git a/packages/steiger-plugin-fsd/src/_lib/collect-related-ts-configs.ts b/packages/steiger-plugin-fsd/src/_lib/collect-related-ts-configs.ts index 5e42269a..25cba350 100644 --- a/packages/steiger-plugin-fsd/src/_lib/collect-related-ts-configs.ts +++ b/packages/steiger-plugin-fsd/src/_lib/collect-related-ts-configs.ts @@ -150,13 +150,13 @@ if (import.meta.vitest) { const payload: CollectRelatedTsConfigsPayload = { extended: [ { - tsconfigFile: resolve(joinFromRoot('tsconfig.json')), + tsconfigFile: resolve(joinFromRoot('user', 'projects', 'project-0', 'src', 'tsconfig.json')), tsconfig: { extends: './.nuxt/tsconfig.json', }, }, { - tsconfigFile: resolve(joinFromRoot('.nuxt', 'tsconfig.json')), + tsconfigFile: resolve(joinFromRoot('user', 'projects', 'project-0', 'src', '.nuxt', 'tsconfig.json')), tsconfig: { compilerOptions: { paths: { @@ -173,7 +173,7 @@ if (import.meta.vitest) { }, }, ], - tsconfigFile: resolve(joinFromRoot('tsconfig.json')), + tsconfigFile: resolve(joinFromRoot('user', 'projects', 'project-0', 'src', 'tsconfig.json')), tsconfig: { extends: './.nuxt/tsconfig.json', compilerOptions: { @@ -196,8 +196,8 @@ if (import.meta.vitest) { extends: './.nuxt/tsconfig.json', compilerOptions: { paths: { - '~': [resolve(joinFromRoot())], - '~/*': [resolve(joinFromRoot('*'))], + '~': [resolve(joinFromRoot('user', 'projects', 'project-0', 'src'))], + '~/*': [resolve(joinFromRoot('user', 'projects', 'project-0', 'src', '*'))], }, strict: true, noUncheckedIndexedAccess: false, diff --git a/packages/steiger-plugin-fsd/src/_lib/index-source-files.ts b/packages/steiger-plugin-fsd/src/_lib/index-source-files.ts index c112c6da..7c8c63dc 100644 --- a/packages/steiger-plugin-fsd/src/_lib/index-source-files.ts +++ b/packages/steiger-plugin-fsd/src/_lib/index-source-files.ts @@ -56,7 +56,8 @@ export function indexSourceFiles(root: Folder): Record { if (import.meta.vitest) { const { test, expect } = import.meta.vitest test('indexSourceFiles', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -80,120 +81,122 @@ if (import.meta.vitest) { 📄 index.ts 📄 root.ts 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(indexSourceFiles(root)).toEqual({ - [joinFromRoot('features', 'comments', 'index.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'index.ts')]: { file: { - path: joinFromRoot('features', 'comments', 'index.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'index.ts'), type: 'file', }, layerName: 'features', segmentName: null, sliceName: 'comments', }, - [joinFromRoot('features', 'comments', 'ui', 'CommentCard.tsx')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'ui', 'CommentCard.tsx')]: { file: { - path: joinFromRoot('features', 'comments', 'ui', 'CommentCard.tsx'), + path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'ui', 'CommentCard.tsx'), type: 'file', }, layerName: 'features', segmentName: 'ui', sliceName: 'comments', }, - [joinFromRoot('pages', 'editor', 'index.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'index.ts')]: { file: { - path: joinFromRoot('pages', 'editor', 'index.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'index.ts'), type: 'file', }, layerName: 'pages', segmentName: null, sliceName: 'editor', }, - [joinFromRoot('pages', 'editor', 'ui', 'Editor.tsx')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'Editor.tsx')]: { file: { - path: joinFromRoot('pages', 'editor', 'ui', 'Editor.tsx'), + path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'Editor.tsx'), type: 'file', }, layerName: 'pages', segmentName: 'ui', sliceName: 'editor', }, - [joinFromRoot('pages', 'editor', 'ui', 'EditorPage.tsx')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'EditorPage.tsx')]: { file: { - path: joinFromRoot('pages', 'editor', 'ui', 'EditorPage.tsx'), + path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'EditorPage.tsx'), type: 'file', }, layerName: 'pages', segmentName: 'ui', sliceName: 'editor', }, - [joinFromRoot('pages', 'editor', 'ui', 'styles.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'styles.ts')]: { file: { - path: joinFromRoot('pages', 'editor', 'ui', 'styles.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'styles.ts'), type: 'file', }, layerName: 'pages', segmentName: 'ui', sliceName: 'editor', }, - [joinFromRoot('shared', 'ui', 'Button.tsx')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'Button.tsx')]: { file: { - path: joinFromRoot('shared', 'ui', 'Button.tsx'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'Button.tsx'), type: 'file', }, layerName: 'shared', segmentName: 'ui', sliceName: null, }, - [joinFromRoot('shared', 'ui', 'TextField.tsx')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'TextField.tsx')]: { file: { - path: joinFromRoot('shared', 'ui', 'TextField.tsx'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'TextField.tsx'), type: 'file', }, layerName: 'shared', segmentName: 'ui', sliceName: null, }, - [joinFromRoot('shared', 'ui', 'index.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'index.ts')]: { file: { - path: joinFromRoot('shared', 'ui', 'index.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'index.ts'), type: 'file', }, layerName: 'shared', segmentName: 'ui', sliceName: null, }, - [joinFromRoot('shared', 'ui', 'styles.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'styles.ts')]: { file: { - path: joinFromRoot('shared', 'ui', 'styles.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'styles.ts'), type: 'file', }, layerName: 'shared', segmentName: 'ui', sliceName: null, }, - [joinFromRoot('app', 'ui', 'index.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'app', 'ui', 'index.ts')]: { file: { - path: joinFromRoot('app', 'ui', 'index.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'app', 'ui', 'index.ts'), type: 'file', }, layerName: 'app', segmentName: 'ui', sliceName: null, }, - [joinFromRoot('app', 'root.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'app', 'root.ts')]: { file: { - path: joinFromRoot('app', 'root.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'app', 'root.ts'), type: 'file', }, layerName: 'app', segmentName: 'root', sliceName: null, }, - [joinFromRoot('app', 'index.ts')]: { + [joinFromRoot('users', 'user', 'project', 'src', 'app', 'index.ts')]: { file: { - path: joinFromRoot('app', 'index.ts'), + path: joinFromRoot('users', 'user', 'project', 'src', 'app', 'index.ts'), type: 'file', }, layerName: 'app', diff --git a/packages/steiger-plugin-fsd/src/ambiguous-slice-names/index.spec.ts b/packages/steiger-plugin-fsd/src/ambiguous-slice-names/index.spec.ts index d2ceba67..4ba889cf 100644 --- a/packages/steiger-plugin-fsd/src/ambiguous-slice-names/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/ambiguous-slice-names/index.spec.ts @@ -5,7 +5,8 @@ import ambiguousSliceNames from './index.js' import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project without slice names that match some segment name in Shared', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -20,13 +21,16 @@ it('reports no errors on a project without slice names that match some segment n 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(ambiguousSliceNames.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with slice names that match some segment name in Shared', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -45,19 +49,22 @@ it('reports errors on a project with slice names that match some segment name in 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = ambiguousSliceNames.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'Slice "i18n" could be confused with a segment from Shared with the same name', - location: { path: joinFromRoot('features', 'i18n') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'i18n') }, }, ]) }) it('works for slice groups and grouped slices', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -78,17 +85,19 @@ it('works for slice groups and grouped slices', () => { 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = ambiguousSliceNames.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'Slice group "i18n" could be confused with a segment "i18n" from Shared', - location: { path: joinFromRoot('features', 'i18n') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'i18n') }, }, { message: `Slice "${join('test', 'store')}" could be confused with a segment "store" from Shared`, - location: { path: joinFromRoot('features', 'test', 'store') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'test', 'store') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/excessive-slicing/index.spec.ts b/packages/steiger-plugin-fsd/src/excessive-slicing/index.spec.ts index 5e0ae1b3..abb1479d 100644 --- a/packages/steiger-plugin-fsd/src/excessive-slicing/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/excessive-slicing/index.spec.ts @@ -4,7 +4,8 @@ import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/tool import excessiveSlicing from './index.js' it('reports no errors on projects with moderate slicing', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -16,7 +17,9 @@ it('reports no errors on projects with moderate slicing', () => { 📂 ui 📄 index.ts 📄 Button.tsx - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const { diagnostics } = excessiveSlicing.check(root) @@ -24,7 +27,8 @@ it('reports no errors on projects with moderate slicing', () => { }) it('reports errors on a project with an excessive amount of features', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -106,13 +110,15 @@ it('reports errors on a project with an excessive amount of features', () => { 📂 bitcoin 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const { diagnostics } = excessiveSlicing.check(root) expect(diagnostics).toEqual([ { - location: { path: joinFromRoot('features') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features') }, message: 'Layer "features" has 23 ungrouped slices, which is above the recommended threshold of 20. Consider grouping them or moving the code inside to the layer where it\'s used.', }, @@ -120,7 +126,8 @@ it('reports errors on a project with an excessive amount of features', () => { }) it('works with slice groups', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -206,13 +213,15 @@ it('works with slice groups', () => { 📂 bitcoin 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const { diagnostics } = excessiveSlicing.check(root) expect(diagnostics).toEqual([ { - location: { path: joinFromRoot('features', 'junk') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'junk') }, message: 'Slice group "junk" has 23 slices, which is above the recommended threshold of 20. Consider grouping them or moving the code inside to the layer where it\'s used.', }, diff --git a/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts b/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts index dbedd802..80a856f3 100644 --- a/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts @@ -12,7 +12,7 @@ vi.mock('tsconfck', async (importOriginal) => { compilerOptions: { baseUrl: '/src/', paths: { - '@/*': ['./*'], + '@/*': ['/users/user/project/src/*'], }, }, }, @@ -27,31 +27,34 @@ vi.mock('node:fs', async (importOriginal) => { return createFsMocks( { - '/src/shared/ui/styles.ts': '', - '/src/shared/ui/Button.tsx': 'import styles from "./styles";', - '/src/shared/ui/TextField.tsx': 'import styles from "./styles";', - '/src/shared/ui/index.ts': '', - '/src/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"', - '/src/entities/user/index.ts': '', - '/src/entities/user/@x/product.ts': '', - '/src/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"', - '/src/entities/product/ui/GoodProductCard.tsx': 'import { UserAvatar } from "@/entities/user/@x/product"', - '/src/entities/product/index.ts': '', - '/src/entities/cart/ui/SmallCart.tsx': 'import { App } from "@/app"', - '/src/entities/cart/ui/BadSmallCart.tsx': 'import { UserAvatar } from "@/entities/user/@x/product"', - '/src/entities/cart/lib/count-cart-items.ts': 'import root from "@/app/root.ts"', - '/src/entities/cart/lib/index.ts': '', - '/src/entities/cart/index.ts': '', - '/src/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"', - '/src/features/comments/index.ts': '', - '/src/pages/editor/ui/styles.ts': '', - '/src/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"', - '/src/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"', - '/src/pages/editor/index.ts': '', - '/src/app': '', - '/src/app/ui/index.ts': '', - '/src/app/index.ts': '', - '/src/app/root.ts': '', + '/users/user/project/src/shared/ui/styles.ts': '', + '/users/user/project/src/shared/ui/Button.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/TextField.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/index.ts': '', + '/users/user/project/src/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"', + '/users/user/project/src/entities/user/index.ts': '', + '/users/user/project/src/entities/user/@x/product.ts': '', + '/users/user/project/src/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"', + '/users/user/project/src/entities/product/ui/GoodProductCard.tsx': + 'import { UserAvatar } from "@/entities/user/@x/product"', + '/users/user/project/src/entities/product/index.ts': '', + '/users/user/project/src/entities/cart/ui/SmallCart.tsx': 'import { App } from "@/app"', + '/users/user/project/src/entities/cart/ui/BadSmallCart.tsx': + 'import { UserAvatar } from "@/entities/user/@x/product"', + '/users/user/project/src/entities/cart/lib/count-cart-items.ts': 'import root from "@/app/root.ts"', + '/users/user/project/src/entities/cart/lib/index.ts': '', + '/users/user/project/src/entities/cart/index.ts': '', + '/users/user/project/src/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"', + '/users/user/project/src/features/comments/index.ts': '', + '/users/user/project/src/pages/editor/ui/styles.ts': '', + '/users/user/project/src/pages/editor/ui/EditorPage.tsx': + 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"', + '/users/user/project/src/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"', + '/users/user/project/src/pages/editor/index.ts': '', + '/users/user/project/src/app': '', + '/users/user/project/src/app/ui/index.ts': '', + '/users/user/project/src/app/index.ts': '', + '/users/user/project/src/app/root.ts': '', }, originalFs, ) @@ -73,7 +76,7 @@ it('reports no errors on a project with only correct imports', async () => { 📄 Editor.tsx 📄 index.ts `, - joinFromRoot('src'), + joinFromRoot('users', 'user', 'project', 'src'), ) expect((await forbiddenImports.check(root)).diagnostics).toEqual([]) @@ -104,13 +107,15 @@ it('reports errors on a project with cross-imports in entities', async () => { 📄 Editor.tsx 📄 index.ts `, - joinFromRoot('src'), + joinFromRoot('users', 'user', 'project', 'src'), ) expect((await forbiddenImports.check(root)).diagnostics).toEqual([ { message: `Forbidden cross-import from slice "user".`, - location: { path: joinFromRoot('src', 'entities', 'product', 'ui', 'ProductCard.tsx') }, + location: { + path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'product', 'ui', 'ProductCard.tsx'), + }, }, ]) }) @@ -137,13 +142,15 @@ it('reports errors on a project where a feature imports from a page', async () = 📄 Editor.tsx 📄 index.ts `, - joinFromRoot('src'), + joinFromRoot('users', 'user', 'project', 'src'), ) expect((await forbiddenImports.check(root)).diagnostics.sort()).toEqual([ { message: `Forbidden import from higher layer "pages".`, - location: { path: joinFromRoot('src', 'features', 'comments', 'ui', 'CommentCard.tsx') }, + location: { + path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'ui', 'CommentCard.tsx'), + }, }, ]) }) @@ -178,18 +185,20 @@ it('reports errors on a project where a lower level imports from files that are 📄 index.ts 📄 root.ts `, - joinFromRoot('src'), + joinFromRoot('users', 'user', 'project', 'src'), ) const diagnostics = (await forbiddenImports.check(root)).diagnostics expect(diagnostics).toEqual([ { message: `Forbidden import from higher layer "app".`, - location: { path: joinFromRoot('src', 'entities', 'cart', 'lib', 'count-cart-items.ts') }, + location: { + path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'cart', 'lib', 'count-cart-items.ts'), + }, }, { message: `Forbidden import from higher layer "app".`, - location: { path: joinFromRoot('src', 'entities', 'cart', 'ui', 'SmallCart.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'cart', 'ui', 'SmallCart.tsx') }, }, ]) }) @@ -221,7 +230,7 @@ it('reports no errors on a project with cross-imports through @x', async () => { 📄 Editor.tsx 📄 index.ts `, - joinFromRoot('src'), + joinFromRoot('users', 'user', 'project', 'src'), ) expect((await forbiddenImports.check(root)).diagnostics).toEqual([]) @@ -258,13 +267,13 @@ it('reports errors on a project with incorrect cross-imports through @x', async 📄 Editor.tsx 📄 index.ts `, - joinFromRoot('src'), + joinFromRoot('users', 'user', 'project', 'src'), ) expect((await forbiddenImports.check(root)).diagnostics).toEqual([ { message: `Forbidden cross-import from slice "user".`, - location: { path: joinFromRoot('src', 'entities', 'cart', 'ui', 'BadSmallCart.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'cart', 'ui', 'BadSmallCart.tsx') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/import-locality/index.spec.ts b/packages/steiger-plugin-fsd/src/import-locality/index.spec.ts index 8a25fa80..ce76d4ba 100644 --- a/packages/steiger-plugin-fsd/src/import-locality/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/import-locality/index.spec.ts @@ -6,7 +6,9 @@ import importLocality from './index.js' vi.mock('tsconfck', async (importOriginal) => { return { ...(await importOriginal()), - parse: vi.fn(() => Promise.resolve({ tsconfig: { compilerOptions: { paths: { '@/*': ['/*'] } } } })), + parse: vi.fn(() => + Promise.resolve({ tsconfig: { compilerOptions: { paths: { '@/*': ['/users/user/project/src/*'] } } } }), + ), } }) @@ -16,28 +18,31 @@ vi.mock('node:fs', async (importOriginal) => { return createFsMocks( { - '/shared/ui/styles.ts': '', - '/shared/ui/Button.tsx': 'import styles from "./styles";', - '/shared/ui/TextField.tsx': 'import styles from "./styles";', - '/shared/ui/index.ts': '', - '/entities/user/ui/Name.tsx': 'import { Button } from "@/shared/ui"', - '/entities/user/ui/Status.tsx': 'import { Button } from "@/shared/ui"; import { Name } from "@/entities/user"', - '/entities/user/ui/UserAvatar.tsx': + '/users/user/project/src/shared/ui/styles.ts': '', + '/users/user/project/src/shared/ui/Button.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/TextField.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/index.ts': '', + '/users/user/project/src/entities/user/ui/Name.tsx': 'import { Button } from "@/shared/ui"', + '/users/user/project/src/entities/user/ui/Status.tsx': + 'import { Button } from "@/shared/ui"; import { Name } from "@/entities/user"', + '/users/user/project/src/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"; import { Name } from "@/entities/user/ui/Name"', - '/entities/user/index.ts': '', - '/features/comments/ui/CommentCard.tsx': 'import { Name } from "../../../entities/user"', - '/features/comments/index.ts': '', - '/pages/editor/ui/styles.ts': '', - '/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"', - '/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"', - '/pages/editor/index.ts': '', + '/users/user/project/src/entities/user/index.ts': '', + '/users/user/project/src/features/comments/ui/CommentCard.tsx': 'import { Name } from "../../../entities/user"', + '/users/user/project/src/features/comments/index.ts': '', + '/users/user/project/src/pages/editor/ui/styles.ts': '', + '/users/user/project/src/pages/editor/ui/EditorPage.tsx': + 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"', + '/users/user/project/src/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"', + '/users/user/project/src/pages/editor/index.ts': '', }, originalFs, ) }) it('reports no errors on a project with relative imports within slices and absolute imports outside', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -50,13 +55,16 @@ it('reports no errors on a project with relative imports within slices and absol 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await importLocality.check(root)).diagnostics).toEqual([]) }) it('reports errors on a project with absolute imports within a slice', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -75,18 +83,21 @@ it('reports errors on a project with absolute imports within a slice', async () 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await importLocality.check(root)).diagnostics).toEqual([ { message: `Import from "@/entities/user/ui/Name" should be relative.`, - location: { path: joinFromRoot('entities', 'user', 'ui', 'UserAvatar.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user', 'ui', 'UserAvatar.tsx') }, }, ]) }) it('reports errors on a project with absolute imports from the index within a slice', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -105,18 +116,21 @@ it('reports errors on a project with absolute imports from the index within a sl 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await importLocality.check(root)).diagnostics).toEqual([ { message: `Import from "@/entities/user" should be relative.`, - location: { path: joinFromRoot('entities', 'user', 'ui', 'Status.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user', 'ui', 'Status.tsx') }, }, ]) }) it('reports errors on a project with relative imports between slices', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -139,12 +153,16 @@ it('reports errors on a project with relative imports between slices', async () 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await importLocality.check(root)).diagnostics).toEqual([ { message: `Import from "../../../entities/user" should not be relative.`, - location: { path: joinFromRoot('features', 'comments', 'ui', 'CommentCard.tsx') }, + location: { + path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'ui', 'CommentCard.tsx'), + }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/inconsistent-naming/index.spec.ts b/packages/steiger-plugin-fsd/src/inconsistent-naming/index.spec.ts index 60aec51c..5bfed103 100644 --- a/packages/steiger-plugin-fsd/src/inconsistent-naming/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/inconsistent-naming/index.spec.ts @@ -4,7 +4,8 @@ import { compareMessages, joinFromRoot, parseIntoFolder as parseIntoFsdRoot } fr import inconsistentNaming from './index.js' it('reports no errors on slice names that are pluralized consistently', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -12,13 +13,16 @@ it('reports no errors on slice names that are pluralized consistently', () => { 📂 posts 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(inconsistentNaming.check(root)).toEqual({ diagnostics: [] }) }) it('reports an error on slice names that are not pluralized consistently', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 user 📂 ui @@ -26,7 +30,9 @@ it('reports an error on slice names that are not pluralized consistently', () => 📂 posts 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = inconsistentNaming.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ @@ -35,17 +41,18 @@ it('reports an error on slice names that are not pluralized consistently', () => fixes: [ { type: 'rename', - path: joinFromRoot('entities', 'user'), + path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user'), newName: 'users', }, ], - location: { path: joinFromRoot('entities') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities') }, }, ]) }) it('prefers the singular form when there are more singular slices', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 user 📂 ui @@ -56,7 +63,9 @@ it('prefers the singular form when there are more singular slices', () => { 📂 comments 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = inconsistentNaming.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ @@ -65,11 +74,11 @@ it('prefers the singular form when there are more singular slices', () => { fixes: [ { type: 'rename', - path: joinFromRoot('entities', 'comments'), + path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'comments'), newName: 'comment', }, ], - location: { path: joinFromRoot('entities') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/insignificant-slice/index.spec.ts b/packages/steiger-plugin-fsd/src/insignificant-slice/index.spec.ts index 3350db7e..12ba280c 100644 --- a/packages/steiger-plugin-fsd/src/insignificant-slice/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/insignificant-slice/index.spec.ts @@ -7,7 +7,9 @@ import insignificantSlice from './index.js' vi.mock('tsconfck', async (importOriginal) => { return { ...(await importOriginal()), - parse: vi.fn(() => Promise.resolve({ tsconfig: { compilerOptions: { paths: { '@/*': ['/*'] } } } })), + parse: vi.fn(() => + Promise.resolve({ tsconfig: { compilerOptions: { paths: { '@/*': ['/users/user/project/src/*'] } } } }), + ), } }) @@ -17,39 +19,41 @@ vi.mock('node:fs', async (importOriginal) => { return createFsMocks( { - '/shared/ui/styles.ts': '', - '/shared/ui/Button.tsx': 'import styles from "./styles";', - '/shared/ui/TextField.tsx': 'import styles from "./styles";', - '/shared/ui/index.ts': '', + '/users/user/project/src/shared/ui/styles.ts': '', + '/users/user/project/src/shared/ui/Button.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/TextField.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/index.ts': '', - '/entities/user/@x/product.ts': '', - '/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"', - '/entities/user/index.ts': '', - '/entities/product/ui/ProductCard.tsx': '', - '/entities/product/ui/CrossReferenceCard.tsx': 'import { UserAvatar } from "@/entities/user/@x/product"', - '/entities/product/index.ts': '', - '/entities/post/index.ts': '', + '/users/user/project/src/entities/user/@x/product.ts': '', + '/users/user/project/src/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"', + '/users/user/project/src/entities/user/index.ts': '', + '/users/user/project/src/entities/product/ui/ProductCard.tsx': '', + '/users/user/project/src/entities/product/ui/CrossReferenceCard.tsx': + 'import { UserAvatar } from "@/entities/user/@x/product"', + '/users/user/project/src/entities/product/index.ts': '', + '/users/user/project/src/entities/post/index.ts': '', - '/features/comments/ui/CommentCard.tsx': '', - '/features/comments/index.ts': '', + '/users/user/project/src/features/comments/ui/CommentCard.tsx': '', + '/users/user/project/src/features/comments/index.ts': '', - '/pages/editor/ui/EditorPage.tsx': + '/users/user/project/src/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"; import { CommentCard } from "@/features/comments"; import { UserAvatar } from "@/entities/user"', - '/pages/editor/ui/Editor.tsx': + '/users/user/project/src/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"; import { UserAvatar } from "@/entities/user"', - '/pages/editor/index.ts': '', - '/pages/settings/ui/SettingsPage.tsx': + '/users/user/project/src/pages/editor/index.ts': '', + '/users/user/project/src/pages/settings/ui/SettingsPage.tsx': 'import { Button } from "@/shared/ui"; import { CommentCard } from "@/features/comments"', - '/pages/settings/index.ts': '', - '/pages/home/index.ts': '', - '/pages/category/index.ts': '', + '/users/user/project/src/pages/settings/index.ts': '', + '/users/user/project/src/pages/home/index.ts': '', + '/users/user/project/src/pages/category/index.ts': '', }, originalFs, ) }) it('reports no errors on a project with slices only on the Pages layer', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -62,13 +66,16 @@ it('reports no errors on a project with slices only on the Pages layer', async ( 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await insignificantSlice.check(root)).diagnostics).toEqual([]) }) it('reports no errors on a project with no insignificant slices', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -90,13 +97,16 @@ it('reports no errors on a project with no insignificant slices', async () => { 📂 ui 📄 SettingsPage.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await insignificantSlice.check(root)).diagnostics).toEqual([]) }) it('reports errors on a project with insignificant slices', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -127,22 +137,25 @@ it('reports errors on a project with insignificant slices', async () => { 📂 ui 📄 SettingsPage.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await insignificantSlice.check(root)).diagnostics.sort(compareMessages)).toEqual([ { message: `This slice has no references. Consider removing it.`, - location: { path: joinFromRoot('entities', 'product') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'product') }, }, { message: `This slice has only one reference in slice "${join('pages', 'editor')}". Consider merging them.`, - location: { path: joinFromRoot('entities', 'user') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user') }, }, ]) }) it('reports errors on a project where the only other reference to a slice is a cross-import', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 user 📂 @x @@ -160,16 +173,18 @@ it('reports errors on a project where the only other reference to a slice is a c 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await insignificantSlice.check(root)).diagnostics.sort(compareMessages)).toEqual([ { message: `This slice has no references. Consider removing it.`, - location: { path: joinFromRoot('entities', 'product') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'product') }, }, { message: `This slice has only one reference in slice "${join('pages', 'editor')}". Consider merging them.`, - location: { path: joinFromRoot('entities', 'user') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-file-segments/index.spec.ts b/packages/steiger-plugin-fsd/src/no-file-segments/index.spec.ts index 925b26bb..95a492e4 100644 --- a/packages/steiger-plugin-fsd/src/no-file-segments/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-file-segments/index.spec.ts @@ -4,7 +4,8 @@ import { compareMessages, joinFromRoot, parseIntoFolder as parseIntoFsdRoot } fr import noFileSegments from './index.js' it('reports no errors on a project with only folder segments', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -17,13 +18,16 @@ it('reports no errors on a project with only folder segments', async () => { 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noFileSegments.check(root).diagnostics).toEqual([]) }) it('reports no errors on a project with folder segments on sliced layers', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -42,22 +46,25 @@ it('reports no errors on a project with folder segments on sliced layers', async 📂 ui 📄 SettingsPage.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noFileSegments.check(root).diagnostics).toEqual([ { message: 'This segment is a file. Prefer folder segments.', - location: { path: joinFromRoot('features', 'comments', 'ui.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'comments', 'ui.tsx') }, }, { message: 'This segment is a file. Prefer folder segments.', - location: { path: joinFromRoot('pages', 'editor', 'ui.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui.tsx') }, }, ]) }) it('reports errors on a project with folder segments in Shared', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📄 routes.ts 📂 ui @@ -89,12 +96,14 @@ it('reports errors on a project with folder segments in Shared', async () => { 📂 ui 📄 SettingsPage.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noFileSegments.check(root).diagnostics.sort(compareMessages)).toEqual([ { message: 'This segment is a file. Prefer folder segments.', - location: { path: joinFromRoot('shared', 'routes.ts') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'routes.ts') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-layer-public-api/index.spec.ts b/packages/steiger-plugin-fsd/src/no-layer-public-api/index.spec.ts index 617b5065..a742dce0 100644 --- a/packages/steiger-plugin-fsd/src/no-layer-public-api/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-layer-public-api/index.spec.ts @@ -4,7 +4,8 @@ import noLayerPublicApi from './index.js' import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project without index files on layer level', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -19,13 +20,16 @@ it('reports no errors on a project without index files on layer level', () => { 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noLayerPublicApi.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with index files on layer level', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -46,11 +50,19 @@ it('reports errors on a project with index files on layer level', () => { 📂 ui 📄 index.ts 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = noLayerPublicApi.check(root).diagnostics expect(diagnostics).toEqual([ - { message: 'Layer "shared" should not have an index file', location: { path: joinFromRoot('shared', 'index.ts') } }, - { message: 'Layer "pages" should not have an index file', location: { path: joinFromRoot('pages', 'index.ts') } }, + { + message: 'Layer "shared" should not have an index file', + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'index.ts') }, + }, + { + message: 'Layer "pages" should not have an index file', + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'index.ts') }, + }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-processes/index.spec.ts b/packages/steiger-plugin-fsd/src/no-processes/index.spec.ts index b3a00907..27839e38 100644 --- a/packages/steiger-plugin-fsd/src/no-processes/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-processes/index.spec.ts @@ -4,7 +4,8 @@ import noProcesses from './index.js' import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project without the Processes layer', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -19,13 +20,16 @@ it('reports no errors on a project without the Processes layer', () => { 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noProcesses.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with the Processes layer', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -44,10 +48,15 @@ it('reports errors on a project with the Processes layer', () => { 📂 cart 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = noProcesses.check(root).diagnostics expect(diagnostics).toEqual([ - { message: 'Layer "processes" is deprecated, avoid using it', location: { path: joinFromRoot('processes') } }, + { + message: 'Layer "processes" is deprecated, avoid using it', + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'processes') }, + }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-public-api-sidestep/index.spec.ts b/packages/steiger-plugin-fsd/src/no-public-api-sidestep/index.spec.ts index 2fd0668c..4ca5f9fb 100644 --- a/packages/steiger-plugin-fsd/src/no-public-api-sidestep/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-public-api-sidestep/index.spec.ts @@ -6,7 +6,9 @@ import noPublicApiSidestep from './index.js' vi.mock('tsconfck', async (importOriginal) => { return { ...(await importOriginal()), - parse: vi.fn(() => Promise.resolve({ tsconfig: { compilerOptions: { paths: { '@/*': ['/*'] } } } })), + parse: vi.fn(() => + Promise.resolve({ tsconfig: { compilerOptions: { paths: { '@/*': ['/users/user/project/src/*'] } } } }), + ), } }) @@ -16,42 +18,46 @@ vi.mock('node:fs', async (importOriginal) => { return createFsMocks( { - '/shared/i18n/index.ts': '', - '/shared/i18n/translator.ts': '', - '/shared/ui/styles.ts': '', - '/shared/ui/Button.tsx': 'import styles from "./styles";', - '/shared/ui/TextField.tsx': 'import styles from "./styles";', - '/shared/ui/index.ts': '', - '/shared/lib/index.ts': '', - '/shared/lib/dates.ts': '', - '/shared/lib/i18n/index.ts': '', - '/shared/lib/i18n/translator.ts': '', - '/entities/user/@x/product.ts': '', - '/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"', - '/entities/user/index.ts': '', - '/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"', - '/entities/product/ui/CrossReferenceCard.tsx': 'import { UserAvatar } from "@/entities/user/@x/product"', - '/entities/product/index.ts': '', - '/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"', - '/features/comments/index.ts': '', - '/pages/editor/ui/styles.ts': '', - '/pages/editor/ui/EditorPage.tsx': 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"', - '/pages/editor/ui/Editor.tsx': + '/users/user/project/src/shared/i18n/index.ts': '', + '/users/user/project/src/shared/i18n/translator.ts': '', + '/users/user/project/src/shared/ui/styles.ts': '', + '/users/user/project/src/shared/ui/Button.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/TextField.tsx': 'import styles from "./styles";', + '/users/user/project/src/shared/ui/index.ts': '', + '/users/user/project/src/shared/lib/index.ts': '', + '/users/user/project/src/shared/lib/dates.ts': '', + '/users/user/project/src/shared/lib/i18n/index.ts': '', + '/users/user/project/src/shared/lib/i18n/translator.ts': '', + '/users/user/project/src/entities/user/@x/product.ts': '', + '/users/user/project/src/entities/user/ui/UserAvatar.tsx': 'import { Button } from "@/shared/ui"', + '/users/user/project/src/entities/user/index.ts': '', + '/users/user/project/src/entities/product/ui/ProductCard.tsx': 'import { UserAvatar } from "@/entities/user"', + '/users/user/project/src/entities/product/ui/CrossReferenceCard.tsx': + 'import { UserAvatar } from "@/entities/user/@x/product"', + '/users/user/project/src/entities/product/index.ts': '', + '/users/user/project/src/features/comments/ui/CommentCard.tsx': 'import { styles } from "@/pages/editor"', + '/users/user/project/src/features/comments/index.ts': '', + '/users/user/project/src/pages/editor/ui/styles.ts': '', + '/users/user/project/src/pages/editor/ui/EditorPage.tsx': + 'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"', + '/users/user/project/src/pages/editor/ui/Editor.tsx': 'import { TextField } from "@/shared/ui"; import { ProductCard } from "@/entities/product/ui/ProductCard.tsx"', - '/pages/editor/ui/SubmitButton.tsx': + '/users/user/project/src/pages/editor/ui/SubmitButton.tsx': 'import { Button } from "@/shared/ui/Button"; import { translator } from "@/shared/i18n/translator"', - '/pages/editor/index.ts': '', - '/pages/settings/index.ts': '', - '/pages/settings/ui/SettingsPage.tsx': + '/users/user/project/src/pages/editor/index.ts': '', + '/users/user/project/src/pages/settings/index.ts': '', + '/users/user/project/src/pages/settings/ui/SettingsPage.tsx': 'import { Button } from "@/shared/ui"; import { dates } from "@/shared/lib/dates"; import { translator } from "@/shared/lib/i18n"', - '/pages/settings/ui/Password.tsx': 'import { translator } from "@/shared/lib/i18n/translator";', + '/users/user/project/src/pages/settings/ui/Password.tsx': + 'import { translator } from "@/shared/lib/i18n/translator";', }, originalFs, ) }) it('reports no errors on a project without public API sidesteps', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -70,13 +76,16 @@ it('reports no errors on a project without public API sidesteps', async () => { 📄 ProductCard.tsx 📄 CrossReferenceCard.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await noPublicApiSidestep.check(root)).diagnostics).toEqual([]) }) it('reports errors on a project with a public API sidestep on entities', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -98,18 +107,21 @@ it('reports errors on a project with a public API sidestep on entities', async ( 📄 EditorPage.tsx 📄 Editor.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await noPublicApiSidestep.check(root)).diagnostics).toEqual([ { message: `Forbidden sidestep of public API when importing from "@/entities/product/ui/ProductCard.tsx".`, - location: { path: joinFromRoot('pages', 'editor', 'ui', 'Editor.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'Editor.tsx') }, }, ]) }) it('reports errors on a project with a public API sidestep on shared', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -125,19 +137,22 @@ it('reports errors on a project with a public API sidestep on shared', async () 📄 EditorPage.tsx 📄 SubmitButton.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await noPublicApiSidestep.check(root)).diagnostics).toEqual([ { message: `Forbidden sidestep of public API when importing from "@/shared/i18n/translator".`, - location: { path: joinFromRoot('pages', 'editor', 'ui', 'SubmitButton.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'ui', 'SubmitButton.tsx') }, }, ]) }) describe('specifics of shared/lib and shared/ui', () => { it('knows that imports from shared/lib must be one layer deeper', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 styles.ts @@ -154,13 +169,16 @@ describe('specifics of shared/lib and shared/ui', () => { 📂 ui 📄 SettingsPage.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await noPublicApiSidestep.check(root)).diagnostics).toEqual([]) }) it('still does not allow sidestepping the index of a single library', async () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 lib 📄 dates.ts @@ -173,12 +191,14 @@ describe('specifics of shared/lib and shared/ui', () => { 📄 SettingsPage.tsx 📄 Password.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect((await noPublicApiSidestep.check(root)).diagnostics).toEqual([ { message: `Forbidden sidestep of public API when importing from "@/shared/lib/i18n/translator".`, - location: { path: joinFromRoot('pages', 'settings', 'ui', 'Password.tsx') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'settings', 'ui', 'Password.tsx') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-reserved-folder-names/index.spec.ts b/packages/steiger-plugin-fsd/src/no-reserved-folder-names/index.spec.ts index 5551f451..491cd4ed 100644 --- a/packages/steiger-plugin-fsd/src/no-reserved-folder-names/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-reserved-folder-names/index.spec.ts @@ -4,7 +4,8 @@ import noReservedFolderNames from './index.js' import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project without subfolders in segments that use reserved names', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -19,13 +20,16 @@ it('reports no errors on a project without subfolders in segments that use reser 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noReservedFolderNames.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with subfolders in segments that use reserved names', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -42,19 +46,21 @@ it('reports errors on a project with subfolders in segments that use reserved na 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = noReservedFolderNames.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'Having a folder with the name "lib" inside a segment could be confusing because that name is commonly used for segments. Consider renaming it.', - location: { path: joinFromRoot('shared', 'ui', 'lib') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', 'lib') }, }, { message: 'Having a folder with the name "@x" inside a segment could be confusing because that name is reserved for cross-import public APIs. Consider renaming it.', - location: { path: joinFromRoot('shared', 'ui', '@x') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'ui', '@x') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-segmentless-slices/index.spec.ts b/packages/steiger-plugin-fsd/src/no-segmentless-slices/index.spec.ts index a12f7550..4319bedf 100644 --- a/packages/steiger-plugin-fsd/src/no-segmentless-slices/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-segmentless-slices/index.spec.ts @@ -4,7 +4,8 @@ import noSegmentlessSlices from './index.js' import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project where every slice has at least one segment', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -24,13 +25,16 @@ it('reports no errors on a project where every slice has at least one segment', 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noSegmentlessSlices.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project where some slices have no segments', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -48,17 +52,19 @@ it('reports errors on a project where some slices have no segments', () => { 📂 profile 📄 ProfilePage.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = noSegmentlessSlices.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'This slice has no segments. Consider dividing the code inside into segments.', - location: { path: joinFromRoot('entities', 'user') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user') }, }, { message: 'This slice has no segments. Consider dividing the code inside into segments.', - location: { path: joinFromRoot('pages', 'settings', 'profile') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'settings', 'profile') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-segments-on-sliced-layers/index.spec.ts b/packages/steiger-plugin-fsd/src/no-segments-on-sliced-layers/index.spec.ts index 00b911c9..d45f4b64 100644 --- a/packages/steiger-plugin-fsd/src/no-segments-on-sliced-layers/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-segments-on-sliced-layers/index.spec.ts @@ -5,7 +5,8 @@ import { compareMessages, joinFromRoot, parseIntoFolder as parseIntoFsdRoot } fr describe('no-segments-on-sliced-layers rule', () => { it('reports no errors on a project where the sliced layers has no segments in direct children', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -25,13 +26,16 @@ describe('no-segments-on-sliced-layers rule', () => { 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noSegmentsOnSlicedLayers.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project where a sliced layer has segments among its direct children', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -69,7 +73,9 @@ describe('no-segments-on-sliced-layers rule', () => { 📄 index.ts 📂 lib 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = noSegmentsOnSlicedLayers.check(root).diagnostics.sort(compareMessages) @@ -77,22 +83,22 @@ describe('no-segments-on-sliced-layers rule', () => { { message: 'Conventional segment "api" should not be a direct child of a sliced layer. Consider moving it inside a slice or, if that is a slice, consider a different name for it to avoid confusion with segments.', - location: { path: joinFromRoot('features', 'api') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'features', 'api') }, }, { message: 'Conventional segment "config" should not be a direct child of a sliced layer. Consider moving it inside a slice or, if that is a slice, consider a different name for it to avoid confusion with segments.', - location: { path: joinFromRoot('widgets', 'config') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'widgets', 'config') }, }, { message: 'Conventional segment "lib" should not be a direct child of a sliced layer. Consider moving it inside a slice or, if that is a slice, consider a different name for it to avoid confusion with segments.', - location: { path: joinFromRoot('pages', 'lib') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'lib') }, }, { message: 'Conventional segment "ui" should not be a direct child of a sliced layer. Consider moving it inside a slice or, if that is a slice, consider a different name for it to avoid confusion with segments.', - location: { path: joinFromRoot('entities', 'ui') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'ui') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/no-ui-in-app/index.spec.ts b/packages/steiger-plugin-fsd/src/no-ui-in-app/index.spec.ts index fd193138..f712f5ee 100644 --- a/packages/steiger-plugin-fsd/src/no-ui-in-app/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/no-ui-in-app/index.spec.ts @@ -4,7 +4,8 @@ import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/tool import noUiInApp from './index.js' it('reports no errors on a project without the "ui" segment on the "app" layer', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -15,13 +16,16 @@ it('reports no errors on a project without the "ui" segment on the "app" layer', 📂 app 📂 providers 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(noUiInApp.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with the "ui" segment on the "app" layer', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -34,13 +38,15 @@ it('reports errors on a project with the "ui" segment on the "app" layer', () => 📄 index.ts 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = noUiInApp.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'Layer "app" should not have "ui" segment.', - location: { path: joinFromRoot('app', 'ui') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'app', 'ui') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/public-api/index.spec.ts b/packages/steiger-plugin-fsd/src/public-api/index.spec.ts index e69e682c..659843a9 100644 --- a/packages/steiger-plugin-fsd/src/public-api/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/public-api/index.spec.ts @@ -4,7 +4,8 @@ import publicApi from './index.js' import { compareMessages, joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project with all the required public APIs', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -22,13 +23,16 @@ it('reports no errors on a project with all the required public APIs', () => { 📂 pages 📂 editor 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(publicApi.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on slices that are missing a public API', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -45,7 +49,9 @@ it('reports errors on slices that are missing a public API', () => { 📂 pages 📂 editor 📂 ui - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = publicApi.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ @@ -54,28 +60,29 @@ it('reports errors on slices that are missing a public API', () => { fixes: [ { type: 'create-file', - path: joinFromRoot('entities', 'posts', 'index.js'), + path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'posts', 'index.js'), content: '', }, ], - location: { path: joinFromRoot('entities', 'posts') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'posts') }, }, { message: 'This slice is missing a public API.', fixes: [ { type: 'create-file', - path: joinFromRoot('pages', 'editor', 'index.js'), + path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor', 'index.js'), content: '', }, ], - location: { path: joinFromRoot('pages', 'editor') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'editor') }, }, ]) }) it('reports errors on segments that are missing a public API', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 button.ts @@ -99,7 +106,9 @@ it('reports errors on segments that are missing a public API', () => { 📂 app 📂 providers 📂 styles - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = publicApi.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ @@ -108,17 +117,18 @@ it('reports errors on segments that are missing a public API', () => { fixes: [ { type: 'create-file', - path: joinFromRoot('shared', 'config', 'index.js'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'config', 'index.js'), content: '', }, ], - location: { path: joinFromRoot('shared', 'config') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'config') }, }, ]) }) it('reports errors on top-level folders in shared/lib and shared/ui that are missing a public API', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -128,7 +138,9 @@ it('reports errors on top-level folders in shared/lib and shared/ui that are mis 📂 dates 📄 index.ts 📂 arrays - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = publicApi.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ @@ -136,12 +148,12 @@ it('reports errors on top-level folders in shared/lib and shared/ui that are mis fixes: [ { content: '', - path: joinFromRoot('shared', 'lib', 'arrays', 'index.js'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'lib', 'arrays', 'index.js'), type: 'create-file', }, ], location: { - path: joinFromRoot('shared', 'lib', 'arrays'), + path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'lib', 'arrays'), }, message: 'This top-level folder in shared/lib is missing a public API.', }, diff --git a/packages/steiger-plugin-fsd/src/repetitive-naming/index.spec.ts b/packages/steiger-plugin-fsd/src/repetitive-naming/index.spec.ts index 94bd700c..2e0d8a59 100644 --- a/packages/steiger-plugin-fsd/src/repetitive-naming/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/repetitive-naming/index.spec.ts @@ -4,7 +4,8 @@ import repetitiveNaming from './index.js' import { compareMessages, joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project with no repetitive words in slices', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 pages 📂 home 📂 ui @@ -15,13 +16,16 @@ it('reports no errors on a project with no repetitive words in slices', () => { 📂 contact 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(repetitiveNaming.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with repetition of "page"', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 pages 📂 homePage 📂 ui @@ -32,16 +36,22 @@ it('reports errors on a project with repetition of "page"', () => { 📂 contactPage 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = repetitiveNaming.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ - { message: 'Repetitive word "page" in slice names.', location: { path: joinFromRoot('pages') } }, + { + message: 'Repetitive word "page" in slice names.', + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'pages') }, + }, ]) }) it('recognizes words in different naming conventions', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 ClientFolder 📂 ui @@ -52,16 +62,22 @@ it('recognizes words in different naming conventions', () => { 📂 service_folder 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = repetitiveNaming.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ - { message: 'Repetitive word "folder" in slice names.', location: { path: joinFromRoot('entities') } }, + { + message: 'Repetitive word "folder" in slice names.', + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities') }, + }, ]) }) it('does not complain about layers with just one slice', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 pages 📂 create-post 📂 ui @@ -88,13 +104,16 @@ it('does not complain about layers with just one slice', () => { 📂 ui 📄 index.tsx 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(repetitiveNaming.check(root)).toEqual({ diagnostics: [] }) }) it('does not treat slice groups as repetitive words', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 features 📂 session 📂 login @@ -109,13 +128,16 @@ it('does not treat slice groups as repetitive words', () => { 📂 api 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(repetitiveNaming.check(root)).toEqual({ diagnostics: [] }) }) it('still recognizes repetitive words inside slice groups', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 pages 📂 login-word 📂 api @@ -139,13 +161,15 @@ it('still recognizes repetitive words inside slice groups', () => { 📂 api 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(repetitiveNaming.check(root)).toEqual({ diagnostics: [ { location: { - path: joinFromRoot('pages', 'group', 'session'), + path: joinFromRoot('users', 'user', 'project', 'src', 'pages', 'group', 'session'), }, message: 'Repetitive word "word" in slice names.', }, diff --git a/packages/steiger-plugin-fsd/src/segments-by-purpose/index.spec.ts b/packages/steiger-plugin-fsd/src/segments-by-purpose/index.spec.ts index a76a5b61..b0a695c9 100644 --- a/packages/steiger-plugin-fsd/src/segments-by-purpose/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/segments-by-purpose/index.spec.ts @@ -4,7 +4,8 @@ import segmentsByPurpose from './index.js' import { compareMessages, joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/toolkit' it('reports no errors on a project with good segments', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -19,13 +20,16 @@ it('reports no errors on a project with good segments', () => { 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(segmentsByPurpose.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with bad segments', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 ui 📄 index.ts @@ -46,29 +50,31 @@ it('reports errors on a project with bad segments', () => { 📂 home 📂 ui 📄 index.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = segmentsByPurpose.check(root).diagnostics.sort(compareMessages) expect(diagnostics).toEqual([ { message: "This segment's name should describe the purpose of its contents, not what the contents are.", - location: { path: joinFromRoot('entities', 'user', 'components') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entities', 'user', 'components') }, }, { message: "This segment's name should describe the purpose of its contents, not what the contents are.", - location: { path: joinFromRoot('shared', 'helpers') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'helpers') }, }, { message: "This segment's name should describe the purpose of its contents, not what the contents are.", - location: { path: joinFromRoot('shared', 'hooks') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'hooks') }, }, { message: "This segment's name should describe the purpose of its contents, not what the contents are.", - location: { path: joinFromRoot('shared', 'modals') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'modals') }, }, { message: "This segment's name should describe the purpose of its contents, not what the contents are.", - location: { path: joinFromRoot('shared', 'utils') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'utils') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/shared-lib-grouping/index.spec.ts b/packages/steiger-plugin-fsd/src/shared-lib-grouping/index.spec.ts index 791d2b68..37ec76d1 100644 --- a/packages/steiger-plugin-fsd/src/shared-lib-grouping/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/shared-lib-grouping/index.spec.ts @@ -4,7 +4,8 @@ import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/tool import excessiveSlicing from './index.js' it('reports no errors on projects with no shared/lib', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -16,7 +17,9 @@ it('reports no errors on projects with no shared/lib', () => { 📂 ui 📄 index.ts 📄 Button.tsx - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const { diagnostics } = excessiveSlicing.check(root) @@ -24,7 +27,8 @@ it('reports no errors on projects with no shared/lib', () => { }) it('reports no errors on projects with shared/lib below threshold', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -40,7 +44,9 @@ it('reports no errors on projects with shared/lib below threshold', () => { 📄 index.ts 📄 dates.ts 📄 collections.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const { diagnostics } = excessiveSlicing.check(root) @@ -48,7 +54,8 @@ it('reports no errors on projects with shared/lib below threshold', () => { }) it('reports errors on a project with shared/lib above threshold', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 entities 📂 users 📂 ui @@ -80,14 +87,16 @@ it('reports errors on a project with shared/lib above threshold', () => { 📄 is.ts 📄 other.ts 📄 people.ts - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const { diagnostics } = excessiveSlicing.check(root) expect(diagnostics).toEqual([ { message: 'Shared/lib has 19 modules, which is above the recommended threshold of 15. Consider grouping them.', - location: { path: joinFromRoot('shared', 'lib') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shared', 'lib') }, }, ]) }) diff --git a/packages/steiger-plugin-fsd/src/typo-in-layer-name/index.spec.ts b/packages/steiger-plugin-fsd/src/typo-in-layer-name/index.spec.ts index 181e07a1..111e2f56 100644 --- a/packages/steiger-plugin-fsd/src/typo-in-layer-name/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/typo-in-layer-name/index.spec.ts @@ -4,51 +4,58 @@ import { joinFromRoot, parseIntoFolder as parseIntoFsdRoot } from '@steiger/tool import typoInLayerName from './index.js' it('reports no errors on a project without typos in layer names', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 entities 📂 features 📂 widgets 📂 pages 📂 app - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(typoInLayerName.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with typos in layer names', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shraed 📂 entities 📂 fietures 📂 wigdets 📂 page 📂 app - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = typoInLayerName.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'Layer "page" potentially contains a typo. Did you mean "pages"?', - location: { path: joinFromRoot('page') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'page') }, }, { message: 'Layer "shraed" potentially contains a typo. Did you mean "shared"?', - location: { path: joinFromRoot('shraed') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shraed') }, }, { message: 'Layer "fietures" potentially contains a typo. Did you mean "features"?', - location: { path: joinFromRoot('fietures') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'fietures') }, }, { message: 'Layer "wigdets" potentially contains a typo. Did you mean "widgets"?', - location: { path: joinFromRoot('wigdets') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'wigdets') }, }, ]) }) it('reports no errors on a project with custom layers if base layers are present', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shared 📂 shapes 📂 entities @@ -60,41 +67,46 @@ it('reports no errors on a project with custom layers if base layers are present 📂 places 📂 app 📂 amp - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) expect(typoInLayerName.check(root)).toEqual({ diagnostics: [] }) }) it('reports errors on a project with custom layers if base layers are absent', () => { - const root = parseIntoFsdRoot(` + const root = parseIntoFsdRoot( + ` 📂 shapes 📂 entries 📂 fixtures 📂 places 📂 amp - `) + `, + joinFromRoot('users', 'user', 'project', 'src'), + ) const diagnostics = typoInLayerName.check(root).diagnostics expect(diagnostics).toEqual([ { message: 'Layer "amp" potentially contains a typo. Did you mean "app"?', - location: { path: joinFromRoot('amp') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'amp') }, }, { message: 'Layer "shapes" potentially contains a typo. Did you mean "shared"?', - location: { path: joinFromRoot('shapes') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'shapes') }, }, { message: 'Layer "entries" potentially contains a typo. Did you mean "entities"?', - location: { path: joinFromRoot('entries') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'entries') }, }, { message: 'Layer "fixtures" potentially contains a typo. Did you mean "features"?', - location: { path: joinFromRoot('fixtures') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'fixtures') }, }, { message: 'Layer "places" potentially contains a typo. Did you mean "pages"?', - location: { path: joinFromRoot('places') }, + location: { path: joinFromRoot('users', 'user', 'project', 'src', 'places') }, }, ]) }) From e749ec716d5e289f8b63dd78be65e9db2f1a7df9 Mon Sep 17 00:00:00 2001 From: Daniil Sapa Date: Mon, 30 Dec 2024 23:13:32 +0200 Subject: [PATCH 2/3] Add a changelog --- .changeset/eighty-steaks-grow.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eighty-steaks-grow.md diff --git a/.changeset/eighty-steaks-grow.md b/.changeset/eighty-steaks-grow.md new file mode 100644 index 00000000..a85943f4 --- /dev/null +++ b/.changeset/eighty-steaks-grow.md @@ -0,0 +1,5 @@ +--- +'@feature-sliced/steiger-plugin': patch +--- + +Refactor test cases to nest FSD roots From ff01e6d955a2bcaff2eaa70002a56e2aa491206c Mon Sep 17 00:00:00 2001 From: Daniil Sapa Date: Thu, 2 Jan 2025 16:08:26 +0200 Subject: [PATCH 3/3] Fix tsconfig in test cases for forbidden-imports rule --- .../steiger-plugin-fsd/src/forbidden-imports/index.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts b/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts index 80a856f3..09c70aba 100644 --- a/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts +++ b/packages/steiger-plugin-fsd/src/forbidden-imports/index.spec.ts @@ -10,9 +10,9 @@ vi.mock('tsconfck', async (importOriginal) => { Promise.resolve({ tsconfig: { compilerOptions: { - baseUrl: '/src/', + baseUrl: '/users/user/project/src/', paths: { - '@/*': ['/users/user/project/src/*'], + '@/*': ['./*'], }, }, },