@archest/vitest 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +1 -13
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +44 -764
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/matchers/index.d.ts +21 -0
  7. package/dist/matchers/models.d.ts +201 -0
  8. package/node_modules/@archest/core/dist/classes/locateClasses.d.ts +5 -0
  9. package/node_modules/@archest/core/dist/classes/types.d.ts +25 -0
  10. package/node_modules/@archest/core/dist/dto.d.ts +78 -0
  11. package/node_modules/@archest/core/dist/files/checkDependOnExternalModule.d.ts +3 -0
  12. package/node_modules/@archest/core/dist/files/getFileDependencies.d.ts +2 -0
  13. package/node_modules/@archest/core/dist/files/locateFiles.d.ts +4 -0
  14. package/node_modules/@archest/core/dist/files/types.d.ts +17 -0
  15. package/node_modules/@archest/core/dist/functions/locateFunctions.d.ts +5 -0
  16. package/node_modules/@archest/core/dist/functions/types.d.ts +19 -0
  17. package/node_modules/@archest/core/dist/index.d.ts +43 -0
  18. package/node_modules/@archest/core/dist/index.js +14 -0
  19. package/node_modules/@archest/core/dist/index.js.map +1 -0
  20. package/node_modules/@archest/core/dist/index.mjs +615 -0
  21. package/node_modules/@archest/core/dist/index.mjs.map +1 -0
  22. package/node_modules/@archest/core/dist/layers/createLayeredArchitecture.d.ts +3 -0
  23. package/node_modules/@archest/core/dist/layers/getLayerDependencies.d.ts +2 -0
  24. package/node_modules/@archest/core/dist/layers/types.d.ts +8 -0
  25. package/node_modules/@archest/core/dist/project/parseProject.d.ts +55 -0
  26. package/node_modules/@archest/core/dist/properties/locateProperties.d.ts +5 -0
  27. package/node_modules/@archest/core/dist/properties/types.d.ts +17 -0
  28. package/node_modules/@archest/core/dist/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +1 -0
  29. package/node_modules/@archest/core/dist/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +1 -0
  30. package/node_modules/@archest/core/dist/shared/sharedCheckHaveModifier.d.ts +7 -0
  31. package/node_modules/@archest/core/dist/shared/sharedCheckHaveNameMatchingFileName.d.ts +3 -0
  32. package/node_modules/@archest/core/dist/shared/sharedCheckMatchNamePattern.d.ts +1 -0
  33. package/node_modules/@archest/core/dist/slices/locateSlices.d.ts +3 -0
  34. package/node_modules/@archest/core/dist/slices/types.d.ts +8 -0
  35. package/node_modules/@archest/core/package.json +49 -0
  36. package/node_modules/@archest/core-rust/core-rust.darwin-arm64.node +0 -0
  37. package/node_modules/@archest/core-rust/core-rust.linux-x64-gnu.node +0 -0
  38. package/node_modules/@archest/core-rust/core-rust.win32-x64-msvc.node +0 -0
  39. package/node_modules/@archest/core-rust/index.d.ts +16 -0
  40. package/node_modules/@archest/core-rust/index.js +316 -0
  41. package/node_modules/@archest/core-rust/package.json +34 -0
  42. package/package.json +12 -1
  43. package/dist/src/core/classes/locateClasses.d.ts +0 -3
  44. package/dist/src/core/classes/types.d.ts +0 -14
  45. package/dist/src/core/files/getFileDependencies.d.ts +0 -2
  46. package/dist/src/core/files/locateFiles.d.ts +0 -3
  47. package/dist/src/core/files/types.d.ts +0 -10
  48. package/dist/src/core/functions/locateFunctions.d.ts +0 -3
  49. package/dist/src/core/functions/types.d.ts +0 -11
  50. package/dist/src/core/layers/createLayeredArchitecture.d.ts +0 -3
  51. package/dist/src/core/layers/getLayerDependencies.d.ts +0 -2
  52. package/dist/src/core/layers/types.d.ts +0 -8
  53. package/dist/src/core/project/parseProject.d.ts +0 -22
  54. package/dist/src/core/properties/locateProperties.d.ts +0 -3
  55. package/dist/src/core/properties/types.d.ts +0 -10
  56. package/dist/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +0 -1
  57. package/dist/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +0 -1
  58. package/dist/src/core/shared/sharedCheckHaveModifier.d.ts +0 -2
  59. package/dist/src/core/shared/sharedCheckHaveNameMatchingFileName.d.ts +0 -2
  60. package/dist/src/core/shared/sharedCheckMatchNamePattern.d.ts +0 -1
  61. package/dist/src/core/slices/locateSlices.d.ts +0 -3
  62. package/dist/src/core/slices/types.d.ts +0 -8
  63. package/dist/src/index.d.ts +0 -35
  64. package/dist/src/matchers/index.d.ts +0 -20
  65. package/src/core/classes/classCheckExtendClass.test.ts +0 -30
  66. package/src/core/classes/classCheckExtendClass.ts +0 -41
  67. package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
  68. package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.ts +0 -35
  69. package/src/core/classes/classCheckHaveModifier.test.ts +0 -30
  70. package/src/core/classes/classCheckHaveModifier.ts +0 -17
  71. package/src/core/classes/classCheckHaveNameMatchingFileName.test.ts +0 -30
  72. package/src/core/classes/classCheckHaveNameMatchingFileName.ts +0 -15
  73. package/src/core/classes/classCheckImplementInterface.test.ts +0 -30
  74. package/src/core/classes/classCheckImplementInterface.ts +0 -43
  75. package/src/core/classes/classCheckMatchNamePattern.test.ts +0 -8
  76. package/src/core/classes/classCheckMatchNamePattern.ts +0 -17
  77. package/src/core/classes/classCheckResideInFolder.test.ts +0 -8
  78. package/src/core/classes/classCheckResideInFolder.ts +0 -31
  79. package/src/core/classes/locateClasses.test.ts +0 -13
  80. package/src/core/classes/locateClasses.ts +0 -127
  81. package/src/core/classes/types.ts +0 -16
  82. package/src/core/files/checkDependOnFilesInFolder.test.ts +0 -7
  83. package/src/core/files/checkDependOnFilesInFolder.ts +0 -36
  84. package/src/core/files/fileCheckBeFreeOfCycles.test.ts +0 -7
  85. package/src/core/files/fileCheckBeFreeOfCycles.ts +0 -72
  86. package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
  87. package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.ts +0 -35
  88. package/src/core/files/fileCheckHaveMaxExportedFunctions.test.ts +0 -32
  89. package/src/core/files/fileCheckHaveMaxExportedFunctions.ts +0 -45
  90. package/src/core/files/fileCheckHaveMinMaintainabilityIndex.test.ts +0 -8
  91. package/src/core/files/fileCheckHaveMinMaintainabilityIndex.ts +0 -19
  92. package/src/core/files/fileCheckMatchNamePattern.test.ts +0 -30
  93. package/src/core/files/fileCheckMatchNamePattern.ts +0 -17
  94. package/src/core/files/getFileDependencies.ts +0 -43
  95. package/src/core/files/locateFiles.test.ts +0 -30
  96. package/src/core/files/locateFiles.ts +0 -31
  97. package/src/core/files/types.ts +0 -12
  98. package/src/core/functions/functionCheckHaveExplicitReturnType.test.ts +0 -30
  99. package/src/core/functions/functionCheckHaveExplicitReturnType.ts +0 -29
  100. package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
  101. package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.ts +0 -20
  102. package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.test.ts +0 -8
  103. package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.ts +0 -20
  104. package/src/core/functions/functionCheckHaveModifier.test.ts +0 -30
  105. package/src/core/functions/functionCheckHaveModifier.ts +0 -18
  106. package/src/core/functions/functionCheckHaveNameMatchingFileName.test.ts +0 -30
  107. package/src/core/functions/functionCheckHaveNameMatchingFileName.ts +0 -16
  108. package/src/core/functions/functionCheckMatchNamePattern.test.ts +0 -30
  109. package/src/core/functions/functionCheckMatchNamePattern.ts +0 -18
  110. package/src/core/functions/locateFunctions.test.ts +0 -16
  111. package/src/core/functions/locateFunctions.ts +0 -47
  112. package/src/core/functions/types.ts +0 -13
  113. package/src/core/layers/checkLayeredArchitecture.test.ts +0 -23
  114. package/src/core/layers/checkLayeredArchitecture.ts +0 -15
  115. package/src/core/layers/createLayeredArchitecture.test.ts +0 -13
  116. package/src/core/layers/createLayeredArchitecture.ts +0 -15
  117. package/src/core/layers/getLayerDependencies.ts +0 -45
  118. package/src/core/layers/layer.test.ts +0 -12
  119. package/src/core/layers/layer.ts +0 -10
  120. package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.test.ts +0 -14
  121. package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.ts +0 -40
  122. package/src/core/layers/layerShouldOnlyBeAccessedBy.test.ts +0 -15
  123. package/src/core/layers/layerShouldOnlyBeAccessedBy.ts +0 -48
  124. package/src/core/layers/types.ts +0 -9
  125. package/src/core/metrics/calculateCyclomaticComplexity.test.ts +0 -23
  126. package/src/core/metrics/calculateCyclomaticComplexity.ts +0 -36
  127. package/src/core/metrics/calculateMaintainabilityIndex.test.ts +0 -38
  128. package/src/core/metrics/calculateMaintainabilityIndex.ts +0 -47
  129. package/src/core/project/parseProject.test.ts +0 -19
  130. package/src/core/project/parseProject.ts +0 -216
  131. package/src/core/properties/locateProperties.test.ts +0 -19
  132. package/src/core/properties/locateProperties.ts +0 -41
  133. package/src/core/properties/propertyCheckBeReadonly.test.ts +0 -32
  134. package/src/core/properties/propertyCheckBeReadonly.ts +0 -27
  135. package/src/core/properties/types.ts +0 -12
  136. package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.test.ts +0 -30
  137. package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.ts +0 -23
  138. package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.test.ts +0 -30
  139. package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.ts +0 -23
  140. package/src/core/shared/sharedCheckHaveModifier.test.ts +0 -31
  141. package/src/core/shared/sharedCheckHaveModifier.ts +0 -51
  142. package/src/core/shared/sharedCheckHaveNameMatchingFileName.test.ts +0 -17
  143. package/src/core/shared/sharedCheckHaveNameMatchingFileName.ts +0 -36
  144. package/src/core/shared/sharedCheckMatchNamePattern.test.ts +0 -29
  145. package/src/core/shared/sharedCheckMatchNamePattern.ts +0 -22
  146. package/src/core/slices/locateSlices.test.ts +0 -22
  147. package/src/core/slices/locateSlices.ts +0 -35
  148. package/src/core/slices/sliceCheckBeFreeOfCycles.test.ts +0 -26
  149. package/src/core/slices/sliceCheckBeFreeOfCycles.ts +0 -91
  150. package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.test.ts +0 -27
  151. package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.ts +0 -110
  152. package/src/core/slices/types.ts +0 -9
  153. package/src/core/testUtils.ts +0 -61
  154. package/src/core/types.ts +0 -19
  155. package/src/core/utils/ruleBuilder.test.ts +0 -24
  156. package/src/core/utils/ruleBuilder.ts +0 -28
  157. package/src/index.ts +0 -35
  158. package/src/matchers/index.ts +0 -331
  159. package/test/architecture.test.ts +0 -152
  160. package/tsconfig.json +0 -18
  161. package/vite.config.ts +0 -18
  162. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckExtendClass.d.ts +0 -0
  163. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
  164. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveModifier.d.ts +0 -0
  165. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveNameMatchingFileName.d.ts +0 -0
  166. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckImplementInterface.d.ts +0 -0
  167. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckMatchNamePattern.d.ts +0 -0
  168. /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckResideInFolder.d.ts +0 -0
  169. /package/{dist/src/core → node_modules/@archest/core/dist}/files/checkDependOnFilesInFolder.d.ts +0 -0
  170. /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckBeFreeOfCycles.d.ts +0 -0
  171. /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
  172. /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMaxExportedFunctions.d.ts +0 -0
  173. /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMinMaintainabilityIndex.d.ts +0 -0
  174. /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckMatchNamePattern.d.ts +0 -0
  175. /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveExplicitReturnType.d.ts +0 -0
  176. /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
  177. /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveMinMaintainabilityIndex.d.ts +0 -0
  178. /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveModifier.d.ts +0 -0
  179. /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveNameMatchingFileName.d.ts +0 -0
  180. /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckMatchNamePattern.d.ts +0 -0
  181. /package/{dist/src/core → node_modules/@archest/core/dist}/layers/checkLayeredArchitecture.d.ts +0 -0
  182. /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layer.d.ts +0 -0
  183. /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layerShouldNotBeAccessedByAnyLayer.d.ts +0 -0
  184. /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layerShouldOnlyBeAccessedBy.d.ts +0 -0
  185. /package/{dist/src/core → node_modules/@archest/core/dist}/metrics/calculateCyclomaticComplexity.d.ts +0 -0
  186. /package/{dist/src/core → node_modules/@archest/core/dist}/metrics/calculateMaintainabilityIndex.d.ts +0 -0
  187. /package/{dist/src/core → node_modules/@archest/core/dist}/properties/propertyCheckBeReadonly.d.ts +0 -0
  188. /package/{dist/src/core → node_modules/@archest/core/dist}/slices/sliceCheckBeFreeOfCycles.d.ts +0 -0
  189. /package/{dist/src/core → node_modules/@archest/core/dist}/slices/sliceCheckHaveMaxDistanceFromMainSequence.d.ts +0 -0
  190. /package/{dist/src/core → node_modules/@archest/core/dist}/types.d.ts +0 -0
  191. /package/{dist/src/core → node_modules/@archest/core/dist}/utils/ruleBuilder.d.ts +0 -0
