Skip to content

API Reference

All public exports from ts-archunit, organized by category.

Entry Points

ExportSignatureDescription
projectproject(tsConfigPath: string): ArchProjectLoad a TypeScript project. Cached per path.
workspaceworkspace(tsConfigPaths: string[]): ArchProjectLoad multiple tsconfigs into a unified project for monorepo use.
modulesmodules(p: ArchProject): ModuleRuleBuilderRule builder for source files (imports/dependencies).
classesclasses(p: ArchProject): ClassRuleBuilderRule builder for class declarations.
functionsfunctions(p: ArchProject, options?: FunctionCollectionOptions): FunctionRuleBuilderRule builder for functions, arrow functions, class methods. options.includeObjectLiteralFunctions (default off) also collects object-literal function values.
typestypes(p: ArchProject): TypeRuleBuilderRule builder for interfaces and type aliases.
slicesslices(p: ArchProject): SliceRuleBuilderRule builder for file groupings (cycles, layers).
callscalls(p: ArchProject): CallRuleBuilderRule builder for call expressions.
jsxElementsjsxElements(p: ArchProject): JsxRuleBuilderRule builder for JSX elements in .tsx/.jsx files.
withinwithin(sel: CallRuleBuilder): ScopedContextScoped rule builder for callback functions inside matched calls.
tsconfigtsconfig(p: ArchProject): TsconfigBuilderAssert the project's resolved TypeScript compiler options.
correspondencecorrespondence(p: ArchProject): CorrespondenceBuilderAssert two independently-derived key sets correspond ("every X has a matching Y").

Rule Builders

ExportDescription
RuleBuilderBase rule builder class.
TerminalBuilderBase terminal builder class (slices, smells, cross-layer).
TsconfigBuilderBuilder returned by tsconfig(); adds .requires().
ModuleRuleBuilderBuilder returned by modules().
ClassRuleBuilderBuilder returned by classes().
FunctionRuleBuilderBuilder returned by functions().
TypeRuleBuilderBuilder returned by types().
SliceRuleBuilderBuilder returned by slices().
CallRuleBuilderBuilder returned by calls().
JsxRuleBuilderBuilder returned by jsxElements().
ScopedFunctionRuleBuilderBuilder returned by within().functions().
CorrespondenceBuilderBuilder returned by correspondence().

Rule Builder Methods

Chain methods available on all rule builders (RuleBuilder, SliceRuleBuilder).

MethodSignatureDescription
.excluding().excluding(...patterns: (string | RegExp | SilentExclusion)[])Permanently suppress violations matching element name (e.g., 'MyService.doWork'), file path, or message. Strings use exact match; regex uses .test(). Warns on unused patterns. Wrap with silent() to suppress the warning.
.because().because(reason: string)Attach a human-readable rationale to the rule.
.rule().rule(metadata: RuleMetadata)Attach rich metadata (id, because, suggestion, docs).
.check().check(options?: CheckOptions)Execute rule; throw on violations.
.warn().warn(options?: CheckOptions)Execute rule; log violations without throwing, with one exception (configuration findings).
.severity().severity(level: 'error' | 'warn')Terminal — execute immediately with the given severity ('error'.check(), 'warn'.warn()). Returns void.
.asSeverity().asSeverity(level: 'error'): this
.asSeverity(level: 'warn', options?: { accepted?: readonly string[] }): this
Non-terminal — mark the rule's severity WITHOUT executing, and return a copy (bug 0016; it returned this through v0.20.0). Use in a rule file's export default [...] array so the CLI runs it; .violations() stamps each result with this severity. 'error' is the default, so .asSeverity('warn') is the meaningful call. Do NOT confuse with the terminal .severity(). .asSeverity('warn') alone is an advisory warning (permanent, unchanged since 0.16.0). .asSeverity('warn', { accepted }) is a deferred warning (plan 0090): a violation whose subjectOf() is in accepted stays warn; anything not in the list — a genuinely new finding — escalates to error. See violation-reporting for the full contract.
.assertsSomething().assertsSomething(): booleanWhether this rule asserts anything about what it selects (0.22.0). false means the rule can never fail, and since 0.23.0 the assertion gate turns that into an unsuppressable configuration finding on every terminal. diagnose()/doctor read it too. External TerminalBuilder subclasses are exempt by default (true) — the default is a compatibility choice, not a judgement that your builder is fine, so override it if your builder has an assertion-less state, or it stays outside the gate permanently.
.assertionAdvice().assertionAdvice(): stringThe remedy for this builder's assertion-less state, per state (0.22.0). One string, one place: doctor's advice and the failure message both read it verbatim, so the diagnostic and the failure cannot drift.
.violations().violations(): ArchViolation[]Execute rule, return violations without throwing (severity-stamped). For programmatic access and presets.
.subjects().subjects(): readonly T[]The elements matched by the predicate chain (post-.that(), before any condition). Powers correspondence().side() and .expectNonEmpty().
.expectNonEmpty().expectNonEmpty(): thisRedundant since 0.34.0 — an empty selection fails by default. Still reads as a statement of intent, and still legal, but it no longer changes behaviour. The finding bypasses diff-aware/baseline.
.expectEmpty().expectEmpty(): this0.34.0. Assert the selector matches nothing, and fail the day it matches something. The escape hatch for a legitimately-empty selection — an assertion, not a silencer. Declaring it alongside .expectNonEmpty() throws a TypeError when the rule is built.
.ownsDiscoveryDiagnosis().ownsDiscoveryDiagnosis(): boolean0.44.0. Whether this builder reports a dead discovery glob itself, with a better message than the generic gate can produce. false by default, so an external subclass is covered by the gate rather than silently exempt. Override to true only if your builder already produces a finding that names the dead population. Two builders do: slices unconditionally, because its fan-out semantics make the gate's per-tree view wrong; and crossLayer per condition — its three shipped conditions name the dead layer, and a condition that does not is covered by the gate instead. Since 0.46.1 that is decided by an internal registry, not by a property you can set.
deadSelectorFindings()protected deadSelectorFindings(): { selector: ArchViolation[]; discovery: ArchViolation[] }Protected; the return type CHANGED in 0.44.0 from ArchViolation[] to the two buckets, so an external override must be updated — a TypeScript override stops compiling, and a JavaScript one throws at the call site. The split exists because the two positions have different precedence: a dead selector always wins, while a dead discovery glob defers to a builder that declares ownsDiscoveryDiagnosis(). ArchViolation carries no position, so the caller cannot recover it downstream.
.describeRule().describeRule(): RuleDescriptionReturn rule metadata without executing. Used by explain command.

