@archest/vitest 1.0.1 → 1.0.3
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.
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -764
- package/dist/index.mjs.map +1 -1
- package/dist/matchers/index.d.ts +16 -0
- package/dist/matchers/models.d.ts +201 -0
- package/node_modules/@archest/core/dist/classes/locateClasses.d.ts +5 -0
- package/node_modules/@archest/core/dist/classes/types.d.ts +25 -0
- package/node_modules/@archest/core/dist/dto.d.ts +78 -0
- package/node_modules/@archest/core/dist/files/checkDependOnExternalModule.d.ts +3 -0
- package/node_modules/@archest/core/dist/files/getFileDependencies.d.ts +2 -0
- package/node_modules/@archest/core/dist/files/locateFiles.d.ts +4 -0
- package/node_modules/@archest/core/dist/files/types.d.ts +17 -0
- package/node_modules/@archest/core/dist/functions/locateFunctions.d.ts +5 -0
- package/node_modules/@archest/core/dist/functions/types.d.ts +19 -0
- package/node_modules/@archest/core/dist/index.d.ts +43 -0
- package/node_modules/@archest/core/dist/index.js +14 -0
- package/node_modules/@archest/core/dist/index.js.map +1 -0
- package/node_modules/@archest/core/dist/index.mjs +615 -0
- package/node_modules/@archest/core/dist/index.mjs.map +1 -0
- package/node_modules/@archest/core/dist/layers/createLayeredArchitecture.d.ts +3 -0
- package/node_modules/@archest/core/dist/layers/getLayerDependencies.d.ts +2 -0
- package/node_modules/@archest/core/dist/layers/types.d.ts +8 -0
- package/node_modules/@archest/core/dist/project/parseProject.d.ts +55 -0
- package/node_modules/@archest/core/dist/properties/locateProperties.d.ts +5 -0
- package/node_modules/@archest/core/dist/properties/types.d.ts +17 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +1 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +1 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveModifier.d.ts +7 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckHaveNameMatchingFileName.d.ts +3 -0
- package/node_modules/@archest/core/dist/shared/sharedCheckMatchNamePattern.d.ts +1 -0
- package/node_modules/@archest/core/dist/slices/locateSlices.d.ts +3 -0
- package/node_modules/@archest/core/dist/slices/types.d.ts +8 -0
- package/node_modules/@archest/core/package.json +49 -0
- package/node_modules/@archest/core-rust/core-rust.darwin-arm64.node +0 -0
- package/node_modules/@archest/core-rust/core-rust.linux-x64-gnu.node +0 -0
- package/node_modules/@archest/core-rust/core-rust.win32-x64-msvc.node +0 -0
- package/node_modules/@archest/core-rust/index.d.ts +16 -0
- package/node_modules/@archest/core-rust/index.js +316 -0
- package/node_modules/@archest/core-rust/package.json +34 -0
- package/package.json +12 -1
- package/dist/src/core/classes/locateClasses.d.ts +0 -3
- package/dist/src/core/classes/types.d.ts +0 -14
- package/dist/src/core/files/getFileDependencies.d.ts +0 -2
- package/dist/src/core/files/locateFiles.d.ts +0 -3
- package/dist/src/core/files/types.d.ts +0 -10
- package/dist/src/core/functions/locateFunctions.d.ts +0 -3
- package/dist/src/core/functions/types.d.ts +0 -11
- package/dist/src/core/layers/createLayeredArchitecture.d.ts +0 -3
- package/dist/src/core/layers/getLayerDependencies.d.ts +0 -2
- package/dist/src/core/layers/types.d.ts +0 -8
- package/dist/src/core/project/parseProject.d.ts +0 -22
- package/dist/src/core/properties/locateProperties.d.ts +0 -3
- package/dist/src/core/properties/types.d.ts +0 -10
- package/dist/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.d.ts +0 -1
- package/dist/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.d.ts +0 -1
- package/dist/src/core/shared/sharedCheckHaveModifier.d.ts +0 -2
- package/dist/src/core/shared/sharedCheckHaveNameMatchingFileName.d.ts +0 -2
- package/dist/src/core/shared/sharedCheckMatchNamePattern.d.ts +0 -1
- package/dist/src/core/slices/locateSlices.d.ts +0 -3
- package/dist/src/core/slices/types.d.ts +0 -8
- package/dist/src/index.d.ts +0 -35
- package/dist/src/matchers/index.d.ts +0 -20
- package/src/core/classes/classCheckExtendClass.test.ts +0 -30
- package/src/core/classes/classCheckExtendClass.ts +0 -41
- package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
- package/src/core/classes/classCheckHaveMaxCyclomaticComplexity.ts +0 -35
- package/src/core/classes/classCheckHaveModifier.test.ts +0 -30
- package/src/core/classes/classCheckHaveModifier.ts +0 -17
- package/src/core/classes/classCheckHaveNameMatchingFileName.test.ts +0 -30
- package/src/core/classes/classCheckHaveNameMatchingFileName.ts +0 -15
- package/src/core/classes/classCheckImplementInterface.test.ts +0 -30
- package/src/core/classes/classCheckImplementInterface.ts +0 -43
- package/src/core/classes/classCheckMatchNamePattern.test.ts +0 -8
- package/src/core/classes/classCheckMatchNamePattern.ts +0 -17
- package/src/core/classes/classCheckResideInFolder.test.ts +0 -8
- package/src/core/classes/classCheckResideInFolder.ts +0 -31
- package/src/core/classes/locateClasses.test.ts +0 -13
- package/src/core/classes/locateClasses.ts +0 -127
- package/src/core/classes/types.ts +0 -16
- package/src/core/files/checkDependOnFilesInFolder.test.ts +0 -7
- package/src/core/files/checkDependOnFilesInFolder.ts +0 -36
- package/src/core/files/fileCheckBeFreeOfCycles.test.ts +0 -7
- package/src/core/files/fileCheckBeFreeOfCycles.ts +0 -72
- package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
- package/src/core/files/fileCheckHaveMaxCyclomaticComplexity.ts +0 -35
- package/src/core/files/fileCheckHaveMaxExportedFunctions.test.ts +0 -32
- package/src/core/files/fileCheckHaveMaxExportedFunctions.ts +0 -45
- package/src/core/files/fileCheckHaveMinMaintainabilityIndex.test.ts +0 -8
- package/src/core/files/fileCheckHaveMinMaintainabilityIndex.ts +0 -19
- package/src/core/files/fileCheckMatchNamePattern.test.ts +0 -30
- package/src/core/files/fileCheckMatchNamePattern.ts +0 -17
- package/src/core/files/getFileDependencies.ts +0 -43
- package/src/core/files/locateFiles.test.ts +0 -30
- package/src/core/files/locateFiles.ts +0 -31
- package/src/core/files/types.ts +0 -12
- package/src/core/functions/functionCheckHaveExplicitReturnType.test.ts +0 -30
- package/src/core/functions/functionCheckHaveExplicitReturnType.ts +0 -29
- package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.test.ts +0 -8
- package/src/core/functions/functionCheckHaveMaxCyclomaticComplexity.ts +0 -20
- package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.test.ts +0 -8
- package/src/core/functions/functionCheckHaveMinMaintainabilityIndex.ts +0 -20
- package/src/core/functions/functionCheckHaveModifier.test.ts +0 -30
- package/src/core/functions/functionCheckHaveModifier.ts +0 -18
- package/src/core/functions/functionCheckHaveNameMatchingFileName.test.ts +0 -30
- package/src/core/functions/functionCheckHaveNameMatchingFileName.ts +0 -16
- package/src/core/functions/functionCheckMatchNamePattern.test.ts +0 -30
- package/src/core/functions/functionCheckMatchNamePattern.ts +0 -18
- package/src/core/functions/locateFunctions.test.ts +0 -16
- package/src/core/functions/locateFunctions.ts +0 -47
- package/src/core/functions/types.ts +0 -13
- package/src/core/layers/checkLayeredArchitecture.test.ts +0 -23
- package/src/core/layers/checkLayeredArchitecture.ts +0 -15
- package/src/core/layers/createLayeredArchitecture.test.ts +0 -13
- package/src/core/layers/createLayeredArchitecture.ts +0 -15
- package/src/core/layers/getLayerDependencies.ts +0 -45
- package/src/core/layers/layer.test.ts +0 -12
- package/src/core/layers/layer.ts +0 -10
- package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.test.ts +0 -14
- package/src/core/layers/layerShouldNotBeAccessedByAnyLayer.ts +0 -40
- package/src/core/layers/layerShouldOnlyBeAccessedBy.test.ts +0 -15
- package/src/core/layers/layerShouldOnlyBeAccessedBy.ts +0 -48
- package/src/core/layers/types.ts +0 -9
- package/src/core/metrics/calculateCyclomaticComplexity.test.ts +0 -23
- package/src/core/metrics/calculateCyclomaticComplexity.ts +0 -36
- package/src/core/metrics/calculateMaintainabilityIndex.test.ts +0 -38
- package/src/core/metrics/calculateMaintainabilityIndex.ts +0 -47
- package/src/core/project/parseProject.test.ts +0 -19
- package/src/core/project/parseProject.ts +0 -216
- package/src/core/properties/locateProperties.test.ts +0 -19
- package/src/core/properties/locateProperties.ts +0 -41
- package/src/core/properties/propertyCheckBeReadonly.test.ts +0 -32
- package/src/core/properties/propertyCheckBeReadonly.ts +0 -27
- package/src/core/properties/types.ts +0 -12
- package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.test.ts +0 -30
- package/src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.ts +0 -23
- package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.test.ts +0 -30
- package/src/core/shared/sharedCheckHaveMinMaintainabilityIndex.ts +0 -23
- package/src/core/shared/sharedCheckHaveModifier.test.ts +0 -31
- package/src/core/shared/sharedCheckHaveModifier.ts +0 -51
- package/src/core/shared/sharedCheckHaveNameMatchingFileName.test.ts +0 -17
- package/src/core/shared/sharedCheckHaveNameMatchingFileName.ts +0 -36
- package/src/core/shared/sharedCheckMatchNamePattern.test.ts +0 -29
- package/src/core/shared/sharedCheckMatchNamePattern.ts +0 -22
- package/src/core/slices/locateSlices.test.ts +0 -22
- package/src/core/slices/locateSlices.ts +0 -35
- package/src/core/slices/sliceCheckBeFreeOfCycles.test.ts +0 -26
- package/src/core/slices/sliceCheckBeFreeOfCycles.ts +0 -91
- package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.test.ts +0 -27
- package/src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.ts +0 -110
- package/src/core/slices/types.ts +0 -9
- package/src/core/testUtils.ts +0 -61
- package/src/core/types.ts +0 -19
- package/src/core/utils/ruleBuilder.test.ts +0 -24
- package/src/core/utils/ruleBuilder.ts +0 -28
- package/src/index.ts +0 -35
- package/src/matchers/index.ts +0 -331
- package/test/architecture.test.ts +0 -152
- package/tsconfig.json +0 -18
- package/vite.config.ts +0 -18
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckExtendClass.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveModifier.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckHaveNameMatchingFileName.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckImplementInterface.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckMatchNamePattern.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/classes/classCheckResideInFolder.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/checkDependOnFilesInFolder.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckBeFreeOfCycles.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMaxExportedFunctions.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckHaveMinMaintainabilityIndex.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/files/fileCheckMatchNamePattern.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveExplicitReturnType.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveMaxCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveMinMaintainabilityIndex.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveModifier.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckHaveNameMatchingFileName.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/functions/functionCheckMatchNamePattern.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/checkLayeredArchitecture.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layer.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layerShouldNotBeAccessedByAnyLayer.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/layers/layerShouldOnlyBeAccessedBy.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/metrics/calculateCyclomaticComplexity.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/metrics/calculateMaintainabilityIndex.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/properties/propertyCheckBeReadonly.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/slices/sliceCheckBeFreeOfCycles.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/slices/sliceCheckHaveMaxDistanceFromMainSequence.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/types.d.ts +0 -0
- /package/{dist/src/core → node_modules/@archest/core/dist}/utils/ruleBuilder.d.ts +0 -0
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/core/classes/classCheckExtendClass.ts","../src/core/metrics/calculateCyclomaticComplexity.ts","../src/core/utils/ruleBuilder.ts","../src/core/shared/sharedCheckHaveMaxCyclomaticComplexity.ts","../src/core/classes/classCheckHaveMaxCyclomaticComplexity.ts","../src/core/shared/sharedCheckHaveModifier.ts","../src/core/classes/classCheckHaveModifier.ts","../src/core/shared/sharedCheckHaveNameMatchingFileName.ts","../src/core/classes/classCheckHaveNameMatchingFileName.ts","../src/core/classes/classCheckImplementInterface.ts","../src/core/shared/sharedCheckMatchNamePattern.ts","../src/core/classes/classCheckMatchNamePattern.ts","../src/core/classes/classCheckResideInFolder.ts","../src/core/classes/locateClasses.ts","../src/core/files/getFileDependencies.ts","../src/core/files/checkDependOnFilesInFolder.ts","../src/core/files/fileCheckBeFreeOfCycles.ts","../src/core/files/fileCheckHaveMaxCyclomaticComplexity.ts","../src/core/files/fileCheckHaveMaxExportedFunctions.ts","../src/core/metrics/calculateMaintainabilityIndex.ts","../src/core/shared/sharedCheckHaveMinMaintainabilityIndex.ts","../src/core/files/fileCheckHaveMinMaintainabilityIndex.ts","../src/core/files/fileCheckMatchNamePattern.ts","../src/core/files/locateFiles.ts","../src/core/functions/functionCheckHaveExplicitReturnType.ts","../src/core/functions/functionCheckHaveMaxCyclomaticComplexity.ts","../src/core/functions/functionCheckHaveMinMaintainabilityIndex.ts","../src/core/functions/functionCheckHaveModifier.ts","../src/core/functions/functionCheckHaveNameMatchingFileName.ts","../src/core/functions/functionCheckMatchNamePattern.ts","../src/core/functions/locateFunctions.ts","../src/core/layers/checkLayeredArchitecture.ts","../src/core/layers/createLayeredArchitecture.ts","../src/core/layers/layer.ts","../src/core/layers/getLayerDependencies.ts","../src/core/layers/layerShouldNotBeAccessedByAnyLayer.ts","../src/core/layers/layerShouldOnlyBeAccessedBy.ts","../src/core/properties/locateProperties.ts","../src/core/slices/locateSlices.ts","../src/core/project/parseProject.ts","../src/core/properties/propertyCheckBeReadonly.ts","../src/core/slices/sliceCheckBeFreeOfCycles.ts","../src/core/slices/sliceCheckHaveMaxDistanceFromMainSequence.ts","../src/matchers/index.ts"],"sourcesContent":["import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckExtendClass(\n locator: ClassLocatorData,\n className: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const c of locator.classes) {\n const name = c.name?.text || 'Anonymous';\n let matches = false;\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ExtendsKeyword) {\n for (const type of clause.types) {\n if (\n ts.isIdentifier(type.expression) &&\n type.expression.text === className\n ) {\n matches = true;\n break;\n }\n }\n }\n }\n }\n if (isNot && matches) {\n violations.push(`Class ${name} extends ${className}, but it shouldn't.`);\n } else if (!isNot && !matches) {\n violations.push(\n `Class ${name} does not extend ${className}, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\n\nexport function calculateCyclomaticComplexity(node: ts.Node): number {\n let complexity = 1;\n\n const visit = (n: ts.Node) => {\n switch (n.kind) {\n case ts.SyntaxKind.IfStatement:\n case ts.SyntaxKind.ForStatement:\n case ts.SyntaxKind.ForInStatement:\n case ts.SyntaxKind.ForOfStatement:\n case ts.SyntaxKind.WhileStatement:\n case ts.SyntaxKind.DoStatement:\n case ts.SyntaxKind.CaseClause:\n case ts.SyntaxKind.CatchClause:\n case ts.SyntaxKind.ConditionalExpression:\n complexity++;\n break;\n case ts.SyntaxKind.BinaryExpression: {\n const binary = n as ts.BinaryExpression;\n if (\n binary.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||\n binary.operatorToken.kind === ts.SyntaxKind.BarBarToken ||\n binary.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken\n ) {\n complexity++;\n }\n break;\n }\n }\n ts.forEachChild(n, visit);\n };\n\n ts.forEachChild(node, visit);\n return complexity;\n}\n","import type { RuleResult } from '../types';\n\nexport function ruleBuilder<T>(\n items: T[],\n isNot: boolean,\n evaluate: (item: T) => {\n passes: boolean;\n failMessage: string;\n failNotMessage: string;\n },\n): RuleResult {\n const violations: string[] = [];\n\n for (const item of items) {\n const { passes, failMessage, failNotMessage } = evaluate(item);\n\n if (isNot && passes) {\n if (failNotMessage) violations.push(failNotMessage);\n } else if (!isNot && !passes) {\n if (failMessage) violations.push(failMessage);\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveMaxCyclomaticComplexity<T>(\n items: T[],\n getName: (item: T) => string | undefined,\n getComplexity: (item: T) => number,\n label: string,\n max: number,\n isNot: boolean,\n) {\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const complexity = getComplexity(item);\n const exceeds = complexity > max;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes: !exceeds,\n failMessage: `${desc} has a total cyclomatic complexity of ${complexity}, which exceeds the maximum of ${max}.`,\n failNotMessage: `${desc} has a total cyclomatic complexity of ${complexity}, which exceeds the maximum of ${max}, but it shouldn't.`,\n };\n });\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from '../metrics/calculateCyclomaticComplexity';\nimport { sharedCheckHaveMaxCyclomaticComplexity } from '../shared/sharedCheckHaveMaxCyclomaticComplexity';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckHaveMaxCyclomaticComplexity(\n locator: ClassLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMaxCyclomaticComplexity(\n locator.classes,\n (c) => c.name?.text,\n (c) => {\n let complexity = 0;\n const visit = (node: ts.Node) => {\n if (\n ts.isMethodDeclaration(node) ||\n ts.isConstructorDeclaration(node) ||\n ts.isGetAccessor(node) ||\n ts.isSetAccessor(node)\n ) {\n complexity += calculateCyclomaticComplexity(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(c);\n return complexity;\n },\n 'Class',\n max,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveModifier<T extends ts.Node>(\n items: T[],\n getName: (item: T) => string | undefined,\n label: string,\n modifierStr: string,\n isNot: boolean,\n) {\n let targetKind: ts.SyntaxKind;\n switch (modifierStr) {\n case 'export':\n targetKind = ts.SyntaxKind.ExportKeyword;\n break;\n case 'default':\n targetKind = ts.SyntaxKind.DefaultKeyword;\n break;\n case 'abstract':\n targetKind = ts.SyntaxKind.AbstractKeyword;\n break;\n case 'async':\n targetKind = ts.SyntaxKind.AsyncKeyword;\n break;\n case 'public':\n targetKind = ts.SyntaxKind.PublicKeyword;\n break;\n case 'private':\n targetKind = ts.SyntaxKind.PrivateKeyword;\n break;\n default:\n throw new Error(`Modifier ${modifierStr} is not fully supported.`);\n }\n\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const modifiers = ts.canHaveModifiers(item)\n ? ts.getModifiers(item)\n : undefined;\n const passes = modifiers\n ? modifiers.some((m: ts.Modifier) => m.kind === targetKind)\n : false;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes,\n failMessage: `${desc} does not have modifier ${modifierStr}, but it should.`,\n failNotMessage: `${desc} has modifier ${modifierStr}, but it shouldn't.`,\n };\n });\n}\n","import { sharedCheckHaveModifier } from '../shared/sharedCheckHaveModifier';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckHaveModifier(\n locator: ClassLocatorData,\n modifierStr: string,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveModifier(\n locator.classes,\n (c) => c.name?.text,\n 'Class',\n modifierStr,\n isNot,\n );\n}\n","import * as path from 'node:path';\nimport * as ts from 'typescript';\nimport { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveNameMatchingFileName<T extends ts.Node>(\n items: T[],\n getName: (item: T) => string | undefined,\n label: string,\n isNot: boolean,\n) {\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const sourceFile = item.getSourceFile\n ? item.getSourceFile()\n : item.parent\n ? ts.getSourceFileOfNode(item)\n : undefined;\n\n if (!sourceFile) {\n return { passes: true, failMessage: '', failNotMessage: '' };\n }\n\n const basename = path.basename(\n sourceFile.fileName,\n path.extname(sourceFile.fileName),\n );\n const passes = name === basename;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes,\n failMessage: `${desc} does not have a name matching its filename ${basename}, but it should.`,\n failNotMessage: `${desc} has a name matching its filename ${basename}, but it shouldn't.`,\n };\n });\n}\n","import { sharedCheckHaveNameMatchingFileName } from '../shared/sharedCheckHaveNameMatchingFileName';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckHaveNameMatchingFileName(\n locator: ClassLocatorData,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveNameMatchingFileName(\n locator.classes,\n (c) => c.name?.text,\n 'Class',\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckImplementInterface(\n locator: ClassLocatorData,\n interfaceName: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const c of locator.classes) {\n const name = c.name?.text || 'Anonymous';\n let matches = false;\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ImplementsKeyword) {\n for (const type of clause.types) {\n if (\n ts.isIdentifier(type.expression) &&\n type.expression.text === interfaceName\n ) {\n matches = true;\n break;\n }\n }\n }\n }\n }\n if (isNot && matches) {\n violations.push(\n `Class ${name} implements ${interfaceName}, but it shouldn't.`,\n );\n } else if (!isNot && !matches) {\n violations.push(\n `Class ${name} does not implement ${interfaceName}, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckMatchNamePattern<T>(\n items: T[],\n getName: (item: T) => string | undefined,\n label: string,\n pattern: string | RegExp,\n isNot: boolean,\n) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const passes = name ? regex.test(name) : false;\n const desc = `${label} ${name || 'Anonymous'}`;\n return {\n passes,\n failMessage: `${desc} does not match pattern ${pattern}, but it should.`,\n failNotMessage: `${desc} matches pattern ${pattern}, but it shouldn't.`,\n };\n });\n}\n","import { sharedCheckMatchNamePattern } from '../shared/sharedCheckMatchNamePattern';\nimport type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckMatchNamePattern(\n locator: ClassLocatorData,\n pattern: string | RegExp,\n isNot: boolean,\n): RuleResult {\n return sharedCheckMatchNamePattern(\n locator.classes,\n (c) => c.name?.text,\n 'Class',\n pattern,\n isNot,\n );\n}\n","import type { RuleResult } from '../types';\nimport type { ClassLocatorData } from './types';\n\nexport function classCheckResideInFolder(\n locator: ClassLocatorData,\n targetFolder: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const c of locator.classes) {\n const className = c.name?.text || 'Anonymous Class';\n const sourceFile = c.getSourceFile();\n const inTargetFolder =\n sourceFile.fileName.includes(`/${targetFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${targetFolder}\\\\`);\n\n if (isNot && inTargetFolder) {\n violations.push(\n `Class ${className} resides in ${targetFolder}, but it shouldn't.`,\n );\n } else if (!isNot && !inTargetFolder) {\n violations.push(\n `Class ${className} does not reside in ${targetFolder}, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\nimport type { ClassLocatorData, ClassQueryOptions } from './types';\n\nexport function locateClasses(\n classes: ts.ClassDeclaration[],\n program: ts.Program,\n options?: ClassQueryOptions,\n): ClassLocatorData {\n let filtered = classes;\n\n if (options?.inFolder) {\n filtered = filtered.filter((c) => {\n const sourceFile = c.getSourceFile\n ? c.getSourceFile()\n : c.parent\n ? ts.getSourceFileOfNode(c)\n : undefined;\n if (!sourceFile) return false;\n return (\n sourceFile.fileName.includes(`/${options.inFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`)\n );\n });\n }\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : options.matchNamePattern;\n filtered = filtered.filter((c) => {\n const name = c.name?.text;\n return name && regex.test(name);\n });\n }\n if (options?.withDecorator) {\n filtered = filtered.filter((c) => {\n const decorators = ts.canHaveDecorators(c)\n ? ts.getDecorators(c)\n : undefined;\n let hasDecorator = false;\n if (decorators) {\n for (const dec of decorators) {\n const exp = dec.expression;\n let name = '';\n if (ts.isIdentifier(exp)) {\n name = exp.text;\n } else if (\n ts.isCallExpression(exp) &&\n ts.isIdentifier(exp.expression)\n ) {\n name = exp.expression.text;\n }\n if (name === options.withDecorator) {\n hasDecorator = true;\n }\n }\n }\n return hasDecorator;\n });\n }\n if (options?.extending) {\n filtered = filtered.filter((c) => {\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ExtendsKeyword) {\n for (const type of clause.types) {\n if (\n ts.isIdentifier(type.expression) &&\n type.expression.text === options.extending\n ) {\n return true;\n }\n }\n }\n }\n }\n return false;\n });\n }\n if (options?.implementing) {\n filtered = filtered.filter((c) => {\n if (c.heritageClauses) {\n for (const clause of c.heritageClauses) {\n if (clause.token === ts.SyntaxKind.ImplementsKeyword) {\n for (const type of clause.types) {\n if (\n ts.isIdentifier(type.expression) &&\n type.expression.text === options.implementing\n ) {\n return true;\n }\n }\n }\n }\n }\n return false;\n });\n }\n if (options?.havingModifier) {\n let targetKind: ts.SyntaxKind;\n switch (options.havingModifier) {\n case 'export':\n targetKind = ts.SyntaxKind.ExportKeyword;\n break;\n case 'default':\n targetKind = ts.SyntaxKind.DefaultKeyword;\n break;\n case 'abstract':\n targetKind = ts.SyntaxKind.AbstractKeyword;\n break;\n default:\n throw new Error(\n `Modifier ${options.havingModifier} is not fully supported.`,\n );\n }\n filtered = filtered.filter((c) => {\n const modifiers = ts.canHaveModifiers(c) ? ts.getModifiers(c) : undefined;\n return modifiers?.some((m: ts.Modifier) => m.kind === targetKind);\n });\n }\n\n return {\n type: 'ClassLocator',\n classes: filtered,\n program,\n };\n}\n","import * as ts from 'typescript';\n\nexport function getFileDependencies(\n sourceFile: ts.SourceFile,\n program: ts.Program,\n): string[] {\n const dependencies: string[] = [];\n const compilerOptions = program.getCompilerOptions();\n\n const visit = (node: ts.Node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys,\n );\n if (resolved.resolvedModule?.resolvedFileName) {\n if (!resolved.resolvedModule.isExternalLibraryImport) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys,\n );\n if (resolved.resolvedModule?.resolvedFileName) {\n if (!resolved.resolvedModule.isExternalLibraryImport) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return dependencies;\n}\n","import type { RuleResult } from '../types';\nimport { getFileDependencies } from './getFileDependencies';\nimport type { FileLocatorData } from './types';\n\nexport function checkDependOnFilesInFolder(\n locator: FileLocatorData,\n targetFolder: string,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n\n for (const file of locator.files) {\n const dependencies = getFileDependencies(file, locator.program);\n\n const dependsOnTarget = dependencies.some(\n (depPath) =>\n depPath.includes(`/${targetFolder}/`) ||\n depPath.includes(`\\\\${targetFolder}\\\\`),\n );\n\n if (isNot && dependsOnTarget) {\n violations.push(\n `File ${file.fileName} depends on files in ${targetFolder}, but it shouldn't.`,\n );\n } else if (!isNot && !dependsOnTarget) {\n violations.push(\n `File ${file.fileName} does not depend on files in ${targetFolder}, but it should.`,\n );\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import type { RuleResult } from '../types';\nimport { getFileDependencies } from './getFileDependencies';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckBeFreeOfCycles(\n locator: FileLocatorData,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n const targetedFilePaths = new Set<string>(\n locator.files.map((f) => f.fileName),\n );\n const graph = new Map<string, string[]>();\n\n for (const file of locator.files) {\n const filePath = file.fileName;\n const dependencies = getFileDependencies(file, locator.program).filter(\n (p) => targetedFilePaths.has(p),\n );\n\n graph.set(filePath, dependencies);\n }\n\n const visited = new Set<string>();\n const recStack = new Set<string>();\n const cycles: string[][] = [];\n\n const isCyclicUtil = (node: string, path: string[]) => {\n if (recStack.has(node)) {\n const cycleStartIndex = path.indexOf(node);\n const cycleStr = [...path.slice(cycleStartIndex), node].join('->');\n if (!cycles.some((c) => c.join('->') === cycleStr)) {\n cycles.push([...path.slice(cycleStartIndex), node]);\n }\n return true;\n }\n\n if (visited.has(node)) return false;\n\n visited.add(node);\n recStack.add(node);\n path.push(node);\n\n const neighbors = graph.get(node) || [];\n for (const neighbor of neighbors) {\n isCyclicUtil(neighbor, path);\n }\n\n recStack.delete(node);\n path.pop();\n return false;\n };\n\n for (const node of graph.keys()) {\n if (!visited.has(node)) {\n isCyclicUtil(node, []);\n }\n }\n\n if (isNot && cycles.length === 0) {\n violations.push('Expected cyclic dependencies, but found none.');\n } else if (!isNot && cycles.length > 0) {\n for (const cycle of cycles) {\n violations.push(`Cycle detected: ${cycle.join(' -> ')}`);\n }\n }\n\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from '../metrics/calculateCyclomaticComplexity';\nimport { sharedCheckHaveMaxCyclomaticComplexity } from '../shared/sharedCheckHaveMaxCyclomaticComplexity';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckHaveMaxCyclomaticComplexity(\n locator: FileLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMaxCyclomaticComplexity(\n locator.files,\n (f) => f.fileName,\n (file) => {\n let complexity = 0;\n const visit = (node: ts.Node) => {\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isArrowFunction(node) ||\n ts.isFunctionExpression(node)\n ) {\n complexity += calculateCyclomaticComplexity(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(file);\n return complexity;\n },\n 'File',\n max,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckHaveMaxExportedFunctions(\n locator: FileLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const file of locator.files) {\n let exportedFuncCount = 0;\n\n ts.forEachChild(file, (node) => {\n if (ts.isFunctionDeclaration(node)) {\n const modifiers = ts.canHaveModifiers(node)\n ? ts.getModifiers(node)\n : undefined;\n if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {\n exportedFuncCount++;\n }\n }\n });\n\n const exceeds = exportedFuncCount > max;\n\n if (isNot && exceeds) {\n violations.push(\n `File ${file.fileName} has ${exportedFuncCount} exported functions, which exceeds the maximum of ${max}, but it shouldn't.`,\n );\n } else if (!isNot && exceeds) {\n violations.push(\n `File ${file.fileName} has ${exportedFuncCount} exported functions, which exceeds the maximum of ${max}.`,\n );\n }\n }\n return {\n pass: isNot ? violations.length > 0 : violations.length === 0,\n message: () =>\n violations.join('\\n') ||\n (isNot\n ? 'Expected some files to exceed maximum exported functions, but none did.'\n : ''),\n };\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from './calculateCyclomaticComplexity';\n\nexport function calculateMaintainabilityIndex(node: ts.Node): number {\n let operators = 0;\n let operands = 0;\n const uniqueOperators = new Set<number>();\n const uniqueOperands = new Set<string>();\n let linesOfCode = 1;\n\n const sourceFile = node.getSourceFile();\n if (sourceFile) {\n const start = sourceFile.getLineAndCharacterOfPosition(node.getStart());\n const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd());\n linesOfCode = end.line - start.line + 1;\n }\n\n const visit = (n: ts.Node) => {\n if (\n ts.isBinaryExpression(n) ||\n ts.isPrefixUnaryExpression(n) ||\n ts.isPostfixUnaryExpression(n)\n ) {\n operators++;\n uniqueOperators.add(n.kind);\n } else if (ts.isIdentifier(n) || ts.isLiteralExpression(n)) {\n operands++;\n uniqueOperands.add(n.getText(sourceFile));\n }\n ts.forEachChild(n, visit);\n };\n\n visit(node);\n\n const N = operators + operands;\n const n = uniqueOperators.size + uniqueOperands.size;\n const V = n === 0 ? 0 : N * Math.log2(n);\n const CC = calculateCyclomaticComplexity(node);\n\n const mi = Math.max(\n 0,\n ((171 - 5.2 * Math.log(V || 1) - 0.23 * CC - 16.2 * Math.log(linesOfCode)) *\n 100) /\n 171,\n );\n return mi;\n}\n","import { ruleBuilder } from '../utils/ruleBuilder';\n\nexport function sharedCheckHaveMinMaintainabilityIndex<T>(\n items: T[],\n getName: (item: T) => string | undefined,\n getMi: (item: T) => number,\n label: string,\n min: number,\n isNot: boolean,\n) {\n return ruleBuilder(items, isNot, (item) => {\n const name = getName(item);\n const mi = getMi(item);\n const fallsBelow = mi < min;\n const desc = `${label} ${name || 'Anonymous'}`;\n\n return {\n passes: !fallsBelow,\n failMessage: `${desc} has a maintainability index of ${mi.toFixed(2)}, which falls below the minimum of ${min}.`,\n failNotMessage: `${desc} has a maintainability index of ${mi.toFixed(2)}, which falls below the minimum of ${min}, but it shouldn't.`,\n };\n });\n}\n","import { calculateMaintainabilityIndex } from '../metrics/calculateMaintainabilityIndex';\nimport { sharedCheckHaveMinMaintainabilityIndex } from '../shared/sharedCheckHaveMinMaintainabilityIndex';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckHaveMinMaintainabilityIndex(\n locator: FileLocatorData,\n min: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMinMaintainabilityIndex(\n locator.files,\n (f) => f.fileName,\n calculateMaintainabilityIndex,\n 'File',\n min,\n isNot,\n );\n}\n","import { sharedCheckMatchNamePattern } from '../shared/sharedCheckMatchNamePattern';\nimport type { RuleResult } from '../types';\nimport type { FileLocatorData } from './types';\n\nexport function fileCheckMatchNamePattern(\n locator: FileLocatorData,\n pattern: string | RegExp,\n isNot: boolean,\n): RuleResult {\n return sharedCheckMatchNamePattern(\n locator.files,\n (f) => f.fileName,\n 'File',\n pattern,\n isNot,\n );\n}\n","import type * as ts from 'typescript';\nimport type { FileLocatorData, FileQueryOptions } from './types';\n\nexport function locateFiles(\n sourceFiles: ts.SourceFile[],\n program: ts.Program,\n options?: FileQueryOptions,\n): FileLocatorData {\n let filtered = sourceFiles;\n\n if (options?.inFolder) {\n filtered = filtered.filter(\n (file) =>\n file.fileName.includes(`/${options.inFolder}/`) ||\n file.fileName.includes(`\\\\${options.inFolder}\\\\`),\n );\n }\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : options.matchNamePattern;\n filtered = filtered.filter((file) => regex.test(file.fileName));\n }\n\n return {\n type: 'FileLocator',\n files: filtered,\n program,\n };\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveExplicitReturnType(\n locator: FunctionLocatorData,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const f of locator.functions) {\n const name =\n f.name && ts.isIdentifier(f.name) ? f.name.text : 'Anonymous Function';\n const hasType = !!f.type;\n\n if (isNot && hasType) {\n violations.push(\n `Function ${name} has an explicit return type, but it shouldn't.`,\n );\n } else if (!isNot && !hasType) {\n violations.push(\n `Function ${name} does not have an explicit return type, but it should.`,\n );\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\nimport { calculateCyclomaticComplexity } from '../metrics/calculateCyclomaticComplexity';\nimport { sharedCheckHaveMaxCyclomaticComplexity } from '../shared/sharedCheckHaveMaxCyclomaticComplexity';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveMaxCyclomaticComplexity(\n locator: FunctionLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMaxCyclomaticComplexity(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n calculateCyclomaticComplexity,\n 'Function',\n max,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { calculateMaintainabilityIndex } from '../metrics/calculateMaintainabilityIndex';\nimport { sharedCheckHaveMinMaintainabilityIndex } from '../shared/sharedCheckHaveMinMaintainabilityIndex';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveMinMaintainabilityIndex(\n locator: FunctionLocatorData,\n min: number,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveMinMaintainabilityIndex(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n calculateMaintainabilityIndex,\n 'Function',\n min,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { sharedCheckHaveModifier } from '../shared/sharedCheckHaveModifier';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveModifier(\n locator: FunctionLocatorData,\n modifierStr: string,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveModifier(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n 'Function',\n modifierStr,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { sharedCheckHaveNameMatchingFileName } from '../shared/sharedCheckHaveNameMatchingFileName';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckHaveNameMatchingFileName(\n locator: FunctionLocatorData,\n isNot: boolean,\n): RuleResult {\n return sharedCheckHaveNameMatchingFileName(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n 'Function',\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport { sharedCheckMatchNamePattern } from '../shared/sharedCheckMatchNamePattern';\nimport type { RuleResult } from '../types';\nimport type { FunctionLocatorData } from './types';\n\nexport function functionCheckMatchNamePattern(\n locator: FunctionLocatorData,\n pattern: string | RegExp,\n isNot: boolean,\n): RuleResult {\n return sharedCheckMatchNamePattern(\n locator.functions,\n (f) => (f.name && ts.isIdentifier(f.name) ? f.name.text : undefined),\n 'Function',\n pattern,\n isNot,\n );\n}\n","import * as ts from 'typescript';\nimport type { FunctionLocatorData, FunctionQueryOptions } from './types';\n\nexport function locateFunctions(\n functions: ts.FunctionLikeDeclaration[],\n program: ts.Program,\n options?: FunctionQueryOptions,\n): FunctionLocatorData {\n let filtered = functions;\n\n if (options?.inFolder) {\n filtered = filtered.filter((f) => {\n const sourceFile = f.getSourceFile\n ? f.getSourceFile()\n : f.parent\n ? ts.getSourceFileOfNode(f)\n : undefined;\n if (!sourceFile) return false;\n return (\n sourceFile.fileName.includes(`/${options.inFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`)\n );\n });\n }\n\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : options.matchNamePattern;\n filtered = filtered.filter((f) => {\n return f.name && ts.isIdentifier(f.name) && regex.test(f.name.text);\n });\n }\n\n if (options?.isTopLevel) {\n filtered = filtered.filter((f) => {\n return ts.isSourceFile(f.parent);\n });\n }\n\n return {\n type: 'FunctionLocator',\n functions: filtered,\n program,\n };\n}\n","import type { RuleResult } from '../types';\nimport type { LayeredArchitectureData } from './types';\n\nexport function checkLayeredArchitecture(\n data: LayeredArchitectureData,\n): RuleResult {\n const violations: string[] = [];\n for (const assertion of data.assertions) {\n violations.push(...assertion(data.files));\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import type * as ts from 'typescript';\nimport type { LayeredArchitectureData } from './types';\n\nexport function createLayeredArchitecture(\n files: ts.SourceFile[],\n program: ts.Program,\n): LayeredArchitectureData {\n return {\n type: 'LayeredArchitecture',\n files,\n layers: new Map<string, string>(),\n assertions: [],\n program,\n };\n}\n","import type { LayeredArchitectureData } from './types';\n\nexport function layer(\n data: LayeredArchitectureData,\n name: string,\n folderPattern: string,\n): LayeredArchitectureData {\n data.layers.set(name, folderPattern);\n return data;\n}\n","import * as ts from 'typescript';\n\nexport function getLayerDependencies(\n sourceFile: ts.SourceFile,\n program: ts.Program,\n): string[] {\n const dependencies: string[] = [];\n const compilerOptions = program.getCompilerOptions();\n\n const visit = (node: ts.Node) => {\n if (ts.isImportDeclaration(node)) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys,\n );\n if (\n resolved.resolvedModule?.resolvedFileName &&\n !resolved.resolvedModule.isExternalLibraryImport\n ) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {\n const moduleSpecifier = (node.moduleSpecifier as ts.StringLiteral).text;\n const resolved = ts.resolveModuleName(\n moduleSpecifier,\n sourceFile.fileName,\n compilerOptions,\n ts.sys,\n );\n if (\n resolved.resolvedModule?.resolvedFileName &&\n !resolved.resolvedModule.isExternalLibraryImport\n ) {\n dependencies.push(resolved.resolvedModule.resolvedFileName);\n }\n }\n ts.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n return dependencies;\n}\n","import { getLayerDependencies } from './getLayerDependencies';\nimport type { LayeredArchitectureData } from './types';\n\nexport function layerShouldNotBeAccessedByAnyLayer(\n data: LayeredArchitectureData,\n targetLayer: string,\n): LayeredArchitectureData {\n if (!data.layers.has(targetLayer)) {\n throw new Error(`Layer ${targetLayer} is not defined`);\n }\n\n data.assertions.push((files) => {\n const violations: string[] = [];\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const targetPattern = data.layers.get(targetLayer)!;\n\n for (const file of files) {\n const filePath = file.fileName;\n if (\n !filePath.includes(`/${targetPattern}/`) &&\n !filePath.includes(`\\\\${targetPattern}\\\\`)\n ) {\n const dependencies = getLayerDependencies(file, data.program);\n const importsTarget = dependencies.some(\n (dep) =>\n dep.includes(`/${targetPattern}/`) ||\n dep.includes(`\\\\${targetPattern}\\\\`),\n );\n if (importsTarget) {\n violations.push(\n `File ${filePath} accesses layer ${targetLayer} but it shouldn't.`,\n );\n }\n }\n }\n return violations;\n });\n\n return data;\n}\n","import { getLayerDependencies } from './getLayerDependencies';\nimport type { LayeredArchitectureData } from './types';\n\nexport function layerShouldOnlyBeAccessedBy(\n data: LayeredArchitectureData,\n targetLayer: string,\n allowedLayers: string[],\n): LayeredArchitectureData {\n if (!data.layers.has(targetLayer)) {\n throw new Error(`Layer ${targetLayer} is not defined`);\n }\n\n data.assertions.push((files) => {\n const violations: string[] = [];\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const targetPattern = data.layers.get(targetLayer)!;\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const allowedPatterns = allowedLayers.map((l) => data.layers.get(l)!);\n\n for (const file of files) {\n const filePath = file.fileName;\n const isInAllowedLayer = allowedPatterns.some(\n (p) => filePath.includes(`/${p}/`) || filePath.includes(`\\\\${p}\\\\`),\n );\n\n if (\n !filePath.includes(`/${targetPattern}/`) &&\n !filePath.includes(`\\\\${targetPattern}\\\\`) &&\n !isInAllowedLayer\n ) {\n const dependencies = getLayerDependencies(file, data.program);\n const importsTarget = dependencies.some(\n (dep) =>\n dep.includes(`/${targetPattern}/`) ||\n dep.includes(`\\\\${targetPattern}\\\\`),\n );\n if (importsTarget) {\n violations.push(\n `File ${filePath} accesses layer ${targetLayer} but only ${allowedLayers.join(', ')} are allowed.`,\n );\n }\n }\n }\n return violations;\n });\n\n return data;\n}\n","import * as ts from 'typescript';\nimport type { PropertyLocatorData, PropertyQueryOptions } from './types';\n\nexport function locateProperties(\n properties: ts.PropertyDeclaration[],\n program: ts.Program,\n options?: PropertyQueryOptions,\n): PropertyLocatorData {\n let filtered = properties;\n\n if (options?.inFolder) {\n filtered = filtered.filter((p) => {\n const sourceFile = p.getSourceFile\n ? p.getSourceFile()\n : p.parent\n ? ts.getSourceFileOfNode(p)\n : undefined;\n if (!sourceFile) return false;\n return (\n sourceFile.fileName.includes(`/${options.inFolder}/`) ||\n sourceFile.fileName.includes(`\\\\${options.inFolder}\\\\`)\n );\n });\n }\n\n if (options?.matchNamePattern) {\n const regex =\n typeof options.matchNamePattern === 'string'\n ? new RegExp(options.matchNamePattern)\n : options.matchNamePattern;\n filtered = filtered.filter((p) => {\n return ts.isIdentifier(p.name) && regex.test(p.name.text);\n });\n }\n\n return {\n type: 'PropertyLocator',\n properties: filtered,\n program,\n };\n}\n","import type * as ts from 'typescript';\nimport type { SliceLocatorData } from './types';\n\nexport function locateSlices(\n sourceFiles: ts.SourceFile[],\n program: ts.Program,\n pattern: string,\n): SliceLocatorData {\n const escaped = pattern.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const regexStr = escaped.replace(/\\*/g, '([^/\\\\\\\\]+)');\n const slicePattern = new RegExp(regexStr);\n\n const sliceIds = new Set<string>();\n const sliceFiles = new Map<string, ts.SourceFile[]>();\n\n for (const sf of sourceFiles) {\n const match = sf.fileName.match(slicePattern);\n if (match?.[1]) {\n const sliceId = match[1];\n sliceIds.add(sliceId);\n if (!sliceFiles.has(sliceId)) {\n sliceFiles.set(sliceId, []);\n }\n sliceFiles.get(sliceId)?.push(sf);\n }\n }\n\n return {\n type: 'SliceLocator',\n slicePattern,\n sliceIds,\n sliceFiles,\n program,\n };\n}\n","import { dirname } from 'node:path';\nimport * as ts from 'typescript';\nimport { locateClasses } from '../classes/locateClasses';\nimport type { ClassQueryOptions } from '../classes/types';\nimport { locateFiles } from '../files/locateFiles';\nimport type { FileQueryOptions } from '../files/types';\nimport { locateFunctions } from '../functions/locateFunctions';\nimport type { FunctionQueryOptions } from '../functions/types';\nimport { checkLayeredArchitecture } from '../layers/checkLayeredArchitecture';\nimport { createLayeredArchitecture } from '../layers/createLayeredArchitecture';\nimport { layer } from '../layers/layer';\nimport { layerShouldNotBeAccessedByAnyLayer } from '../layers/layerShouldNotBeAccessedByAnyLayer';\nimport { layerShouldOnlyBeAccessedBy } from '../layers/layerShouldOnlyBeAccessedBy';\nimport { locateProperties } from '../properties/locateProperties';\nimport type { PropertyQueryOptions } from '../properties/types';\nimport { locateSlices } from '../slices/locateSlices';\n\nexport function parseProject(options: { tsConfigFilePath?: string } = {}) {\n let compilerOptions: ts.CompilerOptions = {};\n const configPath =\n options.tsConfigFilePath ||\n ts.findConfigFile(process.cwd(), ts.sys.fileExists, 'tsconfig.json');\n\n let program: ts.Program;\n\n if (configPath) {\n const configFile = ts.readConfigFile(configPath, ts.sys.readFile);\n const parsedCommandLine = ts.parseJsonConfigFileContent(\n configFile.config,\n ts.sys,\n dirname(configPath),\n undefined,\n configPath,\n undefined,\n [\n {\n extension: '.vue',\n isMixedContent: true,\n scriptKind: ts.ScriptKind.TS,\n },\n {\n extension: '.svelte',\n isMixedContent: true,\n scriptKind: ts.ScriptKind.TS,\n },\n ],\n );\n compilerOptions = parsedCommandLine.options;\n\n const host = ts.createCompilerHost(compilerOptions);\n const originalGetSourceFile = host.getSourceFile;\n\n // biome-ignore lint/suspicious/noExplicitAny: Dynamic require\n let vueCompiler: any;\n try {\n vueCompiler = require('@vue/compiler-sfc');\n } catch (_e) {\n // Not a Vue project\n }\n\n host.getSourceFile = (\n fileName,\n languageVersion,\n onError,\n shouldCreateNewSourceFile,\n ) => {\n if (fileName.endsWith('.vue')) {\n const content = ts.sys.readFile(fileName);\n if (content) {\n let scriptContent = '';\n if (vueCompiler) {\n const parsed = vueCompiler.parse(content);\n const script = parsed.descriptor.script;\n const scriptSetup = parsed.descriptor.scriptSetup;\n if (script) scriptContent += `${script.content}\\n`;\n if (scriptSetup) scriptContent += `${scriptSetup.content}\\n`;\n } else {\n const match = content.match(/<script[^>]*>(.*?)<\\/script>/s);\n if (match) scriptContent = match[1];\n }\n return ts.createSourceFile(\n fileName,\n scriptContent,\n languageVersion,\n true,\n ts.ScriptKind.TS,\n );\n }\n }\n\n if (fileName.endsWith('.svelte')) {\n const content = ts.sys.readFile(fileName);\n if (content) {\n let scriptContent = '';\n const match = content.match(/<script[^>]*>(.*?)<\\/script>/s);\n if (match) scriptContent = match[1];\n return ts.createSourceFile(\n fileName,\n scriptContent,\n languageVersion,\n true,\n ts.ScriptKind.TS,\n );\n }\n }\n\n return originalGetSourceFile(\n fileName,\n languageVersion,\n onError,\n shouldCreateNewSourceFile,\n );\n };\n\n program = ts.createProgram({\n rootNames: parsedCommandLine.fileNames,\n options: compilerOptions,\n host: host,\n });\n\n // Force the TypeScript compiler to bind the AST and populate .parent pointers\n program.getTypeChecker();\n } else {\n throw new Error('Could not find tsconfig.json');\n }\n\n const getSourceFiles = () =>\n program\n .getSourceFiles()\n .filter(\n (sf) => !sf.isDeclarationFile && !sf.fileName.includes('node_modules'),\n );\n\n return {\n getFiles: (queryOptions?: FileQueryOptions) => {\n return locateFiles(getSourceFiles(), program, queryOptions);\n },\n\n getClasses: (queryOptions?: ClassQueryOptions) => {\n const allClasses: ts.ClassDeclaration[] = [];\n for (const sf of getSourceFiles()) {\n const visit = (node: ts.Node) => {\n if (ts.isClassDeclaration(node)) {\n allClasses.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return locateClasses(allClasses, program, queryOptions);\n },\n\n layeredArchitecture: () => {\n let data = createLayeredArchitecture(getSourceFiles(), program);\n const api = {\n layer: (name: string, folderPattern: string) => {\n data = layer(data, name, folderPattern);\n return api;\n },\n whereLayer: (name: string) => {\n return {\n shouldNotBeAccessedByAnyLayer: () => {\n data = layerShouldNotBeAccessedByAnyLayer(data, name);\n return api;\n },\n shouldOnlyBeAccessedBy: (...allowedLayers: string[]) => {\n data = layerShouldOnlyBeAccessedBy(data, name, allowedLayers);\n return api;\n },\n };\n },\n check: () => checkLayeredArchitecture(data),\n get data() {\n return data;\n },\n };\n return api;\n },\n\n getFunctions: (queryOptions?: FunctionQueryOptions) => {\n const allFunctions: ts.FunctionLikeDeclaration[] = [];\n for (const sf of getSourceFiles()) {\n const visit = (node: ts.Node) => {\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isArrowFunction(node)\n ) {\n allFunctions.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return locateFunctions(allFunctions, program, queryOptions);\n },\n\n getProperties: (queryOptions?: PropertyQueryOptions) => {\n const allProperties: ts.PropertyDeclaration[] = [];\n for (const sf of getSourceFiles()) {\n const visit = (node: ts.Node) => {\n if (ts.isPropertyDeclaration(node)) {\n allProperties.push(node);\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n return locateProperties(allProperties, program, queryOptions);\n },\n\n getSlices: (pattern: string) => {\n return locateSlices(getSourceFiles(), program, pattern);\n },\n };\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { PropertyLocatorData } from './types';\n\nexport function propertyCheckBeReadonly(\n locator: PropertyLocatorData,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n for (const p of locator.properties) {\n const name = ts.isIdentifier(p.name) ? p.name.text : 'Anonymous Property';\n const modifiers = ts.canHaveModifiers(p) ? ts.getModifiers(p) : undefined;\n const matches = modifiers?.some(\n (m: ts.Modifier) => m.kind === ts.SyntaxKind.ReadonlyKeyword,\n );\n\n if (isNot && matches) {\n violations.push(`Property ${name} is readonly, but it shouldn't be.`);\n } else if (!isNot && !matches) {\n violations.push(`Property ${name} is not readonly, but it should be.`);\n }\n }\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { SliceLocatorData } from './types';\n\nexport function sliceCheckBeFreeOfCycles(\n locator: SliceLocatorData,\n isNot: boolean,\n): RuleResult {\n const graph: Map<string, Set<string>> = new Map();\n for (const slice of locator.sliceIds) {\n graph.set(slice, new Set());\n }\n\n for (const [sliceId, files] of locator.sliceFiles.entries()) {\n for (const sf of files) {\n ts.forEachChild(sf, (node) => {\n if (\n ts.isImportDeclaration(node) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n ) {\n const importPath = node.moduleSpecifier.text;\n const resolved = ts.resolveModuleName(\n importPath,\n sf.fileName,\n locator.program.getCompilerOptions(),\n ts.sys,\n );\n if (resolved.resolvedModule?.resolvedFileName) {\n const targetMatch = resolved.resolvedModule.resolvedFileName.match(\n locator.slicePattern,\n );\n if (targetMatch?.[1]) {\n const targetSlice = targetMatch[1];\n if (\n targetSlice !== sliceId &&\n locator.sliceIds.has(targetSlice)\n ) {\n graph.get(sliceId)?.add(targetSlice);\n }\n }\n }\n }\n });\n }\n }\n\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n const violations: string[] = [];\n\n const dfs = (node: string, path: string[]): boolean => {\n visited.add(node);\n recursionStack.add(node);\n\n for (const neighbor of graph.get(node) || []) {\n if (!visited.has(neighbor)) {\n if (dfs(neighbor, [...path, neighbor])) return true;\n } else if (recursionStack.has(neighbor)) {\n violations.push(\n `Cycle detected between slices: ${path.join(' -> ')} -> ${neighbor}`,\n );\n return true;\n }\n }\n\n recursionStack.delete(node);\n return false;\n };\n\n for (const slice of locator.sliceIds) {\n if (!visited.has(slice)) {\n dfs(slice, [slice]);\n }\n }\n\n if (isNot) {\n return {\n pass: violations.length > 0,\n message: () =>\n violations.length > 0\n ? ''\n : 'Expected cycles between slices but found none.',\n };\n } else {\n return {\n pass: violations.length === 0,\n message: () => violations.join('\\n'),\n };\n }\n}\n","import * as ts from 'typescript';\nimport type { RuleResult } from '../types';\nimport type { SliceLocatorData } from './types';\n\nexport function sliceCheckHaveMaxDistanceFromMainSequence(\n locator: SliceLocatorData,\n max: number,\n isNot: boolean,\n): RuleResult {\n const violations: string[] = [];\n\n const ceMap = new Map<string, Set<string>>(); // Slices this slice depends on\n const caMap = new Map<string, Set<string>>(); // Slices depending on this slice\n\n for (const slice of locator.sliceIds) {\n ceMap.set(slice, new Set());\n caMap.set(slice, new Set());\n }\n\n for (const [sliceId, files] of locator.sliceFiles.entries()) {\n for (const sf of files) {\n ts.forEachChild(sf, (node) => {\n if (\n ts.isImportDeclaration(node) &&\n node.moduleSpecifier &&\n ts.isStringLiteral(node.moduleSpecifier)\n ) {\n const importPath = node.moduleSpecifier.text;\n const resolved = ts.resolveModuleName(\n importPath,\n sf.fileName,\n locator.program.getCompilerOptions(),\n ts.sys,\n );\n if (resolved.resolvedModule?.resolvedFileName) {\n const targetMatch = resolved.resolvedModule.resolvedFileName.match(\n locator.slicePattern,\n );\n if (targetMatch?.[1]) {\n const targetSlice = targetMatch[1];\n if (\n targetSlice !== sliceId &&\n locator.sliceIds.has(targetSlice)\n ) {\n ceMap.get(sliceId)?.add(targetSlice);\n caMap.get(targetSlice)?.add(sliceId);\n }\n }\n }\n }\n });\n }\n }\n\n for (const sliceId of locator.sliceIds) {\n const ce = ceMap.get(sliceId)?.size;\n const ca = caMap.get(sliceId)?.size;\n\n // biome-ignore lint/style/noNonNullAssertion: Safe map lookup\n const files = locator.sliceFiles.get(sliceId)!;\n let na = 0; // abstract classes + interfaces\n let nc = 0; // all classes + interfaces\n\n for (const sf of files) {\n const visit = (node: ts.Node) => {\n if (ts.isClassDeclaration(node)) {\n nc++;\n const modifiers = ts.canHaveModifiers(node)\n ? ts.getModifiers(node)\n : undefined;\n if (\n modifiers?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword)\n ) {\n na++;\n }\n } else if (ts.isInterfaceDeclaration(node)) {\n nc++;\n na++;\n }\n ts.forEachChild(node, visit);\n };\n visit(sf);\n }\n\n const I = ce + ca === 0 ? 0 : ce / (ca + ce);\n const A = nc === 0 ? 0 : na / nc;\n\n const D = Math.abs(A + I - 1);\n const exceeds = D > max;\n\n if (isNot && exceeds) {\n violations.push(\n `Slice ${sliceId} has a Distance from the Main Sequence of ${D.toFixed(2)}, which exceeds the maximum of ${max}, but it shouldn't.`,\n );\n } else if (!isNot && exceeds) {\n violations.push(\n `Slice ${sliceId} has a Distance from the Main Sequence of ${D.toFixed(2)}, which exceeds the maximum of ${max}.`,\n );\n }\n }\n\n return {\n pass: isNot ? violations.length > 0 : violations.length === 0,\n message: () =>\n violations.join('\\n') ||\n (isNot\n ? 'Expected some slices to exceed maximum distance from main sequence, but none did.'\n : ''),\n };\n}\n","import { expect } from 'vitest';\nimport { classCheckExtendClass } from '../core/classes/classCheckExtendClass';\nimport { classCheckHaveMaxCyclomaticComplexity } from '../core/classes/classCheckHaveMaxCyclomaticComplexity';\nimport { classCheckHaveModifier } from '../core/classes/classCheckHaveModifier';\nimport { classCheckHaveNameMatchingFileName } from '../core/classes/classCheckHaveNameMatchingFileName';\nimport { classCheckImplementInterface } from '../core/classes/classCheckImplementInterface';\nimport { classCheckMatchNamePattern } from '../core/classes/classCheckMatchNamePattern';\nimport { classCheckResideInFolder } from '../core/classes/classCheckResideInFolder';\nimport { checkDependOnFilesInFolder } from '../core/files/checkDependOnFilesInFolder';\nimport { fileCheckBeFreeOfCycles } from '../core/files/fileCheckBeFreeOfCycles';\nimport { fileCheckHaveMaxCyclomaticComplexity } from '../core/files/fileCheckHaveMaxCyclomaticComplexity';\nimport { fileCheckHaveMaxExportedFunctions } from '../core/files/fileCheckHaveMaxExportedFunctions';\nimport { fileCheckHaveMinMaintainabilityIndex } from '../core/files/fileCheckHaveMinMaintainabilityIndex';\nimport { fileCheckMatchNamePattern } from '../core/files/fileCheckMatchNamePattern';\nimport { functionCheckHaveExplicitReturnType } from '../core/functions/functionCheckHaveExplicitReturnType';\nimport { functionCheckHaveMaxCyclomaticComplexity } from '../core/functions/functionCheckHaveMaxCyclomaticComplexity';\nimport { functionCheckHaveMinMaintainabilityIndex } from '../core/functions/functionCheckHaveMinMaintainabilityIndex';\nimport { functionCheckHaveModifier } from '../core/functions/functionCheckHaveModifier';\nimport { functionCheckHaveNameMatchingFileName } from '../core/functions/functionCheckHaveNameMatchingFileName';\nimport { functionCheckMatchNamePattern } from '../core/functions/functionCheckMatchNamePattern';\nimport { checkLayeredArchitecture } from '../core/layers/checkLayeredArchitecture';\n\nimport { propertyCheckBeReadonly } from '../core/properties/propertyCheckBeReadonly';\n\nimport { sliceCheckBeFreeOfCycles } from '../core/slices/sliceCheckBeFreeOfCycles';\nimport { sliceCheckHaveMaxDistanceFromMainSequence } from '../core/slices/sliceCheckHaveMaxDistanceFromMainSequence';\nimport type { LocatorData, RuleResult } from '../core/types';\n\nexport function setupMatchers() {\n expect.extend({\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n toPass(received: any) {\n let result: RuleResult;\n\n if (received?.data && received.data.type === 'LayeredArchitecture') {\n result = checkLayeredArchitecture(received.data);\n } else {\n result = received as RuleResult;\n }\n\n const { pass, message } = result;\n return {\n pass: this.isNot ? !pass : pass,\n message: pass ? () => 'Expected rule not to pass' : () => message(),\n };\n },\n\n toResideInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckResideInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toResideInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveModifier(received: LocatorData, modifier: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckHaveModifier(received, modifier, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveModifier(received, modifier, this.isNot);\n } else {\n throw new Error(\n `toHaveModifier matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toExtendClass(received: LocatorData, className: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckExtendClass(received, className, this.isNot);\n } else {\n throw new Error(\n `toExtendClass matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toImplementInterface(received: LocatorData, interfaceName: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckImplementInterface(\n received,\n interfaceName,\n this.isNot,\n );\n } else {\n throw new Error(\n `toImplementInterface matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveExplicitReturnType(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveExplicitReturnType(received, this.isNot);\n } else {\n throw new Error(\n `toHaveExplicitReturnType matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeReadonly(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'PropertyLocator') {\n result = propertyCheckBeReadonly(received, this.isNot);\n } else {\n throw new Error(\n `toBeReadonly matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toDependOnFilesInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = checkDependOnFilesInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toDependOnFilesInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeFreeOfCycles(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckBeFreeOfCycles(received, this.isNot);\n } else if (received.type === 'SliceLocator') {\n result = sliceCheckBeFreeOfCycles(received, this.isNot);\n } else {\n throw new Error(\n `toBeFreeOfCycles matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toMatchNamePattern(received: LocatorData, pattern: string | RegExp) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckMatchNamePattern(received, pattern, this.isNot);\n } else {\n throw new Error(\n `toMatchNamePattern matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxCyclomaticComplexity(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxCyclomaticComplexity matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMinMaintainabilityIndex(received: LocatorData, min: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMinMaintainabilityIndex matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxDistanceFromMainSequence(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'SliceLocator') {\n result = sliceCheckHaveMaxDistanceFromMainSequence(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxDistanceFromMainSequence matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveNameMatchingFileName(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveNameMatchingFileName(received, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveNameMatchingFileName(received, this.isNot);\n } else {\n throw new Error(\n `toHaveNameMatchingFileName matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxExportedFunctions(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxExportedFunctions(received, max, this.isNot);\n } else {\n throw new Error(\n `toHaveMaxExportedFunctions matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n });\n}\n\ndeclare module 'vitest' {\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n interface Assertion<T = any> {\n toPass(): void;\n toResideInFolder(folder: string): void;\n toHaveModifier(\n modifier:\n | 'export'\n | 'default'\n | 'abstract'\n | 'async'\n | 'private'\n | 'public',\n ): void;\n toExtendClass(className: string): void;\n toImplementInterface(interfaceName: string): void;\n toHaveExplicitReturnType(): void;\n toBeReadonly(): void;\n toDependOnFilesInFolder(folder: string): void;\n toBeFreeOfCycles(): void;\n toMatchNamePattern(pattern: string | RegExp): void;\n toHaveMaxCyclomaticComplexity(max: number): void;\n toHaveMinMaintainabilityIndex(min: number): void;\n toHaveMaxDistanceFromMainSequence(max: number): void;\n toHaveNameMatchingFileName(): void;\n toHaveMaxExportedFunctions(max: number): void;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/matchers/index.ts"],"sourcesContent":["import {\n checkDependOnExternalModule,\n checkDependOnFilesInFolder,\n checkLayeredArchitecture,\n classCheckExtendClass,\n classCheckHaveMaxCyclomaticComplexity,\n classCheckHaveModifier,\n classCheckHaveNameMatchingFileName,\n classCheckImplementInterface,\n classCheckMatchNamePattern,\n classCheckResideInFolder,\n fileCheckBeFreeOfCycles,\n fileCheckHaveMaxCyclomaticComplexity,\n fileCheckHaveMaxExportedFunctions,\n fileCheckHaveMinMaintainabilityIndex,\n fileCheckMatchNamePattern,\n functionCheckHaveExplicitReturnType,\n functionCheckHaveMaxCyclomaticComplexity,\n functionCheckHaveMinMaintainabilityIndex,\n functionCheckHaveModifier,\n functionCheckHaveNameMatchingFileName,\n functionCheckMatchNamePattern,\n type LocatorData,\n propertyCheckBeReadonly,\n type RuleResult,\n sliceCheckBeFreeOfCycles,\n sliceCheckHaveMaxDistanceFromMainSequence,\n} from '@archest/core';\nimport { expect } from 'vitest';\n\nexport * from './models';\n\n/**\n * Registers all Archest custom matchers (e.g., `toResideInFolder`, `toHaveModifier`)\n * with the global Vitest `expect` instance.\n *\n * This function must be called exactly once before any architectural tests are run.\n * The standard way to do this is to add it to a Vitest setup file.\n *\n * @example\n * ```typescript\n * // test/setup.ts\n * import { setupMatchers } from '@archest/vitest';\n * setupMatchers();\n * ```\n */\nexport function setupMatchers() {\n expect.extend({\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n toPass(received: any) {\n let result: RuleResult;\n\n if (received?.data && received.data.type === 'LayeredArchitecture') {\n result = checkLayeredArchitecture(received.data);\n } else {\n result = received as RuleResult;\n }\n\n const { pass, message } = result;\n return {\n pass: this.isNot ? !pass : pass,\n message: pass ? () => 'Expected rule not to pass' : () => message(),\n };\n },\n\n toResideInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckResideInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toResideInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveModifier(received: LocatorData, modifier: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckHaveModifier(received, modifier, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveModifier(received, modifier, this.isNot);\n } else {\n throw new Error(\n `toHaveModifier matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toExtendClass(received: LocatorData, className: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckExtendClass(received, className, this.isNot);\n } else {\n throw new Error(\n `toExtendClass matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toImplementInterface(received: LocatorData, interfaceName: string) {\n let result: RuleResult;\n if (received.type === 'ClassLocator') {\n result = classCheckImplementInterface(\n received,\n interfaceName,\n this.isNot,\n );\n } else {\n throw new Error(\n `toImplementInterface matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveExplicitReturnType(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveExplicitReturnType(received, this.isNot);\n } else {\n throw new Error(\n `toHaveExplicitReturnType matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeReadonly(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'PropertyLocator') {\n result = propertyCheckBeReadonly(received, this.isNot);\n } else {\n throw new Error(\n `toBeReadonly matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toDependOnFilesInFolder(received: LocatorData, folder: string) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = checkDependOnFilesInFolder(received, folder, this.isNot);\n } else {\n throw new Error(\n `toDependOnFilesInFolder matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toDependOnExternalModule(\n received: LocatorData,\n moduleName: string | RegExp,\n ) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = checkDependOnExternalModule(received, moduleName, this.isNot);\n } else {\n throw new Error(\n `toDependOnExternalModule matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toBeFreeOfCycles(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckBeFreeOfCycles(received, this.isNot);\n } else if (received.type === 'SliceLocator') {\n result = sliceCheckBeFreeOfCycles(received, this.isNot);\n } else {\n throw new Error(\n `toBeFreeOfCycles matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toMatchNamePattern(received: LocatorData, pattern: string | RegExp) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckMatchNamePattern(received, pattern, this.isNot);\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckMatchNamePattern(received, pattern, this.isNot);\n } else {\n throw new Error(\n `toMatchNamePattern matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxCyclomaticComplexity(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMaxCyclomaticComplexity(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxCyclomaticComplexity matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMinMaintainabilityIndex(received: LocatorData, min: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else if (received.type === 'FunctionLocator') {\n result = functionCheckHaveMinMaintainabilityIndex(\n received,\n min,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMinMaintainabilityIndex matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxDistanceFromMainSequence(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'SliceLocator') {\n result = sliceCheckHaveMaxDistanceFromMainSequence(\n received,\n max,\n this.isNot,\n );\n } else {\n throw new Error(\n `toHaveMaxDistanceFromMainSequence matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveNameMatchingFileName(received: LocatorData) {\n let result: RuleResult;\n if (received.type === 'FunctionLocator') {\n result = functionCheckHaveNameMatchingFileName(received, this.isNot);\n } else if (received.type === 'ClassLocator') {\n result = classCheckHaveNameMatchingFileName(received, this.isNot);\n } else {\n throw new Error(\n `toHaveNameMatchingFileName matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n\n toHaveMaxExportedFunctions(received: LocatorData, max: number) {\n let result: RuleResult;\n if (received.type === 'FileLocator') {\n result = fileCheckHaveMaxExportedFunctions(received, max, this.isNot);\n } else {\n throw new Error(\n `toHaveMaxExportedFunctions matcher does not support ${received.type}`,\n );\n }\n return {\n pass: this.isNot ? !result.pass : result.pass,\n message: result.message,\n };\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from './models';
|
|
2
|
+
/**
|
|
3
|
+
* Registers all Archest custom matchers (e.g., `toResideInFolder`, `toHaveModifier`)
|
|
4
|
+
* with the global Vitest `expect` instance.
|
|
5
|
+
*
|
|
6
|
+
* This function must be called exactly once before any architectural tests are run.
|
|
7
|
+
* The standard way to do this is to add it to a Vitest setup file.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // test/setup.ts
|
|
12
|
+
* import { setupMatchers } from '@archest/vitest';
|
|
13
|
+
* setupMatchers();
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function setupMatchers(): void;
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native Vitest Matchers provided by Archest for architectural testing.
|
|
3
|
+
*
|
|
4
|
+
* This interface extends Vitest's `Assertion` interface to provide fluent assertions
|
|
5
|
+
* on your codebase's architectural structure.
|
|
6
|
+
*/
|
|
7
|
+
export interface ArchestMatchers<_R = unknown> {
|
|
8
|
+
/**
|
|
9
|
+
* Asserts that the evaluated architectural rule passes.
|
|
10
|
+
* Primarily used for complex rules like LayeredArchitecture.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const architecture = project.layeredArchitecture()
|
|
15
|
+
* .layer('Domain', 'domain')
|
|
16
|
+
* .layer('Infrastructure', 'infrastructure');
|
|
17
|
+
*
|
|
18
|
+
* expect(architecture.whereLayer('Domain').shouldNotAccessAnyLayer().check()).toPass();
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
toPass(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Asserts that the located elements physically reside within the specified folder.
|
|
24
|
+
* Supports ClassLocators.
|
|
25
|
+
*
|
|
26
|
+
* @param folder - The folder name or path pattern the elements must reside in.
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const controllers = project.getClasses({ matchNamePattern: /Controller$/ });
|
|
30
|
+
* expect(controllers).toResideInFolder('controllers');
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
toResideInFolder(folder: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Asserts that the located elements have the specified TypeScript modifier.
|
|
36
|
+
* Supports ClassLocators and FunctionLocators.
|
|
37
|
+
*
|
|
38
|
+
* @param modifier - The AST modifier to enforce (e.g., 'export', 'abstract', 'async').
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const helpers = project.getFunctions({ inFolder: 'utils' });
|
|
42
|
+
* expect(helpers).toHaveModifier('export');
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
toHaveModifier(modifier: 'export' | 'default' | 'abstract' | 'async' | 'private' | 'public'): void;
|
|
46
|
+
/**
|
|
47
|
+
* Asserts that the located classes extend the specified base class.
|
|
48
|
+
* Supports ClassLocators.
|
|
49
|
+
*
|
|
50
|
+
* @param className - The name of the class that must be extended.
|
|
51
|
+
* @example
|
|
52
|
+
* ```typescript
|
|
53
|
+
* const repositories = project.getClasses({ matchNamePattern: /Repository$/ });
|
|
54
|
+
* expect(repositories).toExtendClass('BaseRepository');
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
toExtendClass(className: string): void;
|
|
58
|
+
/**
|
|
59
|
+
* Asserts that the located classes implement the specified interface.
|
|
60
|
+
* Supports ClassLocators.
|
|
61
|
+
*
|
|
62
|
+
* @param interfaceName - The name of the interface that must be implemented.
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const useCases = project.getClasses({ inFolder: 'use-cases' });
|
|
66
|
+
* expect(useCases).toImplementInterface('IUseCase');
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
toImplementInterface(interfaceName: string): void;
|
|
70
|
+
/**
|
|
71
|
+
* Asserts that the located functions have an explicit TypeScript return type.
|
|
72
|
+
* Supports FunctionLocators.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const domainFunctions = project.getFunctions({ inFolder: 'domain' });
|
|
77
|
+
* expect(domainFunctions).toHaveExplicitReturnType();
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
toHaveExplicitReturnType(): void;
|
|
81
|
+
/**
|
|
82
|
+
* Asserts that the located properties are marked as readonly.
|
|
83
|
+
* Supports PropertyLocators.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const dtoProps = project.getProperties({ classPattern: /Dto$/ });
|
|
88
|
+
* expect(dtoProps).toBeReadonly();
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
toBeReadonly(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Asserts that the located files import dependencies from the specified folder.
|
|
94
|
+
* Supports FileLocators.
|
|
95
|
+
*
|
|
96
|
+
* @param folder - The target folder that must be imported.
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const uiFiles = project.getFiles({ inFolder: 'ui' });
|
|
100
|
+
* expect(uiFiles).not.toDependOnFilesInFolder('database');
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
toDependOnFilesInFolder(folder: string): void;
|
|
104
|
+
/**
|
|
105
|
+
* Asserts that a file locator depends on a specific external module (e.g. from node_modules).
|
|
106
|
+
* Supports FileLocators.
|
|
107
|
+
*
|
|
108
|
+
* @param moduleName - The exact string name or RegExp of the external package (e.g. 'vue', 'lodash').
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* it('should only use gql-tada inside the graphql module', () => {
|
|
112
|
+
* expect(
|
|
113
|
+
* project.files().not.matching(/src\/graphql\//)
|
|
114
|
+
* ).not.toDependOnExternalModule('gql-tada');
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
toDependOnExternalModule(moduleName: string | RegExp): void;
|
|
119
|
+
/**
|
|
120
|
+
* Analyzes the AST dependency graph and asserts that the queried elements are entirely free of circular dependencies.
|
|
121
|
+
* Supports FileLocators and SliceLocators.
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const domainFiles = project.getFiles({ inFolder: 'domain' });
|
|
126
|
+
* expect(domainFiles).toBeFreeOfCycles();
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
toBeFreeOfCycles(): void;
|
|
130
|
+
/**
|
|
131
|
+
* Asserts that the name of the located element matches the provided string or RegExp pattern.
|
|
132
|
+
* Supports FileLocators, ClassLocators, and FunctionLocators.
|
|
133
|
+
*
|
|
134
|
+
* @param pattern - The string or RegExp pattern that must match the name.
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const controllers = project.getClasses({ withDecorator: 'Controller' });
|
|
138
|
+
* expect(controllers).toMatchNamePattern(/Controller$/);
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
toMatchNamePattern(pattern: string | RegExp): void;
|
|
142
|
+
/**
|
|
143
|
+
* Computes the cyclomatic complexity of the AST and asserts it is less than or equal to the maximum.
|
|
144
|
+
* Supports FileLocators, ClassLocators, and FunctionLocators.
|
|
145
|
+
*
|
|
146
|
+
* @param max - The maximum allowed cyclomatic complexity.
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* const coreFunctions = project.getFunctions({ inFolder: 'core' });
|
|
150
|
+
* expect(coreFunctions).toHaveMaxCyclomaticComplexity(10);
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
toHaveMaxCyclomaticComplexity(max: number): void;
|
|
154
|
+
/**
|
|
155
|
+
* Computes the maintainability index based on Halstead metrics and asserts it is greater than or equal to the minimum.
|
|
156
|
+
* Supports FileLocators and FunctionLocators.
|
|
157
|
+
*
|
|
158
|
+
* @param min - The minimum acceptable maintainability index (0-100).
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const coreFiles = project.getFiles({ inFolder: 'core' });
|
|
162
|
+
* expect(coreFiles).toHaveMinMaintainabilityIndex(65);
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
toHaveMinMaintainabilityIndex(min: number): void;
|
|
166
|
+
/**
|
|
167
|
+
* Computes the Robert C. Martin Distance from the Main Sequence for the slice and asserts it is less than or equal to the maximum.
|
|
168
|
+
* Supports SliceLocators.
|
|
169
|
+
*
|
|
170
|
+
* @param max - The maximum allowed distance from the main sequence (0 to 1).
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const slices = project.getSlices('modules/(*)/');
|
|
174
|
+
* expect(slices).toHaveMaxDistanceFromMainSequence(0.3);
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
toHaveMaxDistanceFromMainSequence(max: number): void;
|
|
178
|
+
/**
|
|
179
|
+
* Asserts that the exported class or function name exactly matches the name of its parent file.
|
|
180
|
+
* Supports ClassLocators and FunctionLocators.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const allFunctions = project.getFunctions();
|
|
185
|
+
* expect(allFunctions).toHaveNameMatchingFileName();
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
toHaveNameMatchingFileName(): void;
|
|
189
|
+
/**
|
|
190
|
+
* Asserts that the located file does not export more than the specified maximum number of functions.
|
|
191
|
+
* Supports FileLocators.
|
|
192
|
+
*
|
|
193
|
+
* @param max - The maximum number of allowed exported functions per file.
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* const utils = project.getFiles({ inFolder: 'utils' });
|
|
197
|
+
* expect(utils).toHaveMaxExportedFunctions(5);
|
|
198
|
+
* ```
|
|
199
|
+
*/
|
|
200
|
+
toHaveMaxExportedFunctions(max: number): void;
|
|
201
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ClassData, ProjectData } from '../dto';
|
|
2
|
+
import { ClassLocatorData, ClassQueryOptions } from './types';
|
|
3
|
+
export declare function locateClasses(classes: (ClassData & {
|
|
4
|
+
_filePath: string;
|
|
5
|
+
})[], projectData: ProjectData, options?: ClassQueryOptions): ClassLocatorData;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ClassData, ProjectData } from '../dto';
|
|
2
|
+
export interface ClassLocatorData {
|
|
3
|
+
type: 'ClassLocator';
|
|
4
|
+
classes: (ClassData & {
|
|
5
|
+
_filePath: string;
|
|
6
|
+
})[];
|
|
7
|
+
projectData: ProjectData;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Options to filter classes when querying the AST via `getClasses()`.
|
|
11
|
+
*/
|
|
12
|
+
export interface ClassQueryOptions {
|
|
13
|
+
/** Filters classes to only include those residing in a specific folder path. */
|
|
14
|
+
inFolder?: string;
|
|
15
|
+
/** Filters classes by a string or RegExp matching their name. */
|
|
16
|
+
matchNamePattern?: string | RegExp;
|
|
17
|
+
/** Filters classes to only include those that have the specified decorator applied. */
|
|
18
|
+
withDecorator?: string;
|
|
19
|
+
/** Filters classes to only include those extending the specified base class. */
|
|
20
|
+
extending?: string;
|
|
21
|
+
/** Filters classes to only include those implementing the specified interface. */
|
|
22
|
+
implementing?: string;
|
|
23
|
+
/** Filters classes to only include those with the specified AST modifier (e.g., 'export', 'abstract'). */
|
|
24
|
+
havingModifier?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents the entire parsed project structure containing all analyzed files.
|
|
3
|
+
* This is the root node returned by the native Rust parser.
|
|
4
|
+
*/
|
|
5
|
+
export interface ProjectData {
|
|
6
|
+
/** A list of all files that were successfully parsed in the project workspace. */
|
|
7
|
+
files: FileData[];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Represents a single source file in the project.
|
|
11
|
+
* Contains information about its path, dependencies, and all nested code blocks.
|
|
12
|
+
*/
|
|
13
|
+
export interface FileData {
|
|
14
|
+
/** The absolute path to the file. */
|
|
15
|
+
path: string;
|
|
16
|
+
/** An array of all classes defined within this file. */
|
|
17
|
+
classes: ClassData[];
|
|
18
|
+
/** An array of all top-level or exported functions defined within this file. */
|
|
19
|
+
functions: FunctionData[];
|
|
20
|
+
/** An array of properties extracted from classes or objects in the file. */
|
|
21
|
+
properties: PropertyData[];
|
|
22
|
+
/** An array of raw module paths this file imports (e.g., './utils', 'react'). */
|
|
23
|
+
dependencies?: string[];
|
|
24
|
+
/** An array of external module imports (e.g., 'react', 'lodash'). */
|
|
25
|
+
external_dependencies?: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Represents a class declaration extracted from a TypeScript or JavaScript file.
|
|
29
|
+
* Includes architectural metadata such as its hierarchy and complexity.
|
|
30
|
+
*/
|
|
31
|
+
export interface ClassData {
|
|
32
|
+
/** The name of the class, or null if it is an anonymous class. */
|
|
33
|
+
name: string | null;
|
|
34
|
+
/** True if the class has an 'export' modifier. */
|
|
35
|
+
is_exported: boolean;
|
|
36
|
+
/** True if the class has an 'export default' modifier. */
|
|
37
|
+
is_default: boolean;
|
|
38
|
+
/** True if the class is marked as abstract. */
|
|
39
|
+
is_abstract: boolean;
|
|
40
|
+
/** The name of the parent class it extends, if any. */
|
|
41
|
+
extends: string | null;
|
|
42
|
+
/** An array of interface names this class implements. */
|
|
43
|
+
implements: string[];
|
|
44
|
+
/** An array of decorator names applied to the class. */
|
|
45
|
+
decorators: string[];
|
|
46
|
+
/** The computed McCabe cyclomatic complexity of the class methods. */
|
|
47
|
+
cyclomatic_complexity?: number;
|
|
48
|
+
/** The computed Halstead maintainability index (0-100). */
|
|
49
|
+
maintainability_index?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Represents a function declaration or arrow function extracted from a file.
|
|
53
|
+
*/
|
|
54
|
+
export interface FunctionData {
|
|
55
|
+
/** The name of the function, or null if anonymous. */
|
|
56
|
+
name: string | null;
|
|
57
|
+
/** True if the function is exported from the file. */
|
|
58
|
+
is_exported: boolean;
|
|
59
|
+
/** True if the function is marked as async. */
|
|
60
|
+
is_async: boolean;
|
|
61
|
+
/** True if the function is defined at the root level of the file context. */
|
|
62
|
+
is_top_level: boolean;
|
|
63
|
+
/** True if the function explicitly declares a return type. */
|
|
64
|
+
has_explicit_return_type: boolean;
|
|
65
|
+
/** The computed McCabe cyclomatic complexity of the function body. */
|
|
66
|
+
cyclomatic_complexity?: number;
|
|
67
|
+
/** The computed Halstead maintainability index (0-100). */
|
|
68
|
+
maintainability_index?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Represents a class property or interface member extracted from the AST.
|
|
72
|
+
*/
|
|
73
|
+
export interface PropertyData {
|
|
74
|
+
/** The name of the property. */
|
|
75
|
+
name: string;
|
|
76
|
+
/** True if the property is marked with the 'readonly' modifier. */
|
|
77
|
+
is_readonly: boolean;
|
|
78
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ArchestProject } from '@archest/core-rust';
|
|
2
|
+
import { FileData, ProjectData } from '../dto';
|
|
3
|
+
import { FileLocatorData, FileQueryOptions } from './types';
|
|
4
|
+
export declare function locateFiles(sourceFiles: FileData[], projectData: ProjectData, archestProject?: ArchestProject, options?: FileQueryOptions): FileLocatorData;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ArchestProject } from '@archest/core-rust';
|
|
2
|
+
import { FileData, ProjectData } from '../dto';
|
|
3
|
+
export interface FileLocatorData {
|
|
4
|
+
type: 'FileLocator';
|
|
5
|
+
files: FileData[];
|
|
6
|
+
projectData: ProjectData;
|
|
7
|
+
archestProject?: ArchestProject;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Options to filter files when querying the AST via `getFiles()`.
|
|
11
|
+
*/
|
|
12
|
+
export interface FileQueryOptions {
|
|
13
|
+
/** Filters files to only include those residing in a specific folder path. */
|
|
14
|
+
inFolder?: string;
|
|
15
|
+
/** Filters files by a string or RegExp matching their file name (excluding extension). */
|
|
16
|
+
matchNamePattern?: string | RegExp;
|
|
17
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { FunctionData, ProjectData } from '../dto';
|
|
2
|
+
import { FunctionLocatorData, FunctionQueryOptions } from './types';
|
|
3
|
+
export declare function locateFunctions(functions: (FunctionData & {
|
|
4
|
+
_filePath: string;
|
|
5
|
+
})[], projectData: ProjectData, options?: FunctionQueryOptions): FunctionLocatorData;
|