@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,15 +0,0 @@
1
- import type * as ts from 'typescript';
2
- import type { LayeredArchitectureData } from './types';
3
-
4
- export function createLayeredArchitecture(
5
- files: ts.SourceFile[],
6
- program: ts.Program,
7
- ): LayeredArchitectureData {
8
- return {
9
- type: 'LayeredArchitecture',
10
- files,
11
- layers: new Map<string, string>(),
12
- assertions: [],
13
- program,
14
- };
15
- }
@@ -1,45 +0,0 @@
1
- import * as ts from 'typescript';
2
-
3
- export function getLayerDependencies(
4
- sourceFile: ts.SourceFile,
5
- program: ts.Program,
6
- ): string[] {
7
- const dependencies: string[] = [];
8
- const compilerOptions = program.getCompilerOptions();
9
-
10
- const visit = (node: ts.Node) => {
11
- if (ts.isImportDeclaration(node)) {
12
- const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;
13
- const resolved = ts.resolveModuleName(
14
- moduleSpecifier,
15
- sourceFile.fileName,
16
- compilerOptions,
17
- ts.sys,
18
- );
19
- if (
20
- resolved.resolvedModule?.resolvedFileName &&
21
- !resolved.resolvedModule.isExternalLibraryImport
22
- ) {
23
- dependencies.push(resolved.resolvedModule.resolvedFileName);
24
- }
25
- } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
26
- const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;
27
- const resolved = ts.resolveModuleName(
28
- moduleSpecifier,
29
- sourceFile.fileName,
30
- compilerOptions,
31
- ts.sys,
32
- );
33
- if (
34
- resolved.resolvedModule?.resolvedFileName &&
35
- !resolved.resolvedModule.isExternalLibraryImport
36
- ) {
37
- dependencies.push(resolved.resolvedModule.resolvedFileName);
38
- }
39
- }
40
- ts.forEachChild(node, visit);
41
- };
42
-
43
- visit(sourceFile);
44
- return dependencies;
45
- }
@@ -1,12 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createLayeredArchitecture } from './createLayeredArchitecture';
3
- import { layer } from './layer';
4
-
5
- describe('layer', () => {
6
- it('should add a layer pattern to the architecture data', () => {
7
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
8
- let data = createLayeredArchitecture([], {} as any);
9
- data = layer(data, 'Domain', 'src/domain');
10
- expect(data.layers.get('Domain')).toBe('src/domain');
11
- });
12
- });
@@ -1,10 +0,0 @@
1
- import type { LayeredArchitectureData } from './types';
2
-
3
- export function layer(
4
- data: LayeredArchitectureData,
5
- name: string,
6
- folderPattern: string,
7
- ): LayeredArchitectureData {
8
- data.layers.set(name, folderPattern);
9
- return data;
10
- }
@@ -1,14 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createLayeredArchitecture } from './createLayeredArchitecture';
3
- import { layer } from './layer';
4
- import { layerShouldNotBeAccessedByAnyLayer } from './layerShouldNotBeAccessedByAnyLayer';
5
-
6
- describe('layerShouldNotBeAccessedByAnyLayer', () => {
7
- it('should push an assertion to the data', () => {
8
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
9
- let data = createLayeredArchitecture([], {} as any);
10
- data = layer(data, 'Domain', 'src/domain');
11
- data = layerShouldNotBeAccessedByAnyLayer(data, 'Domain');
12
- expect(data.assertions.length).toBe(1);
13
- });
14
- });
@@ -1,40 +0,0 @@
1
- import { getLayerDependencies } from './getLayerDependencies';
2
- import type { LayeredArchitectureData } from './types';
3
-
4
- export function layerShouldNotBeAccessedByAnyLayer(
5
- data: LayeredArchitectureData,
6
- targetLayer: string,
7
- ): LayeredArchitectureData {
8
- if (!data.layers.has(targetLayer)) {
9
- throw new Error(`Layer ${targetLayer} is not defined`);
10
- }
11
-
12
- data.assertions.push((files) => {
13
- const violations: string[] = [];
14
- // biome-ignore lint/style/noNonNullAssertion: Safe map lookup
15
- const targetPattern = data.layers.get(targetLayer)!;
16
-
17
- for (const file of files) {
18
- const filePath = file.fileName;
19
- if (
20
- !filePath.includes(`/${targetPattern}/`) &&
21
- !filePath.includes(`\\${targetPattern}\\`)
22
- ) {
23
- const dependencies = getLayerDependencies(file, data.program);
24
- const importsTarget = dependencies.some(
25
- (dep) =>
26
- dep.includes(`/${targetPattern}/`) ||
27
- dep.includes(`\\${targetPattern}\\`),
28
- );
29
- if (importsTarget) {
30
- violations.push(
31
- `File ${filePath} accesses layer ${targetLayer} but it shouldn't.`,
32
- );
33
- }
34
- }
35
- }
36
- return violations;
37
- });
38
-
39
- return data;
40
- }
@@ -1,15 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createLayeredArchitecture } from './createLayeredArchitecture';
3
- import { layer } from './layer';
4
- import { layerShouldOnlyBeAccessedBy } from './layerShouldOnlyBeAccessedBy';
5
-
6
- describe('layerShouldOnlyBeAccessedBy', () => {
7
- it('should push an assertion to the data', () => {
8
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
9
- let data = createLayeredArchitecture([], {} as any);
10
- data = layer(data, 'Domain', 'src/domain');
11
- data = layer(data, 'Infra', 'src/infra');
12
- data = layerShouldOnlyBeAccessedBy(data, 'Domain', ['Infra']);
13
- expect(data.assertions.length).toBe(1);
14
- });
15
- });
@@ -1,48 +0,0 @@
1
- import { getLayerDependencies } from './getLayerDependencies';
2
- import type { LayeredArchitectureData } from './types';
3
-
4
- export function layerShouldOnlyBeAccessedBy(
5
- data: LayeredArchitectureData,
6
- targetLayer: string,
7
- allowedLayers: string[],
8
- ): LayeredArchitectureData {
9
- if (!data.layers.has(targetLayer)) {
10
- throw new Error(`Layer ${targetLayer} is not defined`);
11
- }
12
-
13
- data.assertions.push((files) => {
14
- const violations: string[] = [];
15
- // biome-ignore lint/style/noNonNullAssertion: Safe map lookup
16
- const targetPattern = data.layers.get(targetLayer)!;
17
- // biome-ignore lint/style/noNonNullAssertion: Safe map lookup
18
- const allowedPatterns = allowedLayers.map((l) => data.layers.get(l)!);
19
-
20
- for (const file of files) {
21
- const filePath = file.fileName;
22
- const isInAllowedLayer = allowedPatterns.some(
23
- (p) => filePath.includes(`/${p}/`) || filePath.includes(`\\${p}\\`),
24
- );
25
-
26
- if (
27
- !filePath.includes(`/${targetPattern}/`) &&
28
- !filePath.includes(`\\${targetPattern}\\`) &&
29
- !isInAllowedLayer
30
- ) {
31
- const dependencies = getLayerDependencies(file, data.program);
32
- const importsTarget = dependencies.some(
33
- (dep) =>
34
- dep.includes(`/${targetPattern}/`) ||
35
- dep.includes(`\\${targetPattern}\\`),
36
- );
37
- if (importsTarget) {
38
- violations.push(
39
- `File ${filePath} accesses layer ${targetLayer} but only ${allowedLayers.join(', ')} are allowed.`,
40
- );
41
- }
42
- }
43
- }
44
- return violations;
45
- });
46
-
47
- return data;
48
- }
@@ -1,9 +0,0 @@
1
- import type * as ts from 'typescript';
2
-
3
- export interface LayeredArchitectureData {
4
- type: 'LayeredArchitecture';
5
- files: ts.SourceFile[];
6
- layers: Map<string, string>;
7
- assertions: Array<(files: ts.SourceFile[]) => string[]>;
8
- program: ts.Program;
9
- }
@@ -1,23 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createSourceFile, getFunctions } from '../testUtils';
3
- import { calculateCyclomaticComplexity } from './calculateCyclomaticComplexity';
4
-
5
- describe('calculateCyclomaticComplexity', () => {
6
- it('should return 1 for a simple function', () => {
7
- const sourceFile = createSourceFile('function simple() { return 1; }');
8
- const fns = getFunctions(sourceFile);
9
- expect(calculateCyclomaticComplexity(fns[0])).toBe(1);
10
- });
11
-
12
- it('should calculate higher complexity for branches', () => {
13
- const sourceFile = createSourceFile(`
14
- function complex(a) {
15
- if (a) return 1;
16
- if (!a) return 2;
17
- return a ? 3 : 4;
18
- }
19
- `);
20
- const fns = getFunctions(sourceFile);
21
- expect(calculateCyclomaticComplexity(fns[0])).toBe(4);
22
- });
23
- });
@@ -1,36 +0,0 @@
1
- import * as ts from 'typescript';
2
-
3
- export function calculateCyclomaticComplexity(node: ts.Node): number {
4
- let complexity = 1;
5
-
6
- const visit = (n: ts.Node) => {
7
- switch (n.kind) {
8
- case ts.SyntaxKind.IfStatement:
9
- case ts.SyntaxKind.ForStatement:
10
- case ts.SyntaxKind.ForInStatement:
11
- case ts.SyntaxKind.ForOfStatement:
12
- case ts.SyntaxKind.WhileStatement:
13
- case ts.SyntaxKind.DoStatement:
14
- case ts.SyntaxKind.CaseClause:
15
- case ts.SyntaxKind.CatchClause:
16
- case ts.SyntaxKind.ConditionalExpression:
17
- complexity++;
18
- break;
19
- case ts.SyntaxKind.BinaryExpression: {
20
- const binary = n as ts.BinaryExpression;
21
- if (
22
- binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
23
- binary.operatorToken.kind === ts.SyntaxKind.BarBarToken ||
24
- binary.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken
25
- ) {
26
- complexity++;
27
- }
28
- break;
29
- }
30
- }
31
- ts.forEachChild(n, visit);
32
- };
33
-
34
- ts.forEachChild(node, visit);
35
- return complexity;
36
- }
@@ -1,38 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { createSourceFile, getFunctions } from '../testUtils';
3
- import { calculateMaintainabilityIndex } from './calculateMaintainabilityIndex';
4
-
5
- describe('calculateMaintainabilityIndex', () => {
6
- it('should return a high index for a simple function', () => {
7
- const sourceFile = createSourceFile('function simple() { return 1; }');
8
- const fns = getFunctions(sourceFile);
9
- expect(calculateMaintainabilityIndex(fns[0])).toBeGreaterThan(80);
10
- });
11
-
12
- it('should return a lower index for a complex function', () => {
13
- const sourceFile = createSourceFile(`
14
- function complex(a, b, c) {
15
- if (a) {
16
- if (b) {
17
- for (let i = 0; i < 10; i++) {
18
- console.log(c);
19
- }
20
- }
21
- }
22
- switch(a) {
23
- case 1: return 1;
24
- case 2: return 2;
25
- }
26
- }
27
- `);
28
- const fns = getFunctions(sourceFile);
29
- const complexMI = calculateMaintainabilityIndex(fns[0]);
30
- const simpleSourceFile = createSourceFile(
31
- 'function simple() { return 1; }',
32
- );
33
- const simpleMI = calculateMaintainabilityIndex(
34
- getFunctions(simpleSourceFile)[0],
35
- );
36
- expect(complexMI).toBeLessThan(simpleMI);
37
- });
38
- });
@@ -1,47 +0,0 @@
1
- import * as ts from 'typescript';
2
- import { calculateCyclomaticComplexity } from './calculateCyclomaticComplexity';
3
-
4
- export function calculateMaintainabilityIndex(node: ts.Node): number {
5
- let operators = 0;
6
- let operands = 0;
7
- const uniqueOperators = new Set<number>();
8
- const uniqueOperands = new Set<string>();
9
- let linesOfCode = 1;
10
-
11
- const sourceFile = node.getSourceFile();
12
- if (sourceFile) {
13
- const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());
14
- const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());
15
- linesOfCode = end.line - start.line + 1;
16
- }
17
-
18
- const visit = (n: ts.Node) => {
19
- if (
20
- ts.isBinaryExpression(n) ||
21
- ts.isPrefixUnaryExpression(n) ||
22
- ts.isPostfixUnaryExpression(n)
23
- ) {
24
- operators++;
25
- uniqueOperators.add(n.kind);
26
- } else if (ts.isIdentifier(n) || ts.isLiteralExpression(n)) {
27
- operands++;
28
- uniqueOperands.add(n.getText(sourceFile));
29
- }
30
- ts.forEachChild(n, visit);
31
- };
32
-
33
- visit(node);
34
-
35
- const N = operators + operands;
36
- const n = uniqueOperators.size + uniqueOperands.size;
37
- const V = n === 0 ? 0 : N * Math.log2(n);
38
- const CC = calculateCyclomaticComplexity(node);
39
-
40
- const mi = Math.max(
41
- 0,
42
- ((171 - 5.2 * Math.log(V || 1) - 0.23 * CC - 16.2 * Math.log(linesOfCode)) *
43
- 100) /
44
- 171,
45
- );
46
- return mi;
47
- }
@@ -1,19 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { parseProject } from './parseProject';
3
-
4
- describe('parseProject', () => {
5
- it('should parse the current project correctly', () => {
6
- // Running from within vitest-arch, it should pick up the tsconfig
7
- const project = parseProject();
8
- expect(project).toHaveProperty('getFiles');
9
- expect(project).toHaveProperty('getClasses');
10
- expect(project).toHaveProperty('getFunctions');
11
- expect(project).toHaveProperty('layeredArchitecture');
12
- expect(project).toHaveProperty('getSlices');
13
-
14
- // Verify it can get its own files
15
- const coreFiles = project.getFiles({ inFolder: 'core' });
16
- expect(coreFiles.files.length).toBeGreaterThan(0);
17
- expect(coreFiles.type).toBe('FileLocator');
18
- });
19
- });
@@ -1,216 +0,0 @@
1
- import { dirname } from 'node:path';
2
- import * as ts from 'typescript';
3
- import { locateClasses } from '../classes/locateClasses';
4
- import type { ClassQueryOptions } from '../classes/types';
5
- import { locateFiles } from '../files/locateFiles';
6
- import type { FileQueryOptions } from '../files/types';
7
- import { locateFunctions } from '../functions/locateFunctions';
8
- import type { FunctionQueryOptions } from '../functions/types';
9
- import { checkLayeredArchitecture } from '../layers/checkLayeredArchitecture';
10
- import { createLayeredArchitecture } from '../layers/createLayeredArchitecture';
11
- import { layer } from '../layers/layer';
12
- import { layerShouldNotBeAccessedByAnyLayer } from '../layers/layerShouldNotBeAccessedByAnyLayer';
13
- import { layerShouldOnlyBeAccessedBy } from '../layers/layerShouldOnlyBeAccessedBy';
14
- import { locateProperties } from '../properties/locateProperties';
15
- import type { PropertyQueryOptions } from '../properties/types';
16
- import { locateSlices } from '../slices/locateSlices';
17
-
18
- export function parseProject(options: { tsConfigFilePath?: string } = {}) {
19
- let compilerOptions: ts.CompilerOptions = {};
20
- const configPath =
21
- options.tsConfigFilePath ||
22
- ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');
23
-
24
- let program: ts.Program;
25
-
26
- if (configPath) {
27
- const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
28
- const parsedCommandLine = ts.parseJsonConfigFileContent(
29
- configFile.config,
30
- ts.sys,
31
- dirname(configPath),
32
- undefined,
33
- configPath,
34
- undefined,
35
- [
36
- {
37
- extension: '.vue',
38
- isMixedContent: true,
39
- scriptKind: ts.ScriptKind.TS,
40
- },
41
- {
42
- extension: '.svelte',
43
- isMixedContent: true,
44
- scriptKind: ts.ScriptKind.TS,
45
- },
46
- ],
47
- );
48
- compilerOptions = parsedCommandLine.options;
49
-
50
- const host = ts.createCompilerHost(compilerOptions);
51
- const originalGetSourceFile = host.getSourceFile;
52
-
53
- // biome-ignore lint/suspicious/noExplicitAny: Dynamic require
54
- let vueCompiler: any;
55
- try {
56
- vueCompiler = require('@vue/compiler-sfc');
57
- } catch (_e) {
58
- // Not a Vue project
59
- }
60
-
61
- host.getSourceFile = (
62
- fileName,
63
- languageVersion,
64
- onError,
65
- shouldCreateNewSourceFile,
66
- ) => {
67
- if (fileName.endsWith('.vue')) {
68
- const content = ts.sys.readFile(fileName);
69
- if (content) {
70
- let scriptContent = '';
71
- if (vueCompiler) {
72
- const parsed = vueCompiler.parse(content);
73
- const script = parsed.descriptor.script;
74
- const scriptSetup = parsed.descriptor.scriptSetup;
75
- if (script) scriptContent += `${script.content}\n`;
76
- if (scriptSetup) scriptContent += `${scriptSetup.content}\n`;
77
- } else {
78
- const match = content.match(/<script[^>]*>(.*?)<\/script>/s);
79
- if (match) scriptContent = match[1];
80
- }
81
- return ts.createSourceFile(
82
- fileName,
83
- scriptContent,
84
- languageVersion,
85
- true,
86
- ts.ScriptKind.TS,
87
- );
88
- }
89
- }
90
-
91
- if (fileName.endsWith('.svelte')) {
92
- const content = ts.sys.readFile(fileName);
93
- if (content) {
94
- let scriptContent = '';
95
- const match = content.match(/<script[^>]*>(.*?)<\/script>/s);
96
- if (match) scriptContent = match[1];
97
- return ts.createSourceFile(
98
- fileName,
99
- scriptContent,
100
- languageVersion,
101
- true,
102
- ts.ScriptKind.TS,
103
- );
104
- }
105
- }
106
-
107
- return originalGetSourceFile(
108
- fileName,
109
- languageVersion,
110
- onError,
111
- shouldCreateNewSourceFile,
112
- );
113
- };
114
-
115
- program = ts.createProgram({
116
- rootNames: parsedCommandLine.fileNames,
117
- options: compilerOptions,
118
- host: host,
119
- });
120
-
121
- // Force the TypeScript compiler to bind the AST and populate .parent pointers
122
- program.getTypeChecker();
123
- } else {
124
- throw new Error('Could not find tsconfig.json');
125
- }
126
-
127
- const getSourceFiles = () =>
128
- program
129
- .getSourceFiles()
130
- .filter(
131
- (sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules'),
132
- );
133
-
134
- return {
135
- getFiles: (queryOptions?: FileQueryOptions) => {
136
- return locateFiles(getSourceFiles(), program, queryOptions);
137
- },
138
-
139
- getClasses: (queryOptions?: ClassQueryOptions) => {
140
- const allClasses: ts.ClassDeclaration[] = [];
141
- for (const sf of getSourceFiles()) {
142
- const visit = (node: ts.Node) => {
143
- if (ts.isClassDeclaration(node)) {
144
- allClasses.push(node);
145
- }
146
- ts.forEachChild(node, visit);
147
- };
148
- visit(sf);
149
- }
150
- return locateClasses(allClasses, program, queryOptions);
151
- },
152
-
153
- layeredArchitecture: () => {
154
- let data = createLayeredArchitecture(getSourceFiles(), program);
155
- const api = {
156
- layer: (name: string, folderPattern: string) => {
157
- data = layer(data, name, folderPattern);
158
- return api;
159
- },
160
- whereLayer: (name: string) => {
161
- return {
162
- shouldNotBeAccessedByAnyLayer: () => {
163
- data = layerShouldNotBeAccessedByAnyLayer(data, name);
164
- return api;
165
- },
166
- shouldOnlyBeAccessedBy: (...allowedLayers: string[]) => {
167
- data = layerShouldOnlyBeAccessedBy(data, name, allowedLayers);
168
- return api;
169
- },
170
- };
171
- },
172
- check: () => checkLayeredArchitecture(data),
173
- get data() {
174
- return data;
175
- },
176
- };
177
- return api;
178
- },
179
-
180
- getFunctions: (queryOptions?: FunctionQueryOptions) => {
181
- const allFunctions: ts.FunctionLikeDeclaration[] = [];
182
- for (const sf of getSourceFiles()) {
183
- const visit = (node: ts.Node) => {
184
- if (
185
- ts.isFunctionDeclaration(node) ||
186
- ts.isMethodDeclaration(node) ||
187
- ts.isArrowFunction(node)
188
- ) {
189
- allFunctions.push(node);
190
- }
191
- ts.forEachChild(node, visit);
192
- };
193
- visit(sf);
194
- }
195
- return locateFunctions(allFunctions, program, queryOptions);
196
- },
197
-
198
- getProperties: (queryOptions?: PropertyQueryOptions) => {
199
- const allProperties: ts.PropertyDeclaration[] = [];
200
- for (const sf of getSourceFiles()) {
201
- const visit = (node: ts.Node) => {
202
- if (ts.isPropertyDeclaration(node)) {
203
- allProperties.push(node);
204
- }
205
- ts.forEachChild(node, visit);
206
- };
207
- visit(sf);
208
- }
209
- return locateProperties(allProperties, program, queryOptions);
210
- },
211
-
212
- getSlices: (pattern: string) => {
213
- return locateSlices(getSourceFiles(), program, pattern);
214
- },
215
- };
216
- }
@@ -1,19 +0,0 @@
1
- import ts from 'typescript';
2
- import { describe, expect, it } from 'vitest';
3
- import { createSourceFile } from '../testUtils';
4
- import { locateProperties } from './locateProperties';
5
-
6
- describe('locateProperties', () => {
7
- it('should return all properties if no query options', () => {
8
- const file1 = createSourceFile('class A { prop: string; }');
9
- const properties: ts.PropertyDeclaration[] = [];
10
- const visit = (node: ts.Node) => {
11
- if (ts.isPropertyDeclaration(node)) properties.push(node);
12
- ts.forEachChild(node, visit);
13
- };
14
- visit(file1);
15
- // biome-ignore lint/suspicious/noExplicitAny: Mocking TS types for tests
16
- const result = locateProperties(properties, {} as any);
17
- expect(result.properties.length).toBe(1);
18
- });
19
- });
@@ -1,41 +0,0 @@
1
- import * as ts from 'typescript';
2
- import type { PropertyLocatorData, PropertyQueryOptions } from './types';
3
-
4
- export function locateProperties(
5
- properties: ts.PropertyDeclaration[],
6
- program: ts.Program,
7
- options?: PropertyQueryOptions,
8
- ): PropertyLocatorData {
9
- let filtered = properties;
10
-
11
- if (options?.inFolder) {
12
- filtered = filtered.filter((p) => {
13
- const sourceFile = p.getSourceFile
14
- ? p.getSourceFile()
15
- : p.parent
16
- ? ts.getSourceFileOfNode(p)
17
- : undefined;
18
- if (!sourceFile) return false;
19
- return (
20
- sourceFile.fileName.includes(`/${options.inFolder}/`) ||
21
- sourceFile.fileName.includes(`\\${options.inFolder}\\`)
22
- );
23
- });
24
- }
25
-
26
- if (options?.matchNamePattern) {
27
- const regex =
28
- typeof options.matchNamePattern === 'string'
29
- ? new RegExp(options.matchNamePattern)
30
- : options.matchNamePattern;
31
- filtered = filtered.filter((p) => {
32
- return ts.isIdentifier(p.name) && regex.test(p.name.text);
33
- });
34
- }
35
-
36
- return {
37
- type: 'PropertyLocator',
38
- properties: filtered,
39
- program,
40
- };
41
- }