Running Rule Arrays

ExportSignatureDescription
checkAllcheckAll(rules: RuleBuilderLike[], options?: CheckOptions): voidRun an array of rules (e.g. a spread preset) and throw one aggregated ArchRuleError on any error-severity violation; warns are reported but never throw. The test-file terminal for the returning form.

Exclusion Comments

ExportSignatureDescription
parseExclusionCommentsparseExclusionComments(source: string, file: string): ParseResultParse // ts-archunit-exclude comments from source text.
isExcludedByCommentisExcludedByComment(violation: ArchViolation, comments: ExclusionComment[]): booleanCheck if a violation is covered by an exclusion comment.

Types

ExportKindDescription
ExclusionCommenttypeParsed exclusion comment with ruleId, reason, file, line, isBlock, endLine.
ExclusionWarningtypeWarning about a malformed exclusion comment.
ParseResulttypeResult of parsing: { exclusions, warnings }.

Identity Predicates

Available on all entry points via .that().

ExportSignatureDescription
haveNameMatchinghaveNameMatching(re: RegExp)Name matches regex.
haveNameStartingWithhaveNameStartingWith(s: string)Name starts with string.
haveNameEndingWithhaveNameEndingWith(s: string)Name ends with string.
resideInFileresideInFile(glob: string)File path matches glob.
resideInFolderresideInFolder(glob: string)Folder path matches glob.
areExportedareExportedElement is exported.
areNotExportedareNotExportedElement is not exported.

Module Predicates

ExportSignatureDescription
importFromimportFrom(...globs) or importFrom(globs[], options)Module has any edge to a path matching glob — import, export … from, import() or type X = import(…). Options: { ignoreTypeImports }. Selects MORE files since v0.28.0.
predicateNotImportFromnotImportFrom(...globs) or notImportFrom(globs[], options)Module has no edge to a path matching glob — every kind counts. Options: { ignoreTypeImports }. Selects FEWER files since v0.28.0: a file whose only matching edge is a re-export now fails the predicate and drops out of the selection.
exportSymbolNamedexportSymbolNamed(name: string)Module exports a symbol with the name.
havePathMatchinghavePathMatching(glob: string)Module file path matches the glob.

Class Predicates

ExportSignatureDescription
extendextend(name: string)Class extends the named base class.
implementimplement(name: string)Class implements the named interface.
haveDecoratorhaveDecorator(name: string)Class has the named decorator.
haveDecoratorMatchinghaveDecoratorMatching(re: RegExp)Class has a decorator matching regex.
areAbstractareAbstractClass is abstract.
classHaveMethodNamedhaveMethodNamed(name: string)Class has a method with the name.
haveMethodMatchinghaveMethodMatching(re: RegExp)Class has a method matching regex.
havePropertyNamedhavePropertyNamed(name: string)Class has a property with the name.

Function Predicates

ExportSignatureDescription
areAsyncareAsyncFunction is async.
areNotAsyncareNotAsyncFunction is not async.
arePublicarePublic()Function/method is public (standalone always match).
areProtectedareProtected()Method is protected.
arePrivatearePrivate()Method is private.
haveParameterCounthaveParameterCount(n: number)Function has exactly n parameters.
haveParameterCountGreaterThanhaveParameterCountGreaterThan(n: number)Function has more than n parameters.
haveParameterCountLessThanhaveParameterCountLessThan(n: number)Function has fewer than n parameters.
haveParameterNamedhaveParameterNamed(name: string)Function has a parameter with the name.
haveReturnTypehaveReturnType(type: string)Function has the given return type.
haveRestParameterhaveRestParameter()Function has a ...args rest parameter.
haveOptionalParameterhaveOptionalParameter()Function has an optional or default-valued parameter.
haveParameterOfTypehaveParameterOfType(i: number, m: TypeMatcher)Parameter at index i matches the TypeMatcher.
haveParameterNameMatchinghaveParameterNameMatching(re: RegExp)Function has a parameter name matching regex.

Type Predicates

ExportSignatureDescription
areInterfacesareInterfacesType is an interface.
areTypeAliasesareTypeAliasesType is a type alias.
havePropertyhaveProperty(name: string)Type has a property with the name.
havePropertyOfTypehavePropertyOfType(name: string, re: RegExp)Property exists with type matching regex.
extendTypeextendType(name: string)Interface extends the named type.

Call Predicates

ExportSignatureDescription
onObjectonObject(name: string)Call is on the named object (e.g., app). Supports nested: router.route.
withMethodwithMethod(nameOrRegex: string | RegExp)Call method matches exact name or regex pattern.
withArgMatchingwithArgMatching(index: number, pattern: string | RegExp)Argument at index matches regex or exact string.
withStringArgwithStringArg(index: number, glob: string)String literal argument at index matches glob pattern.

