@archest/vitest 1.0.2 → 1.0.4

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 CHANGED
@@ -1,3 +1,16 @@
1
+ import { ArchestMatchers } from './matchers';
1
2
  export type { ClassData, ClassQueryOptions, FileData, FileQueryOptions, FunctionData, FunctionQueryOptions, ProjectData, PropertyData, PropertyQueryOptions, } from '@archest/core';
2
3
  export { type ParseProjectOptions, parseProject, } from '@archest/core';
3
4
  export { type ArchestMatchers, setupMatchers } from './matchers';
5
+ declare module 'vitest' {
6
+ interface Assertion<T = any> extends ArchestMatchers<T> {
7
+ }
8
+ interface AsymmetricMatchersContaining extends ArchestMatchers<any> {
9
+ }
10
+ }
11
+ declare module '@vitest/expect' {
12
+ interface Assertion<T = any> extends ArchestMatchers<T> {
13
+ }
14
+ interface AsymmetricMatchersContaining extends ArchestMatchers<any> {
15
+ }
16
+ }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","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';\nimport type { ArchestMatchers } from './models';\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\ndeclare module 'vitest' {\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n interface Assertion<T = any> extends ArchestMatchers<T> {}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","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":"mXA8CA,SAAgB,GAAgB,CAC9B,EAAA,OAAO,OAAO,CAEZ,OAAO,EAAe,CACpB,IAAI,EAEJ,AAGE,EAHE,GAAU,MAAQ,EAAS,KAAK,OAAS,uBAC3C,EAAA,EAAA,0BAAkC,EAAS,IAAI,EAEtC,EAGX,GAAM,CAAE,OAAM,WAAY,EAC1B,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,EAC3B,QAAS,MAAa,gCAAoC,EAAQ,CACpE,CACF,EAEA,iBAAiB,EAAuB,EAAgB,CACtD,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,GAAA,EAAA,EAAA,0BAAkC,EAAU,EAAQ,KAAK,KAAK,OAE9D,MAAU,MACR,6CAA6C,EAAS,MACxD,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,eAAe,EAAuB,EAAkB,CACtD,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,GAAA,EAAA,EAAA,wBAAgC,EAAU,EAAU,KAAK,KAAK,OACzD,GAAI,EAAS,OAAS,kBAC3B,GAAA,EAAA,EAAA,2BAAmC,EAAU,EAAU,KAAK,KAAK,OAEjE,MAAU,MACR,2CAA2C,EAAS,MACtD,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,cAAc,EAAuB,EAAmB,CACtD,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,GAAA,EAAA,EAAA,uBAA+B,EAAU,EAAW,KAAK,KAAK,OAE9D,MAAU,MACR,0CAA0C,EAAS,MACrD,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,qBAAqB,EAAuB,EAAuB,CACjE,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,GAAA,EAAA,EAAA,8BACE,EACA,EACA,KAAK,KACP,OAEA,MAAU,MACR,iDAAiD,EAAS,MAC5D,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,yBAAyB,EAAuB,CAC9C,IAAI,EACJ,GAAI,EAAS,OAAS,kBACpB,GAAA,EAAA,EAAA,qCAA6C,EAAU,KAAK,KAAK,OAEjE,MAAU,MACR,qDAAqD,EAAS,MAChE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,aAAa,EAAuB,CAClC,IAAI,EACJ,GAAI,EAAS,OAAS,kBACpB,GAAA,EAAA,EAAA,yBAAiC,EAAU,KAAK,KAAK,OAErD,MAAU,MACR,yCAAyC,EAAS,MACpD,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,wBAAwB,EAAuB,EAAgB,CAC7D,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,4BAAoC,EAAU,EAAQ,KAAK,KAAK,OAEhE,MAAU,MACR,oDAAoD,EAAS,MAC/D,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,yBACE,EACA,EACA,CACA,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,6BAAqC,EAAU,EAAY,KAAK,KAAK,OAErE,MAAU,MACR,qDAAqD,EAAS,MAChE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,iBAAiB,EAAuB,CACtC,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,yBAAiC,EAAU,KAAK,KAAK,OAChD,GAAI,EAAS,OAAS,eAC3B,GAAA,EAAA,EAAA,0BAAkC,EAAU,KAAK,KAAK,OAEtD,MAAU,MACR,6CAA6C,EAAS,MACxD,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,mBAAmB,EAAuB,EAA0B,CAClE,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,2BAAmC,EAAU,EAAS,KAAK,KAAK,OAC3D,GAAI,EAAS,OAAS,eAC3B,GAAA,EAAA,EAAA,4BAAoC,EAAU,EAAS,KAAK,KAAK,OAC5D,GAAI,EAAS,OAAS,kBAC3B,GAAA,EAAA,EAAA,+BAAuC,EAAU,EAAS,KAAK,KAAK,OAEpE,MAAU,MACR,+CAA+C,EAAS,MAC1D,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,8BAA8B,EAAuB,EAAa,CAChE,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,sCACE,EACA,EACA,KAAK,KACP,OACK,GAAI,EAAS,OAAS,eAC3B,GAAA,EAAA,EAAA,uCACE,EACA,EACA,KAAK,KACP,OACK,GAAI,EAAS,OAAS,kBAC3B,GAAA,EAAA,EAAA,0CACE,EACA,EACA,KAAK,KACP,OAEA,MAAU,MACR,0DAA0D,EAAS,MACrE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,8BAA8B,EAAuB,EAAa,CAChE,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,sCACE,EACA,EACA,KAAK,KACP,OACK,GAAI,EAAS,OAAS,kBAC3B,GAAA,EAAA,EAAA,0CACE,EACA,EACA,KAAK,KACP,OAEA,MAAU,MACR,0DAA0D,EAAS,MACrE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,kCAAkC,EAAuB,EAAa,CACpE,IAAI,EACJ,GAAI,EAAS,OAAS,eACpB,GAAA,EAAA,EAAA,2CACE,EACA,EACA,KAAK,KACP,OAEA,MAAU,MACR,8DAA8D,EAAS,MACzE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,2BAA2B,EAAuB,CAChD,IAAI,EACJ,GAAI,EAAS,OAAS,kBACpB,GAAA,EAAA,EAAA,uCAA+C,EAAU,KAAK,KAAK,OAC9D,GAAI,EAAS,OAAS,eAC3B,GAAA,EAAA,EAAA,oCAA4C,EAAU,KAAK,KAAK,OAEhE,MAAU,MACR,uDAAuD,EAAS,MAClE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,EAEA,2BAA2B,EAAuB,EAAa,CAC7D,IAAI,EACJ,GAAI,EAAS,OAAS,cACpB,GAAA,EAAA,EAAA,mCAA2C,EAAU,EAAK,KAAK,KAAK,OAEpE,MAAU,MACR,uDAAuD,EAAS,MAClE,EAEF,MAAO,CACL,KAAM,KAAK,MAAQ,CAAC,EAAO,KAAO,EAAO,KACzC,QAAS,EAAO,OAClB,CACF,CACF,CAAC,CACH"}
@@ -1 +1 @@
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';\nimport type { ArchestMatchers } from './models';\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\ndeclare module 'vitest' {\n // biome-ignore lint/suspicious/noExplicitAny: Matcher signature\n interface Assertion<T = any> extends ArchestMatchers<T> {}\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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"}
@@ -1,4 +1,3 @@
1
- import { ArchestMatchers } from './models';
2
1
  export * from './models';