@@ -1,32 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createSourceFile, getProperties } from '../testUtils';
3
- import { propertyCheckBeReadonly } from './propertyCheckBeReadonly';
4
- import type { PropertyLocatorData } from './types';
5
-
6
- describe('propertyCheckBeReadonly', () => {
7
- it('should pass if properties are readonly', () => {
8
- const sourceFile = createSourceFile(
9
- `class MyClass { readonly prop: string; }`,
10
- );
11
- const data: PropertyLocatorData = {
12
- type: 'PropertyLocator',
13
- properties: getProperties(sourceFile),
14
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
15
- program: {} as any,
16
- };
17
- const result = propertyCheckBeReadonly(data, false);
18
- expect(result.pass).toBe(true);
19
- });
20
-
21
- it('should fail if properties are not readonly', () => {
22
- const sourceFile = createSourceFile(`class MyClass { prop: string; }`);
23
- const data: PropertyLocatorData = {
24
- type: 'PropertyLocator',
25
- properties: getProperties(sourceFile),
26
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
27
- program: {} as any,
28
- };
29
- const result = propertyCheckBeReadonly(data, false);
30
- expect(result.pass).toBe(false);
31
- });
32
- });
@@ -1,27 +0,0 @@
1
- import * as ts from 'typescript';
2
- import type { RuleResult } from '../types';
3
- import type { PropertyLocatorData } from './types';
4
-
5
- export function propertyCheckBeReadonly(
6
- locator: PropertyLocatorData,
7
- isNot: boolean,
8
- ): RuleResult {
9
- const violations: string[] = [];
10
- for (const p of locator.properties) {
11
- const name = ts.isIdentifier(p.name) ? p.name.text : 'Anonymous Property';
12
- const modifiers = ts.canHaveModifiers(p) ? ts.getModifiers(p) : undefined;
13
- const matches = modifiers?.some(
14
- (m: ts.Modifier) => m.kind === ts.SyntaxKind.ReadonlyKeyword,
15
- );
16
-
17
- if (isNot && matches) {
18
- violations.push(`Property ${name} is readonly, but it shouldn't be.`);
19
- } else if (!isNot && !matches) {
20
- violations.push(`Property ${name} is not readonly, but it should be.`);
21
- }
22
- }
23
- return {
24
- pass: violations.length === 0,
25
- message: () => violations.join('\n'),
26
- };
27
- }
@@ -1,12 +0,0 @@
1
- import type * as ts from 'typescript';
2
-
3
- export interface PropertyLocatorData {
4
- type: 'PropertyLocator';
5
- properties: ts.PropertyDeclaration[];
6
- program: ts.Program;
7
- }
8
-
9
- export interface PropertyQueryOptions {
10
- inFolder?: string;
11
- matchNamePattern?: string | RegExp;
12
- }
@@ -1,30 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { sharedCheckHaveMaxCyclomaticComplexity } from './sharedCheckHaveMaxCyclomaticComplexity';
3
-
4
- describe('sharedCheckHaveMaxCyclomaticComplexity', () => {
5
- it('should pass if complexity is within limits', () => {
6
- const items = [{ name: 'A', complexity: 5 }];
7
- const result = sharedCheckHaveMaxCyclomaticComplexity(
8
- items,
9
- (i) => i.name,
10
- (i) => i.complexity,
11
- 'Item',
12
- 10,
13
- false,
14
- );
15
- expect(result.pass).toBe(true);
16
- });
17
-
18
- it('should fail if complexity exceeds limits', () => {
19
- const items = [{ name: 'A', complexity: 15 }];
20
- const result = sharedCheckHaveMaxCyclomaticComplexity(
21
- items,
22
- (i) => i.name,
23
- (i) => i.complexity,
24
- 'Item',
25
- 10,
26
- false,
27
- );
28
- expect(result.pass).toBe(false);
29
- });
30
- });
@@ -1,23 +0,0 @@
1
- import { ruleBuilder } from '../utils/ruleBuilder';
2
-
3
- export function sharedCheckHaveMaxCyclomaticComplexity<T>(
4
- items: T[],
5
- getName: (item: T) => string | undefined,
6
- getComplexity: (item: T) => number,
7
- label: string,
8
- max: number,
9
- isNot: boolean,
10
- ) {
11
- return ruleBuilder(items, isNot, (item) => {
12
- const name = getName(item);
13
- const complexity = getComplexity(item);
14
- const exceeds = complexity > max;
15
- const desc = `${label} ${name || 'Anonymous'}`;
16
-
17
- return {
18
- passes: !exceeds,
19
- failMessage: `${desc} has a total cyclomatic complexity of ${complexity}, which exceeds the maximum of ${max}.`,
20
- failNotMessage: `${desc} has a total cyclomatic complexity of ${complexity}, which exceeds the maximum of ${max}, but it shouldn't.`,
21
- };
22
- });
23
- }
@@ -1,30 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { sharedCheckHaveMinMaintainabilityIndex } from './sharedCheckHaveMinMaintainabilityIndex';
3
-
4
- describe('sharedCheckHaveMinMaintainabilityIndex', () => {
5
- it('should pass if MI is above limit', () => {
6
- const items = [{ name: 'A', mi: 50 }];
7
- const result = sharedCheckHaveMinMaintainabilityIndex(
8
- items,
9
- (i) => i.name,
10
- (i) => i.mi,
11
- 'Item',
12
- 20,
13
- false,
14
- );
15
- expect(result.pass).toBe(true);
16
- });
17
-
18
- it('should fail if MI is below limit', () => {
19
- const items = [{ name: 'A', mi: 10 }];
20
- const result = sharedCheckHaveMinMaintainabilityIndex(
21
- items,
22
- (i) => i.name,
23
- (i) => i.mi,
24
- 'Item',
25
- 20,
26
- false,
27
- );
28
- expect(result.pass).toBe(false);
29
- });
30
- });
@@ -1,23 +0,0 @@
1
- import { ruleBuilder } from '../utils/ruleBuilder';
2
-
3
- export function sharedCheckHaveMinMaintainabilityIndex<T>(
4
- items: T[],
5
- getName: (item: T) => string | undefined,
6
- getMi: (item: T) => number,
7
- label: string,
8
- min: number,
9
- isNot: boolean,
10
- ) {
11
- return ruleBuilder(items, isNot, (item) => {
12
- const name = getName(item);
13
- const mi = getMi(item);
14
- const fallsBelow = mi < min;
15
- const desc = `${label} ${name || 'Anonymous'}`;
16
-
17
- return {
18
- passes: !fallsBelow,
19
- failMessage: `${desc} has a maintainability index of ${mi.toFixed(2)}, which falls below the minimum of ${min}.`,
20
- failNotMessage: `${desc} has a maintainability index of ${mi.toFixed(2)}, which falls below the minimum of ${min}, but it shouldn't.`,
21
- };
22
- });
23
- }
@@ -1,31 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createSourceFile, getClasses } from '../testUtils';
3
- import { sharedCheckHaveModifier } from './sharedCheckHaveModifier';
4
-
5
- describe('sharedCheckHaveModifier', () => {
6
- it('should pass if node has the modifier', () => {
7
- const sourceFile = createSourceFile('export class MyClass {}');
8
- const classes = getClasses(sourceFile);
9
- const result = sharedCheckHaveModifier(
10
- classes,
11
- (c) => c.name?.text,
12
- 'Class',
13
- 'export',
14
- false,
15
- );
16
- expect(result.pass).toBe(true);
17
- });
18
-
19
- it('should fail if node does not have the modifier', () => {
20
- const sourceFile = createSourceFile('class MyClass {}');
21
- const classes = getClasses(sourceFile);
22
- const result = sharedCheckHaveModifier(
23
- classes,
24
- (c) => c.name?.text,
25
- 'Class',
26
- 'export',
27
- false,
28
- );
29
- expect(result.pass).toBe(false);
30
- });
31
- });
@@ -1,51 +0,0 @@
1
- import * as ts from 'typescript';
2
- import { ruleBuilder } from '../utils/ruleBuilder';
3
-
4
- export function sharedCheckHaveModifier<T extends ts.Node>(
5
- items: T[],
6
- getName: (item: T) => string | undefined,
7
- label: string,
8
- modifierStr: string,
9
- isNot: boolean,
10
- ) {
11
- let targetKind: ts.SyntaxKind;
12
- switch (modifierStr) {
13
- case 'export':
14
- targetKind = ts.SyntaxKind.ExportKeyword;
15
- break;
16
- case 'default':
17
- targetKind = ts.SyntaxKind.DefaultKeyword;
18
- break;
19
- case 'abstract':
20
- targetKind = ts.SyntaxKind.AbstractKeyword;
21
- break;
22
- case 'async':
23
- targetKind = ts.SyntaxKind.AsyncKeyword;
24
- break;
25
- case 'public':
26
- targetKind = ts.SyntaxKind.PublicKeyword;
27
- break;
28
- case 'private':
29
- targetKind = ts.SyntaxKind.PrivateKeyword;
30
- break;
31
- default:
32
- throw new Error(`Modifier ${modifierStr} is not fully supported.`);
33
- }
34
-
35
- return ruleBuilder(items, isNot, (item) => {
36
- const name = getName(item);
37
- const modifiers = ts.canHaveModifiers(item)
38
- ? ts.getModifiers(item)
39
- : undefined;
40
- const passes = modifiers
41
- ? modifiers.some((m: ts.Modifier) => m.kind === targetKind)
42
- : false;
43
- const desc = `${label} ${name || 'Anonymous'}`;
44
-
45
- return {
46
- passes,
47
- failMessage: `${desc} does not have modifier ${modifierStr}, but it should.`,
48
- failNotMessage: `${desc} has modifier ${modifierStr}, but it shouldn't.`,
49
- };
50
- });
51
- }
@@ -1,17 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { sharedCheckHaveNameMatchingFileName } from './sharedCheckHaveNameMatchingFileName';
3
-
4
- describe('sharedCheckHaveNameMatchingFileName', () => {
5
- it('should skip nodes without source files', () => {
6
- // getFunctions actually provides a getSourceFile natively
7
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
8
- const items = [{ parent: undefined } as any];
9
- const result = sharedCheckHaveNameMatchingFileName(
10
- items,
11
- () => 'name',
12
- 'Item',
13
- false,
14
- );
15
- expect(result.pass).toBe(true);
16
- });
17
- });
@@ -1,36 +0,0 @@
1
- import * as path from 'node:path';
2
- import * as ts from 'typescript';
3
- import { ruleBuilder } from '../utils/ruleBuilder';
4
-
5
- export function sharedCheckHaveNameMatchingFileName<T extends ts.Node>(
6
- items: T[],
7
- getName: (item: T) => string | undefined,
8
- label: string,
9
- isNot: boolean,
10
- ) {
11
- return ruleBuilder(items, isNot, (item) => {
12
- const name = getName(item);
13
- const sourceFile = item.getSourceFile
14
- ? item.getSourceFile()
15
- : item.parent
16
- ? ts.getSourceFileOfNode(item)
17
- : undefined;
18
-
19
- if (!sourceFile) {
20
- return { passes: true, failMessage: '', failNotMessage: '' };
21
- }
22
-
23
- const basename = path.basename(
24
- sourceFile.fileName,
25
- path.extname(sourceFile.fileName),
26
- );
27
- const passes = name === basename;
28
- const desc = `${label} ${name || 'Anonymous'}`;
29
-
30
- return {
31
- passes,
32
- failMessage: `${desc} does not have a name matching its filename ${basename}, but it should.`,
33
- failNotMessage: `${desc} has a name matching its filename ${basename}, but it shouldn't.`,
34
- };
35
- });
36
- }
@@ -1,29 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { sharedCheckMatchNamePattern } from './sharedCheckMatchNamePattern';
3
-
4
- describe('sharedCheckMatchNamePattern', () => {
5
- it('should pass if all items match the pattern', () => {
6
- const items = [{ name: 'UserService' }, { name: 'AuthService' }];
7
- const result = sharedCheckMatchNamePattern(
8
- items,
9
- (i) => i.name,
10
- 'Item',
11
- /Service$/,
12
- false,
13
- );
14
- expect(result.pass).toBe(true);
15
- });
16
-
17
- it('should fail if any item does not match the pattern', () => {
18
- const items = [{ name: 'UserService' }, { name: 'AuthRepository' }];
19
- const result = sharedCheckMatchNamePattern(
20
- items,
21
- (i) => i.name,
22
- 'Item',
23
- /Service$/,
24
- false,
25
- );
26
- expect(result.pass).toBe(false);
27
- expect(result.message()).toContain('AuthRepository does not match pattern');
28
- });
29
- });
@@ -1,22 +0,0 @@
1
- import { ruleBuilder } from '../utils/ruleBuilder';
2
-
3
- export function sharedCheckMatchNamePattern<T>(
4
- items: T[],
5
- getName: (item: T) => string | undefined,
6
- label: string,
7
- pattern: string | RegExp,
8
- isNot: boolean,
9
- ) {
10
- const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
11
-
12
- return ruleBuilder(items, isNot, (item) => {
13
- const name = getName(item);
14
- const passes = name ? regex.test(name) : false;
15
- const desc = `${label} ${name || 'Anonymous'}`;
16
- return {
17
- passes,
18
- failMessage: `${desc} does not match pattern ${pattern}, but it should.`,
19
- failNotMessage: `${desc} matches pattern ${pattern}, but it shouldn't.`,
20
- };
21
- });
22
- }
@@ -1,22 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createSourceFile } from '../testUtils';
3
- import { locateSlices } from './locateSlices';
4
-
5
- describe('locateSlices', () => {
6
- it('should group files into slices based on pattern', () => {
7
- const file1 = createSourceFile('', 'src/domain/auth/index.ts');
8
- const file2 = createSourceFile('', 'src/domain/users/index.ts');
9
- const file3 = createSourceFile('', 'src/domain/users/user.ts');
10
- const result = locateSlices(
11
- [file1, file2, file3],
12
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
13
- {} as any,
14
- 'src/domain/*',
15
- );
16
-
17
- expect(result.sliceIds.size).toBe(2);
18
- expect(result.sliceIds.has('auth')).toBe(true);
19
- expect(result.sliceIds.has('users')).toBe(true);
20
- expect(result.sliceFiles.get('users')?.length).toBe(2);
21
- });
22
- });
@@ -1,35 +0,0 @@
1
- import type * as ts from 'typescript';
2
- import type { SliceLocatorData } from './types';
3
-
4
- export function locateSlices(
5
- sourceFiles: ts.SourceFile[],
6
- program: ts.Program,
7
- pattern: string,
8
- ): SliceLocatorData {
9
- const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, '\\$&');
10
- const regexStr = escaped.replace(/\*/g, '([^/\\\\]+)');
11
- const slicePattern = new RegExp(regexStr);
12
-
13
- const sliceIds = new Set<string>();
14
- const sliceFiles = new Map<string, ts.SourceFile[]>();
15
-
16
- for (const sf of sourceFiles) {
17
- const match = sf.fileName.match(slicePattern);
18
- if (match?.[1]) {
19
- const sliceId = match[1];
20
- sliceIds.add(sliceId);
21
- if (!sliceFiles.has(sliceId)) {
22
- sliceFiles.set(sliceId, []);
23
- }
24
- sliceFiles.get(sliceId)?.push(sf);
25
- }
26
- }
27
-
28
- return {
29
- type: 'SliceLocator',
30
- slicePattern,
31
- sliceIds,
32
- sliceFiles,
33
- program,
34
- };
35
- }
@@ -1,26 +0,0 @@
1
- import { describe, it } from 'vitest';
2
-
3
- describe('sliceCheckBeFreeOfCycles', () => {
4
- it('should fail if there is a cycle between slices', () => {
5
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
6
- const sliceFiles = new Map<string, any[]>();
7
- const sliceIds = new Set(['sliceA', 'sliceB']);
8
- sliceFiles.set('sliceA', [{ fileName: 'a.ts' }]);
9
- sliceFiles.set('sliceB', [{ fileName: 'b.ts' }]);
10
-
11
- const _locator = {
12
- type: 'SliceLocator' as const,
13
- slicePattern: /.*/,
14
- sliceIds,
15
- sliceFiles,
16
- program: {
17
- getCompilerOptions: () => ({}),
18
- getSourceFile: () => ({}),
19
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
20
- } as any,
21
- };
22
-
23
- // To mock the cycle, we would have to mock getFileDependencies.
24
- // Given the difficulty without vi.mock, let's just write a test that passes cleanly or skips.
25
- });
26
- });
@@ -1,91 +0,0 @@
1
- import * as ts from 'typescript';
2
- import type { RuleResult } from '../types';
3
- import type { SliceLocatorData } from './types';
4
-
5
- export function sliceCheckBeFreeOfCycles(
6
- locator: SliceLocatorData,
7
- isNot: boolean,
8
- ): RuleResult {
9
- const graph: Map<string, Set<string>> = new Map();
10
- for (const slice of locator.sliceIds) {
11
- graph.set(slice, new Set());
12
- }
13
-
14
- for (const [sliceId, files] of locator.sliceFiles.entries()) {
15
- for (const sf of files) {
16
- ts.forEachChild(sf, (node) => {
17
- if (
18
- ts.isImportDeclaration(node) &&
19
- node.moduleSpecifier &&
20
- ts.isStringLiteral(node.moduleSpecifier)
21
- ) {
22
- const importPath = node.moduleSpecifier.text;
23
- const resolved = ts.resolveModuleName(
24
- importPath,
25
- sf.fileName,
26
- locator.program.getCompilerOptions(),
27
- ts.sys,
28
- );
29
- if (resolved.resolvedModule?.resolvedFileName) {
30
- const targetMatch = resolved.resolvedModule.resolvedFileName.match(
31
- locator.slicePattern,
32
- );
33
- if (targetMatch?.[1]) {
34
- const targetSlice = targetMatch[1];
35
- if (
36
- targetSlice !== sliceId &&
37
- locator.sliceIds.has(targetSlice)
38
- ) {
39
- graph.get(sliceId)?.add(targetSlice);
40
- }
41
- }
42
- }
43
- }
44
- });
45
- }
46
- }
47
-
48
- const visited = new Set<string>();
49
- const recursionStack = new Set<string>();
50
- const violations: string[] = [];
51
-
52
- const dfs = (node: string, path: string[]): boolean => {
53
- visited.add(node);
54
- recursionStack.add(node);
55
-
56
- for (const neighbor of graph.get(node) || []) {
57
- if (!visited.has(neighbor)) {
58
- if (dfs(neighbor, [...path, neighbor])) return true;
59
- } else if (recursionStack.has(neighbor)) {
60
- violations.push(
61
- `Cycle detected between slices: ${path.join(' -> ')} -> ${neighbor}`,
62
- );
63
- return true;
64
- }
65
- }
66
-
67
- recursionStack.delete(node);
68
- return false;
69
- };
70
-
71
- for (const slice of locator.sliceIds) {
72
- if (!visited.has(slice)) {
73
- dfs(slice, [slice]);
74
- }
75
- }
76
-
77
- if (isNot) {
78
- return {
79
- pass: violations.length > 0,
80
- message: () =>
81
- violations.length > 0
82
- ? ''
83
- : 'Expected cycles between slices but found none.',
84
- };
85
- } else {
86
- return {
87
- pass: violations.length === 0,
88
- message: () => violations.join('\n'),
89
- };
90
- }
91
- }
@@ -1,27 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createSourceFile } from '../testUtils';
3
- import { sliceCheckHaveMaxDistanceFromMainSequence } from './sliceCheckHaveMaxDistanceFromMainSequence';
4
-
5
- describe('sliceCheckHaveMaxDistanceFromMainSequence', () => {
6
- it('should be structured correctly', () => {
7
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
8
- const sliceFiles = new Map<string, any[]>();
9
- const sliceIds = new Set(['sliceA']);
10
- sliceFiles.set('sliceA', [createSourceFile('class A {}')]);
11
-
12
- const locator = {
13
- type: 'SliceLocator' as const,
14
- slicePattern: /.*/,
15
- sliceIds,
16
- sliceFiles,
17
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
18
- program: { getCompilerOptions: () => ({}) } as any,
19
- };
20
-
21
- // Very hard to fully mock distance sequence because of resolving dependencies.
22
- // We will just verify it runs without crashing given valid input.
23
- expect(() =>
24
- sliceCheckHaveMaxDistanceFromMainSequence(locator, 0.5, false),
25
- ).not.toThrow();
26
- });
27
- });