CallRuleBuilder identity enrichment

MethodSignatureDescription
identifiedByArgidentifiedByArg(index: number)Opt-in: fold the indexed string-literal argument into the violation element and message so individual registrations can be .excluding()-targeted. See docs/calls.md for details and the Identity scope footgun.

JSX Predicates

ExportSignatureDescription
areHtmlElementsareHtmlElements(...tags: string[])Matches HTML intrinsic elements with the given tag names.
areComponentsareComponents(...names?: string[])Matches component elements. No args = all components.
jsxWithAttributewithAttribute(name: string)Filter to elements that have the named attribute.
jsxWithAttributeMatchingwithAttributeMatching(name: string, value: string | RegExp)Filter to elements where attribute matches value.

JSX Conditions

ExportSignatureDescription
jsxNotExistnotExist()Filtered JSX element set must be empty.
jsxHaveAttributehaveAttribute(name: string)Every matched element must have the named attribute.
jsxNotHaveAttributenotHaveAttribute(name: string)No matched element may have the named attribute.
jsxHaveAttributeMatchinghaveAttributeMatching(name: string, value: string | RegExp)Attribute must exist and match value.
jsxNotHaveAttributeMatchingnotHaveAttributeMatching(name: string, value: string | RegExp)Attribute must not match (or be absent).

JSX Utilities

ExportDescription
STANDARD_HTML_TAGSreadonly string[] — All standard HTML tag names for use with areHtmlElements().
collectJsxElements(sf: SourceFile) => ArchJsxElement[] — Collect JSX elements from a source file.

Structural Conditions

ExportSignatureDescription
notExistnotExist()No elements should match the predicates.
beExportedbeExported()All matched elements should be exported.
conditionResideInFileresideInFile(glob: string)All elements should reside in matching files.
conditionResideInFolderresideInFolder(glob: string)All elements should reside in matching folders.
conditionHaveNameMatchinghaveNameMatching(re: RegExp)All elements should have names matching regex.

Class Conditions

ExportSignatureDescription
shouldExtendshouldExtend(name: string)Class must extend the named base class.
shouldImplementshouldImplement(name: string)Class must implement the named interface.
shouldHaveMethodNamedshouldHaveMethodNamed(name: string)Class must have a method with the name.
shouldNotHaveMethodMatchingshouldNotHaveMethodMatching(re: RegExp)Class must not have methods matching regex.
classAcceptParameterOfTypeacceptParameterOfType(matcher: TypeMatcher)At least one param (ctor/method/setter) matches type.
classNotAcceptParameterOfTypenotAcceptParameterOfType(matcher: TypeMatcher)No param (ctor/method/setter) matches type.

Function Conditions

ExportSignatureDescription
functionNotExistnotExist()No functions should match.
functionBeExportedbeExported()Function must be exported.
functionBeAsyncbeAsync()Function must be async.
functionHaveNameMatchinghaveNameMatching(re: RegExp)Function name must match regex.
functionHaveReturnTypeMatchinghaveReturnTypeMatching(matcher: TypeMatcher)Return type must satisfy TypeMatcher.
functionAcceptParameterOfTypeacceptParameterOfType(matcher: TypeMatcher)At least one parameter matches TypeMatcher.
functionNotAcceptParameterOfTypenotAcceptParameterOfType(matcher: TypeMatcher)No parameter matches TypeMatcher.

Dependency Conditions

ExportSignatureDescription
onlyImportFromonlyImportFrom(...globs) or (globs[], options)Module may have no edge outside the listed paths — every kind counts. Options: { ignoreTypeImports }. Reports MORE findings since v0.28.0.
conditionNotImportFromnotImportFrom(...globs) or (globs[], options)Module must have no edge to the listed paths — import, export … from, import() or type X = import(…). Options: { ignoreTypeImports }. Reports MORE findings since v0.28.0.
dependOndependOn(...globs) or (globs[], options)Module must import from at least one matching path. Options: { ignoreTypeImports }.
onlyHaveTypeImportsFromonlyHaveTypeImportsFrom(...globs: string[])Imports from matching paths must use import type.
notHaveAliasedImportsnotHaveAliasedImports()No named import may use an alias (import { x as y }).

Body Analysis Matchers

ExportSignatureDescription
callcall(target: string | RegExp)Match function/method call expressions.
newExprnewExpr(target: string | RegExp)Match constructor invocations (new ...).
accessaccess(target: string | RegExp)Match property access expressions.
propertyproperty(name: string | RegExp, value?: boolean | number | string | RegExp)Match property assignments by name and optional value.
expressionexpression(target: string | RegExp)Match any expression by text.
jsxElementjsxElement(tag: string | RegExp)Match JSX elements by tag name (tag-only, no attributes).
jsxTextjsxText()Match hardcoded JSX text content (children, incl. {"..."}).
typeAssertiontypeAssertion(options?: { allowConst?: boolean })Match as Type expressions. Excludes as const by default.
nonNullAssertionnonNullAssertion()Match ! non-null assertion expressions.
commentcomment(pattern: string | RegExp)Match comments attached to AST nodes.
STUB_PATTERNSRegExpMatches common stub markers: TODO, FIXME, HACK, XXX, STUB, etc.

Body Analysis Conditions