3
2
  /**
4
3
  * Registers all Archest custom matchers (e.g., `toResideInFolder`, `toHaveModifier`)
@@ -15,7 +14,3 @@ export * from './models';
15
14
  * ```
16
15
  */
17
16
  export declare function setupMatchers(): void;
18
- declare module 'vitest' {
19
- interface Assertion<T = any> extends ArchestMatchers<T> {
20
- }
21
- }
@@ -5,6 +5,8 @@
5
5
  export interface ProjectData {
6
6
  /** A list of all files that were successfully parsed in the project workspace. */
7
7
  files: FileData[];
8
+ /** The root directory of the parsed project. */
9
+ projectRoot?: string;
8
10
  }
9
11
  /**
10
12
  * Represents a single source file in the project.
@@ -23,6 +25,10 @@ export interface FileData {
23
25
  dependencies?: string[];
24
26
  /** An array of external module imports (e.g., 'react', 'lodash'). */
25
27
  external_dependencies?: string[];
28
+ /** An array of type-only module paths this file imports. */
29
+ type_dependencies?: string[];
30
+ /** An array of external type-only module imports. */
31
+ external_type_dependencies?: string[];
26
32
  }
27
33
  /**
28
34
  * Represents a class declaration extracted from a TypeScript or JavaScript file.
@@ -1,5 +1,7 @@
1
1
  import { ArchestProject } from '@archest/core-rust';
2
+ import { ClassQueryOptions } from '../classes/types';
2
3
  import { FileData, ProjectData } from '../dto';
4
+ import { FunctionQueryOptions } from '../functions/types';
3
5
  export interface FileLocatorData {
4
6
  type: 'FileLocator';
5
7
  files: FileData[];
@@ -14,4 +16,8 @@ export interface FileQueryOptions {
14
16
  inFolder?: string;
15
17
  /** Filters files by a string or RegExp matching their file name (excluding extension). */
16
18
  matchNamePattern?: string | RegExp;
19
+ /** Filters files to only include those containing a function matching the criteria. */
20
+ hasFunction?: FunctionQueryOptions;
21
+ /** Filters files to only include those containing a class matching the criteria. */
22
+ hasClass?: ClassQueryOptions;
17
23
  }