ExportSignatureDescription
classContainclassContain(matcher: ExpressionMatcher)Class methods must contain expression.
classNotContainclassNotContain(matcher: ExpressionMatcher)Class methods must not contain expression.
classUseInsteadOfclassUseInsteadOf(banned, replacement)Ban expression in class, suggest replacement.
functionContainfunctionContain(matcher: ExpressionMatcher)Function body must contain expression.
functionNotContainfunctionNotContain(matcher: ExpressionMatcher)Function body must not contain expression.
functionUseInsteadOffunctionUseInsteadOf(banned, replacement)Ban expression in function, suggest replacement.
functionNotHaveEmptyBodyfunctionNotHaveEmptyBody()Function must have at least one statement.
classNotHaveEmptyBodyclassNotHaveEmptyBody()Class must have at least one member.
moduleContainmoduleContain(matcher, options?)Module must contain expression.
moduleNotContainmoduleNotContain(matcher, options?)Module must not contain expression.
moduleUseInsteadOfmoduleUseInsteadOf(banned, replacement, opts?)Ban expression in module, suggest replacement.

Export Conditions

ExportSignatureDescription
notHaveDefaultExportnotHaveDefaultExport()Module must not have a default export.
haveDefaultExporthaveDefaultExport()Module must have a default export.
haveMaxExportshaveMaxExports(max: number)Module must have at most max named exports.

Reverse Dependency Conditions

ExportSignatureDescription
onlyBeImportedViaonlyBeImportedVia(...globs)All importers must match at least one glob.
beImportedbeImported()Module must be imported by at least one other file.
haveNoUnusedExportshaveNoUnusedExports()Every named export must be referenced by another file.

Property Conditions

ExportSignatureDescription
conditionHavePropertyNamedhavePropertyNamed(...names: string[])All named properties must exist.
conditionNotHavePropertyNamednotHavePropertyNamed(...names: string[])None of the named properties may exist.
conditionHavePropertyMatchinghavePropertyMatching(pattern: RegExp)At least one property name matches regex.
conditionNotHavePropertyMatchingnotHavePropertyMatching(pattern: RegExp)No property name matches regex.
haveOnlyReadonlyPropertieshaveOnlyReadonlyProperties()All properties must be readonly.
maxPropertiesmaxProperties(max: number)Property count must not exceed max.

Type-Level Conditions

ExportSignatureDescription
havePropertyTypehavePropertyType(name: string, matcher: TypeMatcher)Property must match the type matcher.

Type Matchers

ExportSignatureDescription
isStringisString(): TypeMatcherType is string.
isNumberisNumber(): TypeMatcherType is number.
isBooleanisBoolean(): TypeMatcherType is boolean.
isUnionOfLiteralsisUnionOfLiterals(): TypeMatcherType is a union of literal types.
isStringLiteralisStringLiteral(): TypeMatcherType is a string literal.
arrayOfarrayOf(matcher: TypeMatcher): TypeMatcherType is an array whose element matches.
matchingmatching(re: RegExp): TypeMatcherType text matches regex.
exactlyexactly(text: string): TypeMatcherType text matches exactly.

Slice Conditions

ExportSignatureDescription
beFreeOfCyclesbeFreeOfCycles(options?)No circular dependencies between slices. Ignores type-only imports by default; pass { ignoreTypeImports: false } to count type-only edges too — note that is not the pre-0.47 graph, since re-exports are counted as well since v0.48.0.
respectLayerOrderrespectLayerOrder(...layers) or (layers, options)Dependencies follow declared layer order. Counts type-only edges by default.
notDependOnnotDependOn(...slices) or (slices, options)No slice depends on the named slices. Counts type-only edges by default; one finding per dependency site.

Call Conditions

ExportSignatureDescription
callHaveCallbackContaininghaveCallbackContaining(matcher: ExpressionMatcher)At least one callback argument must contain the matched expression.
callNotHaveCallbackContainingnotHaveCallbackContaining(matcher: ExpressionMatcher)No callback argument may contain the matched expression.
callNotExistnotExist()The filtered call set must be empty.
haveArgumentWithPropertyhaveArgumentWithProperty(...names: string[])At least one object literal arg has ALL named properties.
notHaveArgumentWithPropertynotHaveArgumentWithProperty(...names: string[])No object literal arg has ANY of the named properties.
callHaveArgumentContaininghaveArgumentContaining(matcher: ExpressionMatcher)At least one argument subtree must contain the matched expression.
callNotHaveArgumentContainingnotHaveArgumentContaining(matcher: ExpressionMatcher)No argument subtree may contain the matched expression.

See Call Rules for usage examples.

Pattern Templates

ExportSignatureDescription
definePatterndefinePattern(name: string, opts: { returnShape: Record<string, PropertyConstraint> }): ArchPatternDefine a return type shape pattern.
followPatternfollowPattern(pattern: ArchPattern): Condition<ArchFunction>Condition: function return type must match the pattern. Unwraps Promise<T>.
PropertyConstraintstring | TypeMatcherstring = regex on type text, 'T[]' = any array, TypeMatcher = programmatic.
ArchPatterntypePattern with name and returnShape.

See Pattern Templates for usage examples.

Smell Detectors

ExportSignatureDescription
smells.duplicateBodiessmells.duplicateBodies(p: ArchProject): DuplicateBodiesBuilderDetect functions with structurally similar AST bodies.
smells.inconsistentSiblingssmells.inconsistentSiblings(p: ArchProject): InconsistentSiblingsBuilderDetect sibling files missing a majority pattern.
SmellBuilderclassBase builder: inFolder, minLines, ignoreTests, ignorePaths, groupByFolder, because, warn, check.
DuplicateBodiesBuilderclassExtends SmellBuilder. Adds withMinSimilarity(n) and minDistinctVocabulary(n) (default 8) — a pairwise floor gating comparison before similarity is even computed.
InconsistentSiblingsBuilderclassExtends SmellBuilder. Adds forPattern(matcher) and inertAdvice(): string — non-empty when the rule examines a real corpus but no folder is within one edit of the 60% majority needed to ever flag anything; '' otherwise, including when the pattern matches nothing at all. diagnose() reports the same text.
buildFingerprintbuildFingerprint(node: Node): FingerprintBuild an AST fingerprint (kinds, calls, nodeCount, distinctVocabulary) from a body node.
computeSimilaritycomputeSimilarity(a: Fingerprint, b: Fingerprint): numberLCS-based similarity between two fingerprints, normalized to [0,1].

See Smell Detection for usage examples.

Cross-Layer Validation

ExportSignatureDescription
crossLayercrossLayer(p: ArchProject): CrossLayerBuilderEntry point for cross-layer consistency rules.
CrossLayerBuilderclassBuilder: .layer(name, glob) (2+ required) then .mapping(fn).
MappedCrossLayerBuilderclassAfter .mapping(): provides .forEachPair().
PairConditionBuilderclassAfter .forEachPair(): provides .should(condition).
PairFinalBuilderclassTerminal: .because(), .rule(), .check(), .warn(), .severity().
haveMatchingCounterparthaveMatchingCounterpart(): PairConditionEvery left-layer file must have a counterpart in the right layer. Fails on an empty left layer (v0.18.0). Takes no argument since v0.42.0 — the builder supplies its own resolved layers. An optional Layer[] is still accepted for compatibility and is ignored when the builder provides them.
haveConsistentExportshaveConsistentExports(extractLeft, extractRight): PairConditionEvery exported symbol in left file must appear in right file.
satisfyPairConditionsatisfyPairCondition(desc: string, fn: (pair: LayerPair) => Violation | null): PairConditionCustom inline pair condition.

See Cross-Layer Validation for usage examples.

Correspondence

correspondence(p) asserts that two independently-derived key sets correspond — "every X has a matching Y" (ADR-008 Rule 5 as a primitive). Compares by identity, never count; an empty side fails (non-vacuity). Call .side() twice, then an assertion.

MethodSignatureDescription
.side().side(name, selection: RuleBuilder<T>, keyFn: KeyFn<T>) · .side(name, keys: readonly string[] | ReadonlySet<string>)Add a side — a selection keyed by keyFn, or a pre-derived key set. Call twice.
.beComplete().beComplete(): thisEvery key of the first side has a match in the second (A ⊆ B).
.haveNoOrphans().haveNoOrphans(): thisEvery key of the second side has a source in the first (B ⊆ A).
.beBijective().beBijective(): thisBoth directions — the key sets are identical.
.expectEmpty().expectEmpty(sideName?: string): thisDeclare a side empty. An assertion, not a permission: it fails the day the side fills up. Replaces .allowEmpty() from the next release.
.distinctKeysOn().distinctKeysOn(sideName: string): thisFail if a side maps two distinct subjects to one key (over-normalization).

Extends TerminalBuilder, so .rule() / .excluding() / .check() / .warn() / .violations() also apply.