@@ -1,14 +1,14 @@
1
1
  (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("node:path"),require("@archest/core-rust"),require("typescript")):typeof define==`function`&&define.amd?define([`exports`,`node:path`,`@archest/core-rust`,`typescript`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.VitestArch={},e.node_path,e._archest_core_rust,e.typescript))})(this,function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=Object.create,a=Object.defineProperty,o=Object.getOwnPropertyDescriptor,s=Object.getOwnPropertyNames,c=Object.getPrototypeOf,l=Object.prototype.hasOwnProperty,u=(e,t,n,r)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var i=s(t),c=0,u=i.length,d;c<u;c++)d=i[c],!l.call(e,d)&&d!==n&&a(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(r=o(t,d))||r.enumerable});return e},d=(e,t,n)=>(n=e==null?{}:i(c(e)),u(t||!e||!e.__esModule?a(n,`default`,{value:e,enumerable:!0}):n,e));t=d(t),r=d(r);function f(e,t,n){let r=[];for(let i of e.classes){let e=i.name||`Anonymous`,a=!1;i.extends===t&&(a=!0),n&&a?r.push(`Class ${e} extends ${t}, but it shouldn't.`):!n&&!a&&r.push(`Class ${e} does not extend ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
2
- `)}}function p(e,t,n){let r=[];for(let i of e){let{passes:e,failMessage:a,failNotMessage:o}=n(i);t&&e?o&&r.push(o):!t&&!e&&a&&r.push(a)}return{pass:r.length===0,message:()=>r.join(`
3
- `)}}function m(e,t,n,r,i,a){return p(e,a,e=>{let a=t(e),o=n(e),s=o>i,c=`${r} ${a||`Anonymous`}`;return{passes:!s,failMessage:`${c} has a total cyclomatic complexity of ${o}, which exceeds the maximum of ${i}.`,failNotMessage:`${c} has a total cyclomatic complexity of ${o}, which exceeds the maximum of ${i}, but it shouldn't.`}})}function h(e,t,n){return m(e.classes,e=>e.name,e=>e.cyclomatic_complexity||0,`Class`,t,n)}function g(e,t,n,r,i){return p(e,i,e=>{let i=t(e),a=!1;switch(r){case`export`:a=!!e.is_exported;break;case`default`:a=!!e.is_default;break;case`abstract`:a=!!e.is_abstract;break;case`async`:a=!!e.is_async;break;case`readonly`:a=!!e.is_readonly;break;default:throw Error(`Modifier ${r} is not fully supported.`)}let o=`${n} ${i||`Anonymous`}`;return{passes:a,failMessage:`${o} does not have modifier ${r}, but it should.`,failNotMessage:`${o} has modifier ${r}, but it shouldn't.`}})}function _(e,t,n){return g(e.classes,e=>e.name,`Class`,t,n)}function v(e,n,r,i){return p(e,i,e=>{let i=n(e);if(!e._filePath)return{passes:!0,failMessage:``,failNotMessage:``};let a=t.basename(e._filePath,t.extname(e._filePath)),o=i===a,s=`${r} ${i||`Anonymous`}`;return{passes:o,failMessage:`${s} does not have a name matching its filename ${a}, but it should.`,failNotMessage:`${s} has a name matching its filename ${a}, but it shouldn't.`}})}function y(e,t){return v(e.classes,e=>e.name,`Class`,t)}function b(e,t,n){let r=[];for(let i of e.classes){let e=i.name||`Anonymous`,a=!1;i.implements.includes(t)&&(a=!0),n&&a?r.push(`Class ${e} implements ${t}, but it shouldn't.`):!n&&!a&&r.push(`Class ${e} does not implement ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
4
- `)}}function x(e,t,n,r,i){let a=typeof r==`string`?new RegExp(r):r;return p(e,i,e=>{let i=t(e),o=i?a.test(i):!1,s=`${n} ${i||`Anonymous`}`;return{passes:o,failMessage:`${s} does not match pattern ${r}, but it should.`,failNotMessage:`${s} matches pattern ${r}, but it shouldn't.`}})}function ee(e,t,n){return x(e.classes,e=>e.name,`Class`,t,n)}function S(e,t,n){let r=[];for(let i of e.classes){let e=i.name||`Anonymous Class`,a=i._filePath,o=a.includes(`/${t}/`)||a.includes(`\\${t}\\`);n&&o?r.push(`Class ${e} resides in ${t}, but it shouldn't.`):!n&&!o&&r.push(`Class ${e} does not reside in ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
5
- `)}}function C(e,t,n){let r=e;if(n?.inFolder&&(r=r.filter(e=>e._filePath.includes(`/${n.inFolder}/`)||e._filePath.includes(`\\${n.inFolder}\\`))),n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>t.name&&e.test(t.name))}if(n?.withDecorator){let e=n.withDecorator;r=r.filter(t=>t.decorators.includes(e))}if(n?.extending&&(r=r.filter(e=>e.extends===n.extending)),n?.implementing){let e=n.implementing;r=r.filter(t=>t.implements.includes(e))}return n?.havingModifier&&(r=r.filter(e=>{switch(n.havingModifier){case`export`:return e.is_exported;case`default`:return e.is_default;case`abstract`:return e.is_abstract;default:throw Error(`Modifier ${n.havingModifier} is not fully supported.`)}})),{type:`ClassLocator`,classes:r,projectData:t}}function w(e,t,n){let r=[],i=typeof t==`string`?new RegExp(t):t;for(let a of e.files){let e=(a.external_dependencies||[]).some(e=>i.test(e));n&&e?r.push(`${a.path} incorrectly depends on external module '${t}'`):!n&&!e&&r.push(`${a.path} does not depend on external module '${t}'`)}return{pass:r.length===0,message:()=>r.join(`
6
- `)}}function T(e,t){return e.dependencies||[]}function E(e,t,n){let r=[];for(let i of e.files){let a=T(i,e.projectData).some(e=>e.includes(`/${t}/`)||e.includes(`\\${t}\\`));n&&a?r.push(`File ${i.path} depends on files in ${t}, but it shouldn't.`):!n&&!a&&r.push(`File ${i.path} does not depend on files in ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
7
- `)}}function D(e,t){let n=e.files.map(e=>e.path),r=e.archestProject;if(!r)return{pass:!0,message:()=>`Mock pass: archestProject not in registry`};let i=r.checkFileCycles(n,!!t);return{pass:i.pass,message:()=>i.message}}function O(e,t,n){return m(e.files,e=>e.path,e=>{let t=0;for(let n of e.functions)t+=n.cyclomatic_complexity||0;for(let n of e.classes)t+=n.cyclomatic_complexity||0;return t},`File`,t,n)}function k(e,t,n){let r=[];for(let i of e.files){let e=i.functions.filter(e=>e.is_exported).length,a=e>t;n&&a?r.push(`File ${i.path} has ${e} exported functions, which exceeds the maximum of ${t}, but it shouldn't.`):!n&&a&&r.push(`File ${i.path} has ${e} exported functions, which exceeds the maximum of ${t}.`)}return{pass:n?r.length>0:r.length===0,message:()=>r.join(`
8
- `)||(n?`Expected some files to exceed maximum exported functions, but none did.`:``)}}function A(e,t,n,r,i,a){return p(e,a,e=>{let a=t(e),o=n(e),s=o<i,c=`${r} ${a||`Anonymous`}`;return{passes:!s,failMessage:`${c} has a maintainability index of ${o.toFixed(2)}, which falls below the minimum of ${i}.`,failNotMessage:`${c} has a maintainability index of ${o.toFixed(2)}, which falls below the minimum of ${i}, but it shouldn't.`}})}function te(e,t,n){return A(e.files,e=>e.path,e=>e.functions.length>0&&e.functions[0].maintainability_index||100,`File`,t,n)}function ne(e,t,n){return x(e.files,e=>e.path,`File`,t,n)}function j(e,t,n,r){let i=e;if(r?.inFolder&&(i=i.filter(e=>e.path.includes(`/${r.inFolder}/`)||e.path.includes(`\\${r.inFolder}\\`))),r?.matchNamePattern){let e=typeof r.matchNamePattern==`string`?new RegExp(r.matchNamePattern):r.matchNamePattern;i=i.filter(t=>e.test(t.path))}let a={type:`FileLocator`,files:i,projectData:t};return n&&Object.defineProperty(a,"archestProject",{value:n,enumerable:!1}),a}function M(e,t){let n=[];for(let r of e.functions){let e=r.name||`Anonymous Function`,i=r.has_explicit_return_type;t&&i?n.push(`Function ${e} has an explicit return type, but it shouldn't.`):!t&&!i&&n.push(`Function ${e} does not have an explicit return type, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
9
- `)}}function N(e,t,n){return m(e.functions,e=>e.name,e=>e.cyclomatic_complexity||0,`Function`,t,n)}function P(e,t,n){return A(e.functions,e=>e.name,e=>e.maintainability_index||100,`Function`,t,n)}function F(e,t,n){return g(e.functions,e=>e.name,`Function`,t,n)}function I(e,t){return v(e.functions,e=>e.name,`Function`,t)}function L(e,t,n){return x(e.functions,e=>e.name,`Function`,t,n)}function R(e,t,n){let r=e;if(n?.inFolder&&(r=r.filter(e=>e._filePath.includes(`/${n.inFolder}/`)||e._filePath.includes(`\\${n.inFolder}\\`))),n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>t.name&&e.test(t.name))}return n?.isTopLevel&&(r=r.filter(e=>e.is_top_level)),{type:`FunctionLocator`,functions:r,projectData:t}}function z(e){let t=[];for(let n of e.assertions)t.push(...n(e.files));return{pass:t.length===0,message:()=>t.join(`
10
- `)}}function B(e,t){return{type:`LayeredArchitecture`,files:e,layers:new Map,assertions:[],projectData:t}}function V(e,t,n){return e.layers.set(t,n),e}function H(e,t){return e.dependencies||[]}function U(e,t){if(!e.layers.has(t))throw Error(`Layer ${t} is not defined`);return e.assertions.push(n=>{let r=[],i=e.layers.get(t);for(let a of n){let n=a.path;!n.includes(`/${i}/`)&&!n.includes(`\\${i}\\`)&&H(a,e.projectData).some(e=>e.includes(`/${i}/`)||e.includes(`\\${i}\\`))&&r.push(`File ${n} accesses layer ${t} but it shouldn't.`)}return r}),e}function W(e,t,n){if(!e.layers.has(t))throw Error(`Layer ${t} is not defined`);return e.assertions.push(r=>{let i=[],a=e.layers.get(t),o=n.map(t=>e.layers.get(t));for(let s of r){let r=s.path,c=o.some(e=>r.includes(`/${e}/`)||r.includes(`\\${e}\\`));!r.includes(`/${a}/`)&&!r.includes(`\\${a}\\`)&&!c&&H(s,e.projectData).some(e=>e.includes(`/${a}/`)||e.includes(`\\${a}\\`))&&i.push(`File ${r} accesses layer ${t} but only ${n.join(`, `)} are allowed.`)}return i}),e}function G(e,t,n){let r=e;if(n?.inFolder&&(r=r.filter(e=>e._filePath.includes(`/${n.inFolder}/`)||e._filePath.includes(`\\${n.inFolder}\\`))),n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>e.test(t.name))}return{type:`PropertyLocator`,properties:r,projectData:t}}function K(e,t,n){let r=n.replace(/[.+?^${}()|[\]\\]/g,`\\$&`).replace(/\*/g,`([^/\\\\]+)`),i=new RegExp(r),a=new Set,o=new Map;for(let t of e){let e=t.path.match(i);if(e?.[1]){let n=e[1];a.add(n),o.has(n)||o.set(n,[]),o.get(n)?.push(t)}}return{type:`SliceLocator`,slicePattern:i,sliceIds:a,sliceFiles:o,projectData:t}}function q(e={}){let i=e.tsConfigFilePath||r.findConfigFile(process.cwd(),r.sys.fileExists,`tsconfig.json`);if(!i)throw Error(`Could not find tsconfig.json`);let a=(0,t.dirname)(i),o=r.readConfigFile(i,r.sys.readFile);e.include&&(o.config.include=e.include),e.exclude&&(o.config.exclude=e.exclude);let s=r.parseJsonConfigFileContent(o.config,r.sys,a,void 0,i,void 0,[{extension:`.vue`,isMixedContent:!0,scriptKind:r.ScriptKind.TS},{extension:`.svelte`,isMixedContent:!0,scriptKind:r.ScriptKind.TS}]),c=n.ArchestProject.parse(s.fileNames),l=JSON.parse(c.getProjectData());return{projectData:l,getFiles:e=>j(l.files,l,c,e),getClasses:e=>C(l.files.flatMap(e=>e.classes.map(t=>({...t,_filePath:e.path}))),l,e),layeredArchitecture:()=>{let e=B(l.files,l),t={layer:(n,r)=>(e=V(e,n,r),t),whereLayer:n=>({shouldNotBeAccessedByAnyLayer:()=>(e=U(e,n),t),shouldOnlyBeAccessedBy:(...r)=>(e=W(e,n,r),t)}),check:()=>z(e),get data(){return e}};return t},getFunctions:e=>R(l.files.flatMap(e=>e.functions.map(t=>({...t,_filePath:e.path}))),l,e),getProperties:e=>G(l.files.flatMap(e=>e.properties.map(t=>({...t,_filePath:e.path}))),l,e),getSlices:e=>K(l.files,l,e)}}function J(e,t){let n=[];for(let r of e.properties){let e=r.name||`Anonymous Property`,i=r.is_readonly;t&&i?n.push(`Property ${e} is readonly, but it shouldn't be.`):!t&&!i&&n.push(`Property ${e} is not readonly, but it should be.`)}return{pass:n.length===0,message:()=>n.join(`
11
- `)}}function Y(e,t){let n=new Map;for(let t of e.sliceIds)n.set(t,new Set);for(let[t,r]of e.sliceFiles.entries())for(let i of r)if(i.dependencies)for(let r of i.dependencies){let i=r.match(e.slicePattern);if(i?.[1]){let r=i[1];r!==t&&e.sliceIds.has(r)&&n.get(t)?.add(r)}}let r=new Set,i=new Set,a=[],o=(e,t)=>{r.add(e),i.add(e);for(let s of n.get(e)||[])if(!r.has(s)){if(o(s,[...t,s]))return!0}else if(i.has(s))return a.push(`Cycle detected between slices: ${t.join(` -> `)} -> ${s}`),!0;return i.delete(e),!1};for(let t of e.sliceIds)r.has(t)||o(t,[t]);return t?{pass:a.length>0,message:()=>a.length>0?``:`Expected cycles between slices but found none.`}:{pass:a.length===0,message:()=>a.join(`
12
- `)}}function X(e,t,n){let r=[],i=new Map,a=new Map;for(let t of e.sliceIds)i.set(t,new Set),a.set(t,new Set);for(let[t,n]of e.sliceFiles.entries())for(let r of n)if(r.dependencies)for(let n of r.dependencies){let r=n.match(e.slicePattern);if(r?.[1]){let n=r[1];n!==t&&e.sliceIds.has(n)&&(i.get(t)?.add(n),a.get(n)?.add(t))}}for(let o of e.sliceIds){let s=i.get(o)?.size||0,c=a.get(o)?.size||0,l=e.sliceFiles.get(o),u=0,d=0;for(let e of l)for(let t of e.classes)d++,t.is_abstract&&u++;let f=s+c===0?0:s/(c+s),p=d===0?0:u/d,m=Math.abs(p+f-1),h=m>t;n&&h?r.push(`Slice ${o} has a Distance from the Main Sequence of ${m.toFixed(2)}, which exceeds the maximum of ${t}, but it shouldn't.`):!n&&h&&r.push(`Slice ${o} has a Distance from the Main Sequence of ${m.toFixed(2)}, which exceeds the maximum of ${t}.`)}return{pass:n?r.length>0:r.length===0,message:()=>r.join(`
13
- `)||(n?`Expected some slices to exceed maximum distance from main sequence, but none did.`:``)}}function re(e,t=`test.ts`){return r.createSourceFile(t,e,r.ScriptTarget.Latest,!0)}function ie(e){return{files:e.map(e=>({path:e.fileName,classes:Z(e),functions:Q(e),properties:$(e)}))}}function ae(e){return n.ArchestProject.parseMock(JSON.stringify(e))}function Z(e){let t=[];return r.forEachChild(e,n=>{if(r.isClassDeclaration(n)){let i=null,a=[];if(n.heritageClauses)for(let e of n.heritageClauses){if(e.token===r.SyntaxKind.ExtendsKeyword)for(let t of e.types)r.isIdentifier(t.expression)&&(i=t.expression.text);if(e.token===r.SyntaxKind.ImplementsKeyword)for(let t of e.types)r.isIdentifier(t.expression)&&a.push(t.expression.text)}let o=[];if(r.canHaveDecorators(n)){let e=r.getDecorators(n);if(e)for(let t of e)r.isIdentifier(t.expression)?o.push(t.expression.text):r.isCallExpression(t.expression)&&r.isIdentifier(t.expression.expression)&&o.push(t.expression.expression.text)}t.push({name:n.name?.text||null,is_exported:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.ExportKeyword)||!1,is_default:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.DefaultKeyword)||!1,is_abstract:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.AbstractKeyword)||!1,extends:i,implements:a,decorators:o,_filePath:e.fileName})}}),t}function Q(e){let t=[];return r.forEachChild(e,n=>{if(r.isFunctionDeclaration(n)||r.isMethodDeclaration(n)||r.isArrowFunction(n)){let i=null;(r.isFunctionDeclaration(n)||r.isMethodDeclaration(n))&&(i=n.name?.getText()||null),t.push({name:i,is_exported:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.ExportKeyword)||!1,is_async:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.AsyncKeyword)||!1,is_top_level:!0,has_explicit_return_type:!!n.type,_filePath:e.fileName})}}),t}function $(e){let t=[];return r.forEachChild(e,n=>{r.isClassDeclaration(n)&&n.members.forEach(n=>{r.isPropertyDeclaration(n)&&t.push({name:n.name.getText(),is_readonly:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.ReadonlyKeyword)||!1,_filePath:e.fileName})})}),t}e.checkDependOnExternalModule=w,e.checkDependOnFilesInFolder=E,e.checkLayeredArchitecture=z,e.classCheckExtendClass=f,e.classCheckHaveMaxCyclomaticComplexity=h,e.classCheckHaveModifier=_,e.classCheckHaveNameMatchingFileName=y,e.classCheckImplementInterface=b,e.classCheckMatchNamePattern=ee,e.classCheckResideInFolder=S,e.createLayeredArchitecture=B,e.createMockArchestProject=ae,e.createMockProgram=ie,e.createSourceFile=re,e.fileCheckBeFreeOfCycles=D,e.fileCheckHaveMaxCyclomaticComplexity=O,e.fileCheckHaveMaxExportedFunctions=k,e.fileCheckHaveMinMaintainabilityIndex=te,e.fileCheckMatchNamePattern=ne,e.functionCheckHaveExplicitReturnType=M,e.functionCheckHaveMaxCyclomaticComplexity=N,e.functionCheckHaveMinMaintainabilityIndex=P,e.functionCheckHaveModifier=F,e.functionCheckHaveNameMatchingFileName=I,e.functionCheckMatchNamePattern=L,e.getClasses=Z,e.getFunctions=Q,e.getProperties=$,e.layer=V,e.layerShouldNotBeAccessedByAnyLayer=U,e.layerShouldOnlyBeAccessedBy=W,e.locateClasses=C,e.locateFiles=j,e.locateFunctions=R,e.locateProperties=G,e.locateSlices=K,e.parseProject=q,e.propertyCheckBeReadonly=J,e.sliceCheckBeFreeOfCycles=Y,e.sliceCheckHaveMaxDistanceFromMainSequence=X});
2
+ `)}}function p(e,t,n){if(e.length===0)return{pass:!1,message:()=>`No items matched the selector. The rule is vacuous.`};let r=[];for(let i of e){let{passes:e,failMessage:a,failNotMessage:o}=n(i);t&&e?o&&r.push(o):!t&&!e&&a&&r.push(a)}return{pass:r.length===0,message:()=>r.join(`
3
+ `)}}function m(e,t,n,r,i,a){return p(e,a,e=>{let a=t(e),o=n(e),s=o>i,c=`${r} ${a||`Anonymous`}`;return{passes:!s,failMessage:`${c} has a total cyclomatic complexity of ${o}, which exceeds the maximum of ${i}.`,failNotMessage:`${c} has a total cyclomatic complexity of ${o}, which exceeds the maximum of ${i}, but it shouldn't.`}})}function h(e,t,n){return m(e.classes,e=>e.name,e=>e.cyclomatic_complexity||0,`Class`,t,n)}function g(e,t,n,r,i){return p(e,i,e=>{let i=t(e),a=!1;switch(r){case`export`:a=!!e.is_exported;break;case`default`:a=!!e.is_default;break;case`abstract`:a=!!e.is_abstract;break;case`async`:a=!!e.is_async;break;case`readonly`:a=!!e.is_readonly;break;default:throw Error(`Modifier ${r} is not fully supported.`)}let o=`${n} ${i||`Anonymous`}`;return{passes:a,failMessage:`${o} does not have modifier ${r}, but it should.`,failNotMessage:`${o} has modifier ${r}, but it shouldn't.`}})}function ee(e,t,n){return g(e.classes,e=>e.name,`Class`,t,n)}function _(e,n,r,i){return p(e,i,e=>{let i=n(e);if(!e._filePath)return{passes:!0,failMessage:``,failNotMessage:``};let a=t.basename(e._filePath,t.extname(e._filePath)),o=i===a,s=`${r} ${i||`Anonymous`}`;return{passes:o,failMessage:`${s} does not have a name matching its filename ${a}, but it should.`,failNotMessage:`${s} has a name matching its filename ${a}, but it shouldn't.`}})}function te(e,t){return _(e.classes,e=>e.name,`Class`,t)}function v(e,t,n){let r=[];for(let i of e.classes){let e=i.name||`Anonymous`,a=!1;i.implements.includes(t)&&(a=!0),n&&a?r.push(`Class ${e} implements ${t}, but it shouldn't.`):!n&&!a&&r.push(`Class ${e} does not implement ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
4
+ `)}}function y(e,t,n,r,i){let a=typeof r==`string`?new RegExp(r):r;return p(e,i,e=>{let i=t(e),o=i?a.test(i):!1,s=`${n} ${i||`Anonymous`}`;return{passes:o,failMessage:`${s} does not match pattern ${r}, but it should.`,failNotMessage:`${s} matches pattern ${r}, but it shouldn't.`}})}function b(e,t,n){return y(e.classes,e=>e.name,`Class`,t,n)}function x(e,t,n){let r=[];for(let i of e.classes){let e=i.name||`Anonymous Class`,a=i._filePath,o=a.includes(`/${t}/`)||a.includes(`\\${t}\\`);n&&o?r.push(`Class ${e} resides in ${t}, but it shouldn't.`):!n&&!o&&r.push(`Class ${e} does not reside in ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
5
+ `)}}function S(e){if(e.length===0)return``;let t=[...e].sort(),n=t[0],r=t[t.length-1],i=0;for(;i<n.length&&n[i]===r[i];)i++;let a=n.substring(0,i),o=Math.max(a.lastIndexOf(`/`),a.lastIndexOf(`\\`));return o===-1?``:a.substring(0,o+1)}function C(e,t,n){let r=e.substring(t.length).replace(/\\/g,`/`).replace(/^\//,``),i=n.replace(/\\/g,`/`).replace(/^\//,``).replace(/\/$/,``);return r.startsWith(`src/`)&&!i.startsWith(`src/`)&&i!==`src`&&(r=r.substring(4)),r.startsWith(`${i}/`)||r===i}function w(e,t){let n=e.replace(/\\/g,`/`),r=t.replace(/\\/g,`/`).replace(/^\//,``).replace(/\/$/,``),i=n.split(`/`),a=r.split(`/`);return i.some((e,t)=>a.every((e,n)=>i[t+n]===e))}function T(e,t,n){let r=e;if(n?.inFolder){let i=e.map(e=>e._filePath),a=t.projectRoot||S(i);r=r.filter(e=>C(e._filePath,a,n.inFolder))}if(n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>t.name&&e.test(t.name))}if(n?.withDecorator){let e=n.withDecorator;r=r.filter(t=>t.decorators.includes(e))}if(n?.extending&&(r=r.filter(e=>e.extends===n.extending)),n?.implementing){let e=n.implementing;r=r.filter(t=>t.implements.includes(e))}return n?.havingModifier&&(r=r.filter(e=>{switch(n.havingModifier){case`export`:return e.is_exported;case`default`:return e.is_default;case`abstract`:return e.is_abstract;default:throw Error(`Modifier ${n.havingModifier} is not fully supported.`)}})),{type:`ClassLocator`,classes:r,projectData:t}}function E(e,t,n){if(e.files.length===0)return{pass:!1,message:()=>`No files matched the selector. The rule is vacuous.`};let r=[],i=typeof t==`string`?new RegExp(t):t;for(let a of e.files){let e=(a.external_dependencies||[]).some(e=>i.test(e));n&&e?r.push(`${a.path} incorrectly depends on external module '${t}'`):!n&&!e&&r.push(`${a.path} does not depend on external module '${t}'`)}return{pass:r.length===0,message:()=>r.join(`
6
+ `)}}function D(e,t){return e.dependencies||[]}function O(e,t,n){if(e.files.length===0)return{pass:!1,message:()=>`No files matched the selector. The rule is vacuous.`};let r=[];for(let i of e.files){let a=D(i,e.projectData).some(e=>w(e,t));n&&a?r.push(`File ${i.path} depends on files in ${t}, but it shouldn't.`):!n&&!a&&r.push(`File ${i.path} does not depend on files in ${t}, but it should.`)}return{pass:r.length===0,message:()=>r.join(`
7
+ `)}}function k(e,t){if(e.files.length===0)return{pass:!1,message:()=>`No files matched the selector. The rule is vacuous.`};let n=e.files.map(e=>e.path),r=e.archestProject;if(!r)return{pass:!0,message:()=>`Mock pass: archestProject not in registry`};let i=r.checkFileCycles(n,!!t);return{pass:i.pass,message:()=>i.message}}function A(e,t,n){return m(e.files,e=>e.path,e=>{let t=0;for(let n of e.functions)t+=n.cyclomatic_complexity||0;for(let n of e.classes)t+=n.cyclomatic_complexity||0;return t},`File`,t,n)}function j(e,t,n){if(e.files.length===0)return{pass:!1,message:()=>`No files matched the selector. The rule is vacuous.`};let r=[];for(let i of e.files){let e=i.functions.filter(e=>e.is_exported).length,a=e>t;n&&a?r.push(`File ${i.path} has ${e} exported functions, which exceeds the maximum of ${t}, but it shouldn't.`):!n&&a&&r.push(`File ${i.path} has ${e} exported functions, which exceeds the maximum of ${t}.`)}return{pass:n?r.length>0:r.length===0,message:()=>r.join(`
8
+ `)||(n?`Expected some files to exceed maximum exported functions, but none did.`:``)}}function M(e,t,n,r,i,a){return p(e,a,e=>{let a=t(e),o=n(e),s=o<i,c=`${r} ${a||`Anonymous`}`;return{passes:!s,failMessage:`${c} has a maintainability index of ${o.toFixed(2)}, which falls below the minimum of ${i}.`,failNotMessage:`${c} has a maintainability index of ${o.toFixed(2)}, which falls below the minimum of ${i}, but it shouldn't.`}})}function ne(e,t,n){return e.files.length===0?{pass:!1,message:()=>`No files matched the selector. The rule is vacuous.`}:M(e.files,e=>e.path,e=>{let t=[...e.functions||[],...e.classes||[]];if(t.length>0){let e=t.reduce((e,t)=>e+(t.maintainability_index||0),0);return Math.round(e/t.length)}return 100},`File`,t,n)}function re(e,t,n){return y(e.files,e=>e.path,`File`,t,n)}function N(e,t,n){let r=e;if(n?.inFolder){let i=e.map(e=>e._filePath),a=t.projectRoot||S(i);r=r.filter(e=>C(e._filePath,a,n.inFolder))}if(n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>t.name&&e.test(t.name))}return n?.isTopLevel&&(r=r.filter(e=>e.is_top_level)),{type:`FunctionLocator`,functions:r,projectData:t}}function P(e,t,n,r){let i=e;if(r?.inFolder){let n=e.map(e=>e.path),a=t.projectRoot||S(n);i=i.filter(e=>C(e.path,a,r.inFolder))}if(r?.matchNamePattern){let e=typeof r.matchNamePattern==`string`?new RegExp(r.matchNamePattern):r.matchNamePattern;i=i.filter(t=>e.test(t.path))}if(r?.hasFunction){let e=r.hasFunction;i=i.filter(n=>N((n.functions||[]).map(e=>({...e,_filePath:n.path})),t,e).functions.length>0)}if(r?.hasClass){let e=r.hasClass;i=i.filter(n=>T((n.classes||[]).map(e=>({...e,_filePath:n.path})),t,e).classes.length>0)}let a={type:`FileLocator`,files:i,projectData:t};return n&&Object.defineProperty(a,"archestProject",{value:n,enumerable:!1}),a}function F(e,t){let n=[];for(let r of e.functions){let e=r.name||`Anonymous Function`,i=r.has_explicit_return_type;t&&i?n.push(`Function ${e} has an explicit return type, but it shouldn't.`):!t&&!i&&n.push(`Function ${e} does not have an explicit return type, but it should.`)}return{pass:n.length===0,message:()=>n.join(`
9
+ `)}}function I(e,t,n){return m(e.functions,e=>e.name,e=>e.cyclomatic_complexity||0,`Function`,t,n)}function L(e,t,n){return M(e.functions,e=>e.name,e=>e.maintainability_index||100,`Function`,t,n)}function R(e,t,n){return g(e.functions,e=>e.name,`Function`,t,n)}function z(e,t){return _(e.functions,e=>e.name,`Function`,t)}function B(e,t,n){return y(e.functions,e=>e.name,`Function`,t,n)}function V(e){let t=[];for(let n of e.assertions)t.push(...n(e.files));return{pass:t.length===0,message:()=>t.join(`
10
+ `)}}function H(e,t){return{type:`LayeredArchitecture`,files:e,layers:new Map,assertions:[],projectData:t}}function U(e,t,n){return e.layers.set(t,n),e}function W(e,t){return e.dependencies||[]}function G(e,t){if(!e.layers.has(t))throw Error(`Layer ${t} is not defined`);return e.assertions.push(n=>{let r=[],i=e.layers.get(t);for(let a of n){let n=a.path;!n.includes(`/${i}/`)&&!n.includes(`\\${i}\\`)&&W(a,e.projectData).some(e=>e.includes(`/${i}/`)||e.includes(`\\${i}\\`))&&r.push(`File ${n} accesses layer ${t} but it shouldn't.`)}return r}),e}function K(e,t,n){if(!e.layers.has(t))throw Error(`Layer ${t} is not defined`);return e.assertions.push(r=>{let i=[],a=e.layers.get(t),o=n.map(t=>e.layers.get(t));for(let s of r){let r=s.path,c=o.some(e=>r.includes(`/${e}/`)||r.includes(`\\${e}\\`));!r.includes(`/${a}/`)&&!r.includes(`\\${a}\\`)&&!c&&W(s,e.projectData).some(e=>e.includes(`/${a}/`)||e.includes(`\\${a}\\`))&&i.push(`File ${r} accesses layer ${t} but only ${n.join(`, `)} are allowed.`)}return i}),e}function q(e,t,n){let r=e;if(n?.inFolder){let i=e.map(e=>e._filePath),a=t.projectRoot||S(i);r=r.filter(e=>C(e._filePath,a,n.inFolder))}if(n?.matchNamePattern){let e=typeof n.matchNamePattern==`string`?new RegExp(n.matchNamePattern):n.matchNamePattern;r=r.filter(t=>e.test(t.name))}return{type:`PropertyLocator`,properties:r,projectData:t}}function J(e,t,n){let r=n.replace(/[.+?^${}()|[\]\\]/g,`\\$&`).replace(/\*/g,`([^/\\\\]+)`),i=new RegExp(r),a=new Set,o=new Map;for(let t of e){let e=t.path.match(i);if(e?.[1]){let n=e[1];a.add(n),o.has(n)||o.set(n,[]),o.get(n)?.push(t)}}return{type:`SliceLocator`,slicePattern:i,sliceIds:a,sliceFiles:o,projectData:t}}function Y(e={}){let i=e.tsConfigFilePath||r.findConfigFile(process.cwd(),r.sys.fileExists,`tsconfig.json`);if(!i)throw Error(`Could not find tsconfig.json`);let a=(0,t.dirname)(i),o=r.readConfigFile(i,r.sys.readFile);e.include&&(o.config.include=e.include),e.exclude&&(o.config.exclude=e.exclude);let s=r.parseJsonConfigFileContent(o.config,r.sys,a,void 0,i,void 0,[{extension:`.vue`,isMixedContent:!0,scriptKind:r.ScriptKind.Deferred},{extension:`.svelte`,isMixedContent:!0,scriptKind:r.ScriptKind.Deferred}]),c=n.ArchestProject.parse(s.fileNames),l=JSON.parse(c.getProjectData());return l.projectRoot=a,{projectData:l,getFiles:e=>P(l.files,l,c,e),getClasses:e=>T(l.files.flatMap(e=>e.classes.map(t=>({...t,_filePath:e.path}))),l,e),layeredArchitecture:()=>{let e=H(l.files,l),t={layer:(n,r)=>(e=U(e,n,r),t),whereLayer:n=>({shouldNotBeAccessedByAnyLayer:()=>(e=G(e,n),t),shouldOnlyBeAccessedBy:(...r)=>(e=K(e,n,r),t)}),check:()=>V(e),get data(){return e}};return t},getFunctions:e=>N(l.files.flatMap(e=>e.functions.map(t=>({...t,_filePath:e.path}))),l,e),getProperties:e=>q(l.files.flatMap(e=>e.properties.map(t=>({...t,_filePath:e.path}))),l,e),getSlices:e=>J(l.files,l,e)}}function ie(e,t){let n=[];for(let r of e.properties){let e=r.name||`Anonymous Property`,i=r.is_readonly;t&&i?n.push(`Property ${e} is readonly, but it shouldn't be.`):!t&&!i&&n.push(`Property ${e} is not readonly, but it should be.`)}return{pass:n.length===0,message:()=>n.join(`
11
+ `)}}function ae(e,t){if(e.sliceIds.size===0)return{pass:!1,message:()=>`No slices matched the selector. The rule is vacuous.`};let n=new Map;for(let t of e.sliceIds)n.set(t,new Set);for(let[t,r]of e.sliceFiles.entries())for(let i of r)if(i.dependencies)for(let r of i.dependencies){let i=r.match(e.slicePattern);if(i?.[1]){let r=i[1];r!==t&&e.sliceIds.has(r)&&n.get(t)?.add(r)}}let r=new Set,i=new Set,a=[],o=(e,t)=>{r.add(e),i.add(e);for(let s of n.get(e)||[])if(!r.has(s)){if(o(s,[...t,s]))return!0}else if(i.has(s))return a.push(`Cycle detected between slices: ${t.join(` -> `)} -> ${s}`),!0;return i.delete(e),!1};for(let t of e.sliceIds)r.has(t)||o(t,[t]);return t?{pass:a.length>0,message:()=>a.length>0?``:`Expected cycles between slices but found none.`}:{pass:a.length===0,message:()=>a.join(`
12
+ `)}}function X(e,t,n){if(e.sliceIds.size===0)return{pass:!1,message:()=>`No slices matched the selector. The rule is vacuous.`};let r=[],i=new Map,a=new Map;for(let t of e.sliceIds)i.set(t,new Set),a.set(t,new Set);for(let[t,n]of e.sliceFiles.entries())for(let r of n)if(r.dependencies)for(let n of r.dependencies){let r=n.match(e.slicePattern);if(r?.[1]){let n=r[1];n!==t&&e.sliceIds.has(n)&&(i.get(t)?.add(n),a.get(n)?.add(t))}}for(let o of e.sliceIds){let s=i.get(o)?.size||0,c=a.get(o)?.size||0,l=e.sliceFiles.get(o),u=0,d=0;for(let e of l)for(let t of e.classes)d++,t.is_abstract&&u++;let f=s+c===0?0:s/(c+s),p=d===0?0:u/d,m=Math.abs(p+f-1),h=m>t;n&&h?r.push(`Slice ${o} has a Distance from the Main Sequence of ${m.toFixed(2)}, which exceeds the maximum of ${t}, but it shouldn't.`):!n&&h&&r.push(`Slice ${o} has a Distance from the Main Sequence of ${m.toFixed(2)}, which exceeds the maximum of ${t}.`)}return{pass:n?r.length>0:r.length===0,message:()=>r.join(`
13
+ `)||(n?`Expected some slices to exceed maximum distance from main sequence, but none did.`:``)}}function oe(e,t=`test.ts`){return r.createSourceFile(t,e,r.ScriptTarget.Latest,!0)}function se(e){return{files:e.map(e=>({path:e.fileName,classes:Z(e),functions:Q(e),properties:$(e)}))}}function ce(e){return n.ArchestProject.parseMock(JSON.stringify(e))}function Z(e){let t=[];return r.forEachChild(e,n=>{if(r.isClassDeclaration(n)){let i=null,a=[];if(n.heritageClauses)for(let e of n.heritageClauses){if(e.token===r.SyntaxKind.ExtendsKeyword)for(let t of e.types)r.isIdentifier(t.expression)&&(i=t.expression.text);if(e.token===r.SyntaxKind.ImplementsKeyword)for(let t of e.types)r.isIdentifier(t.expression)&&a.push(t.expression.text)}let o=[];if(r.canHaveDecorators(n)){let e=r.getDecorators(n);if(e)for(let t of e)r.isIdentifier(t.expression)?o.push(t.expression.text):r.isCallExpression(t.expression)&&r.isIdentifier(t.expression.expression)&&o.push(t.expression.expression.text)}t.push({name:n.name?.text||null,is_exported:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.ExportKeyword)||!1,is_default:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.DefaultKeyword)||!1,is_abstract:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.AbstractKeyword)||!1,extends:i,implements:a,decorators:o,_filePath:e.fileName})}}),t}function Q(e){let t=[];return r.forEachChild(e,n=>{if(r.isFunctionDeclaration(n)||r.isMethodDeclaration(n)||r.isArrowFunction(n)){let i=null;(r.isFunctionDeclaration(n)||r.isMethodDeclaration(n))&&(i=n.name?.getText()||null),t.push({name:i,is_exported:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.ExportKeyword)||!1,is_async:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.AsyncKeyword)||!1,is_top_level:!0,has_explicit_return_type:!!n.type,_filePath:e.fileName})}}),t}function $(e){let t=[];return r.forEachChild(e,n=>{r.isClassDeclaration(n)&&n.members.forEach(n=>{r.isPropertyDeclaration(n)&&t.push({name:n.name.getText(),is_readonly:r.canHaveModifiers(n)&&r.getModifiers(n)?.some(e=>e.kind===r.SyntaxKind.ReadonlyKeyword)||!1,_filePath:e.fileName})})}),t}e.checkDependOnExternalModule=E,e.checkDependOnFilesInFolder=O,e.checkLayeredArchitecture=V,e.classCheckExtendClass=f,e.classCheckHaveMaxCyclomaticComplexity=h,e.classCheckHaveModifier=ee,e.classCheckHaveNameMatchingFileName=te,e.classCheckImplementInterface=v,e.classCheckMatchNamePattern=b,e.classCheckResideInFolder=x,e.createLayeredArchitecture=H,e.createMockArchestProject=ce,e.createMockProgram=se,e.createSourceFile=oe,e.fileCheckBeFreeOfCycles=k,e.fileCheckHaveMaxCyclomaticComplexity=A,e.fileCheckHaveMaxExportedFunctions=j,e.fileCheckHaveMinMaintainabilityIndex=ne,e.fileCheckMatchNamePattern=re,e.functionCheckHaveExplicitReturnType=F,e.functionCheckHaveMaxCyclomaticComplexity=I,e.functionCheckHaveMinMaintainabilityIndex=L,e.functionCheckHaveModifier=R,e.functionCheckHaveNameMatchingFileName=z,e.functionCheckMatchNamePattern=B,e.getClasses=Z,e.getFunctions=Q,e.getProperties=$,e.layer=U,e.layerShouldNotBeAccessedByAnyLayer=G,e.layerShouldOnlyBeAccessedBy=K,e.locateClasses=T,e.locateFiles=P,e.locateFunctions=N,e.locateProperties=q,e.locateSlices=J,e.parseProject=Y,e.propertyCheckBeReadonly=ie,e.sliceCheckBeFreeOfCycles=ae,e.sliceCheckHaveMaxDistanceFromMainSequence=X});
14
14
  //# sourceMappingURL=index.js.map