ExportSignatureDescription
byNamebyName<T>(): KeyFn<T>Key a subject by getName() (<anonymous> fallback).
byArgbyArg<T>(index: number): KeyFn<T>Key a call-like subject by its argument at index (string/template literals are unquoted).
byPropertyNamesbyPropertyNames<T>(): KeyFn<T>Key a subject by each of its property names (one subject → many keys).
setCorrespondencesetCorrespondence(aKeys, bKeys): CorrespondenceResultPure identity set-difference + emptiness core (also backs crossLayer's existence check).
typescript
import { correspondence, calls, byArg } from '@nielspeter/ts-archunit'
import { ROUTE_PERMISSIONS } from '../src/config/route-permissions.js'

correspondence(p)
  .side(
    'routes',
    calls(p)
      .that()
      .onObject('app')
      .and()
      .withMethod(/^(get|post)$/),
    byArg(0),
  )
  .side('matrix', Object.keys(ROUTE_PERMISSIONS))
  .should()
  .beBijective()
  .rule({ id: 'auth/route-matrix', suggestion: 'Add the route to ROUTE_PERMISSIONS.' })
  .check()

Extension API

ExportSignatureDescription
definePredicatedefinePredicate<T>(desc, fn, globs?): Predicate<T>Create a custom predicate. globs declares the path globs it matches against, so doctor can report a dead one — see Custom rules.
defineConditiondefineCondition<T>(desc, fn, globs?): Condition<T>Create a custom condition. globs makes them visible to explain; a dead condition glob is deliberately not a finding.
andand(...inputs): Predicate | TypeMatcherCombine with AND. Accepts predicates or type matchers.
oror(...inputs): Predicate | TypeMatcherCombine with OR. Accepts predicates or type matchers.
notnot(input): Predicate | TypeMatcherNegate. Accepts a predicate or type matcher.

Utilities

ExportSignatureDescription
createViolationcreateViolation(node, msg, ctx): ArchViolationCreate a violation from a ts-morph node.
getElementNamegetElementName(node): stringGet the name of a ts-morph node.
getElementFilegetElementFile(node): stringGet the file path of a ts-morph node.
getElementLinegetElementLine(node): numberGet the line number of a ts-morph node.
remedyRepeatsMessageremedyRepeatsMessage(v: ArchViolation): booleanTrue when a violation's suggestion is its message, as a configuration finding's is. A renderer that already printed the message must not print it again as Fix:. Both fields carry the text on purpose — a tool reads suggestion, a human reads the body.
severityForseverityFor(v, fallback): 'error' | 'warn'The severity a violation must be reported at. A configuration finding is always error, whatever the rule asked for — an aggregator that applies the rule's own severity would silence the one finding that may not be silenced.
generateCodeFramegenerateCodeFrame(source, line, opts?): stringGenerate a code frame snippet.
formatViolationsformatViolations(violations, opts?): stringFormat violations for terminal output.
formatViolationsPlainformatViolationsPlain(violations): stringFormat violations as plain text.
formatViolationsJsonformatViolationsJson(violations): stringFormat violations as JSON.
formatViolationsGitHubformatViolationsGitHub(violations): stringFormat violations as GitHub Actions annotations.
detectFormatdetectFormat(): OutputFormatAuto-detect output format from environment.
isCIisCI(): booleanTrue if running in a CI environment.
ArchRuleErrorclassError thrown by .check() on violations.
isTypeOnlyImportisTypeOnlyImport(decl: ImportDeclaration): booleanCheck if an import is purely type-only.

Check Options

ExportSignatureDescription
withBaselinewithBaseline(path: string, options?: { root?: string }): BaselineLoad a baseline file for gradual adoption. root overrides the repository root used for portable identity — rarely needed, see Baselines.
generateBaselinegenerateBaseline(violations, path): BaselineDeltaWrite a baseline file from current violations, and return the delta it applied (before, after, added, removed). See enforcing the ratchet.
collectViolationscollectViolations(...rules): ArchViolation[]Collect violations from multiple rules.
diffAwarediffAware(base: string): DiffFilterOnly report violations in changed files.
BaselineclassBaseline instance for filtering known violations.
DiffFilterclassDiff filter instance.
silentsilent(pattern: string | RegExp): SilentExclusionWrap an exclusion pattern to suppress the "unused exclusion" warning.

ArchFunction Model

ExportSignatureDescription
collectFunctionscollectFunctions(sourceFiles): ArchFunction[]Collect all functions from source files.
fromFunctionDeclarationfromFunctionDeclaration(node): ArchFunctionWrap a function declaration.
fromArrowVariableDeclarationfromArrowVariableDeclaration(node): ArchFunctionWrap an arrow function variable.
fromMethodDeclarationfromMethodDeclaration(node): ArchFunctionWrap a class method declaration.

Callback Extraction

ExportSignatureDescription
extractCallbacksextractCallbacks(calls): ExtractedCallback[]Extract callback functions from call expressions.

Scoped Rules

ExportSignatureDescription
withinwithin(sel): ScopedContextCreate scoped rules from call selections.
ScopedFunctionRuleBuilderclassBuilder for function rules within a scope.

Metrics

ExportSignatureDescription
cyclomaticComplexitycyclomaticComplexity(body: Node | undefined): numberCalculate McCabe cyclomatic complexity for a function body.
linesOfCodelinesOfCode(node: Node): numberCount span lines (start to end, inclusive).
haveCyclomaticComplexityhaveCyclomaticComplexity(opts): Predicate<ClassDeclaration>Predicate: class has a method with complexity > threshold.
haveComplexityhaveComplexity(opts): Predicate<ArchFunction>Predicate: function has complexity > threshold.
haveMoreLinesThanhaveMoreLinesThan(n): Predicate<ClassDeclaration>Predicate: class spans more than n lines.
haveMoreFunctionLinesThanhaveMoreFunctionLinesThan(n): Predicate<ArchFunction>Predicate: function spans more than n lines.
haveMoreMethodsThanhaveMoreMethodsThan(n): Predicate<ClassDeclaration>Predicate: class has more than n methods.

CLI

ExportSignatureDescription
defineConfigdefineConfig(config: CliConfig): CliConfigDefine CLI configuration file.
resetProjectCacheresetProjectCache(): voidClear the project singleton cache. Used by watch mode and tests.

Diagnostics

Report which rules cannot enforce anything, without evaluating their conditions. It does materialize each rule's selection, because "this rule examined nothing" is a fact about the selection — so it is fast but not free, and the wording changed from "without running them" when that became true.

diagnose() itself returns findings rather than throwing — it is the surface for inspecting a rule set. Since 0.23.0 the underlying faults do fail a build when the rules actually run: a rule that asserts nothing is a configuration finding on every terminal. Use this to survey rules ahead of time — before an upgrade, or after adding rules. ts-archunit doctor is the CLI equivalent and exits non-zero when it reports anything, but it is a diagnostic you invoke rather than a gate; check is the gate.

Two hosts, one diagnosis. diagnose() runs wherever you build your rules, including inside vitest or jest. ts-archunit doctor is the CLI equivalent for rule files the CLI can load — the arch.rules.ts shape — and additionally reports a rule file that fails to load, which diagnose() cannot see because it never loads one.

ExportSignatureDescription
diagnosediagnose(rules: RuleBuilderLike[], project?): DiagnosticFinding[]Report what each rule cannot enforce: dead globs, condition-less rules, rules whose project cannot be named, and projects that loaded no files. Reports identities, never totals. The project defaults to the one each rule was built against.
DiagnosticFindingtype{ kind, rule, ruleFile?, origin?, glob?, position?, fault?, onDisk?, advice }. kind is the JSON contract and has seven values: 'dead-glob', 'no-condition', 'project-unknown', 'project-empty', 'orphan-exclusion', 'zero-subjects', 'inert' — only 'dead-glob' carries origin/glob/position/fault/onDisk. ruleFile is set by doctor, which knows which file each rule came from; diagnose() never sets it, because it is handed rules rather than files.
DiagnosableRuletypeWhat diagnose can inspect. Any RuleBuilderLike qualifies.

'inert' previews smells.inconsistentSiblings() rules that examine a non-empty corpus and still cannot fail: no folder's matching files are within one edit of the 60% majority forPattern() requires to flag anything. diagnose() reports it; check() does not yet fail on it — that flip is a separate, tracked migration (see docs/upgrading.md). A rule with a real majority, or one edit away from forming one, is unaffected: the preview is silent exactly where a finding could still fire soon.

typescript
import { project, modules, diagnose } from '@nielspeter/ts-archunit'

const p = project('tsconfig.json')
const rules = [
  modules(p).that().resideInFolder('**/src/reslvers/**').should().notHaveDefaultExport(),
]

// In a test, so rules written in vitest can be measured too:
expect(diagnose(rules)).toEqual([])

Or from the command line:

bash
ts-archunit doctor arch.rules.ts   # exits non-zero if it reports anything

Declaring globs on a custom predicate

A predicate that matches on a path can declare it, which is what makes it visible to diagnose. A predicate that declares nothing is simply invisible — nothing breaks.

ExportDescription
DeclaredGlob{ glob, kind, polarity?, base? } — what a predicate declares. Deliberately cannot express position.
GlobKind'file-path' | 'parent-dir' | 'import-target' | 'specifier' | 'literal' — names the string the matcher is applied to, not the API.
globNode, globAnyOfBuild a declaration from one glob, or from a variadic set (any).
combineGlobs, negateGlobs, stampGlobsFor combinators and builders. negateGlobs is a full NNF push-down.
GlobNode, GlobSite, GlobTree, GlobPosition, GlobBase, OpaqueGlobSupporting types.
typescript
import { globNode, type Predicate } from '@nielspeter/ts-archunit'
import type { SourceFile } from 'ts-morph'

function inGeneratedOutput(glob: string): Predicate<SourceFile> {
  return {
    description: `in generated output matching "${glob}"`,
    globs: globNode({ glob, kind: 'file-path' }),
    test: (sf) => sf.getFilePath().includes('/generated/'),
  }
}

Types (TypeScript)

ExportKindDescription
ArchProjecttypeLoaded TypeScript project.
PredicatetypePredicate interface.
ConditiontypeCondition interface.
ConditionContexttypeContext passed to condition evaluators.
ArchViolationtypeViolation model.
RuleMetadatatypeRule metadata (id, because, suggestion, docs).
RuleDescriptiontypeStructured rule description returned by .describeRule().
CheckOptionstypeOptions for .check().
OutputFormattypeOutput format ('terminal' | 'github' | 'json').
FormatOptionstypeOptions for formatting functions.
CodeFrameOptionstypeOptions for generateCodeFrame().
ExpressionMatchertypeMatcher returned by call(), newExpr(), etc.
TypeMatchertypeMatcher used with havePropertyType().
TypeDeclarationtypeUnion of interface and type alias declarations.
ArchFunctiontypeUnified function/arrow/method model.
ArchCalltypeModel for matched call expressions.
FunctionCollectionOptionstypeOptions for functions() (includeMethods, includeObjectLiteralFunctions).
KeyFntypecorrespondence().side() key extractor: (subject: T) => string | readonly string[].
KeysSourcetypeA pre-derived key set: readonly string[] | ReadonlySet<string>.
CorrespondenceResulttypeResult of setCorrespondence() (missing, orphans, aEmpty, bEmpty).
ObjectLiteralFunctiontypeA function found in an object literal (node, keyPath) from collectObjectLiteralFunctions().
SlicetypeA named group of source files.
SliceDefinitiontypeInput to assignedFrom().
NamedtypeElement with a name.
LocatedtypeElement with a file location.
ExportabletypeElement that can be exported.
BaselineEntrytypeSingle entry in a baseline file.
BaselineFiletypeStructure of the baseline JSON file.
LayertypeLayer definition for cross-layer validation.
LayerPairtypePair of elements from two layers.
PairConditiontypeCondition for cross-layer pairs.
ArchPatterntypePattern template definition.
PropertyConstrainttypeProperty type constraint in a pattern.
FingerprinttypeAST fingerprint for similarity detection.
ScopedContexttypeContext returned by within().
ExtractedCallbacktypeCallback extracted from a call expression.
PropertyBearingNodetypeUnion of interface, type alias, and class declarations.
ImportOptionstypeOptions for import conditions/predicates ({ ignoreTypeImports }).
CliConfigtypeCLI configuration object.

GraphQL Extension (ts-archunit/graphql)

Requires the optional graphql peer dependency.

Entry Points

ExportSignatureDescription
schemaschema(p: ArchProject | string, glob: string): SchemaRuleBuilderRule builder for .graphql schema files.
schemaFromSDLschemaFromSDL(sdl: string, path?): SchemaRuleBuilderRule builder from raw SDL string.
resolversresolvers(p: ArchProject, glob: string): ResolverRuleBuilderRule builder for resolver TypeScript files.

Schema Predicates

ExportSignatureDescription
queriesqueriesSelect Query type fields.
mutationsmutationsSelect Mutation type fields.
typesNamedtypesNamed(re: RegExp)Select types matching regex.
returnListOfreturnListOf(re: RegExp)Select fields returning a list of matching type.

Schema Conditions

ExportSignatureDescription
haveFieldshaveFields(...names: string[])Type must have the named fields.
acceptArgsacceptArgs(...names: string[])Field must accept the named arguments.
haveMatchingResolverhaveMatchingResolver(resolverGlob: string)Schema field has a matching resolver file.

Resolver Predicates

ExportSignatureDescription
resolveFieldReturningresolveFieldReturning(re: RegExp)Resolver resolves a field returning matching type.

Schema Loader

ExportSignatureDescription
loadSchemaFromGlobloadSchemaFromGlob(root, glob): LoadedSchemaLoad schema from glob pattern.
loadSchemaFromSDLloadSchemaFromSDL(sdl, path?): LoadedSchemaLoad schema from SDL string.
isGraphQLAvailableisGraphQLAvailable(): booleanCheck if the graphql package is installed.

Builders

ExportDescription
SchemaRuleBuilderBuilder for schema architecture rules.
ResolverRuleBuilderBuilder for resolver architecture rules.

Types

ExportKindDescription
SchemaElementtypeElement in a GraphQL schema.
LoadedSchematypeLoaded and parsed GraphQL schema.
GraphQLSchemaLiketypeSchema interface.
GraphQLObjectTypeLiketypeObject type interface.
GraphQLFieldLiketypeField interface.
GraphQLArgumentLiketypeArgument interface.
GraphQLTypeLiketypeType interface.

Presets (ts-archunit/presets)

Parameterized architecture rule bundles that generate multiple coordinated rules from a single function call.

Every preset returns RuleBuilderLike[] — spread it into a rule file (export default [...]) or run it with checkAll in a test.

ExportSignatureDescription
recommendedrecommended(p, options?): RuleBuilderLike[]Thin universal safety floor (eval, Function ctor, …).
agentGuardrailsagentGuardrails(p, options): RuleBuilderLike[]Guardrails for AI-agent mistakes.
layeredArchitecturelayeredArchitecture(p, options): RuleBuilderLike[]Layer ordering, cycles, isolation, restricted packages.
dataLayerIsolationdataLayerIsolation(p, options): RuleBuilderLike[]Base class extension and typed error enforcement.
strictBoundariesstrictBoundaries(p, options): RuleBuilderLike[]No cycles, no cross-boundary imports, shared isolation.
validateOverridesvalidateOverrides(overrides, knownIds): voidWarn on unrecognized override keys.

See Architecture Presets for full configuration options.

Standard Rules (Sub-Path Imports)

ts-archunit/rules/typescript

ExportDescription
noAnyProperties()Class properties must not be typed as any.
noTypeAssertions()Method bodies must not contain as type assertions (allows as const).
noNonNullAssertions()Method bodies must not contain non-null assertions (!).

ts-archunit/rules/security

ExportTargetDescription
noEval()classesNo eval() calls in class methods.
noFunctionConstructor()classesNo new Function() constructor.
noConsoleLog()classesNo console.log calls.
noProcessEnv()classesNo direct process.env access.
noConsole()classesNo console access at all (log, warn, error, etc).
noJsonParse()classesNo JSON.parse calls.
functionNoEval()functionsNo eval() calls in functions.
functionNoFunctionConstructor()functionsNo new Function() in functions.
functionNoProcessEnv()functionsNo process.env access in functions.
functionNoConsoleLog()functionsNo console.log in functions.
functionNoConsole()functionsNo console access in functions.
functionNoJsonParse()functionsNo JSON.parse in functions.
moduleNoEval()modulesNo eval() anywhere in module.
moduleNoProcessEnv()modulesNo process.env anywhere in module.
moduleNoConsoleLog()modulesNo console.log anywhere in module.

ts-archunit/rules/errors

ExportTargetDescription
noGenericErrors()classesNo new Error() -- use typed domain errors.
noTypeErrors()classesNo new TypeError().
functionNoGenericErrors()functionsNo new Error() in functions.
functionNoTypeErrors()functionsNo new TypeError() in functions.
noSilentCatch()classesCatch blocks must reference the caught error.
functionNoSilentCatch()functionsCatch blocks must reference the caught error.
moduleNoSilentCatch()modulesCatch blocks must reference the caught error.

ts-archunit/rules/naming

ExportDescription
mustMatchName(re: RegExp)Class name must match regex.
mustNotEndWith(suffix: string)Class name must not end with suffix.

ts-archunit/rules/dependencies

ExportDescription
onlyDependOn(...globs)Module may only import from listed paths.
mustNotDependOn(...globs)Module must not import from listed paths.
typeOnlyFrom(...globs)Imports from listed paths must use import type.

ts-archunit/rules/architecture

ExportTargetDescription
mustCall(pattern)functionsFunction body must contain a call matching the regex.
classMustCall(pattern)classesAt least one class method must contain a matching call.

ts-archunit/rules/hygiene

ExportTargetDescription
noDeadModules()modulesModule must be imported by at least one other file.
noUnusedExports()modulesEvery named export must be referenced by another file.
noStubComments(pattern?)functionsNo TODO/FIXME/HACK/STUB comments in a function's body or its own docstring. Markers are case-sensitive and must begin a comment line.
noEmptyBodies()functionsFunctions must have at least one statement.

ts-archunit/rules/metrics

ExportDescription
maxCyclomaticComplexity(n)No method/constructor/getter/setter exceeds complexity n.
maxClassLines(n)Class spans no more than n lines.
maxMethodLines(n)No method/constructor/getter/setter exceeds n lines.
maxMethods(n)Class has no more than n methods.
maxParameters(n)No method/constructor has more than n parameters.
maxFunctionComplexity(n)Function complexity does not exceed n.
maxFunctionLines(n)Function spans no more than n lines.
maxFunctionParameters(n)Function has no more than n parameters.

Released under the MIT License.