or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

cli-tools.mdconfiguration-management.mdcore-analysis.mdindex.mdoutput-formatting.mdreporter-plugins.mdrule-system.mdtranspiler-support.md
tile.json

rule-system.mddocs/

Rule System

Comprehensive rule system for validating dependencies against architectural constraints, circular dependencies, and custom business rules.

Capabilities

Rule Set Structure

Define validation rules that enforce architectural constraints and best practices.

interface IFlattenedRuleSet {
  /** Rules that forbid certain dependency patterns */
  forbidden?: IRegularForbiddenRuleType[];
  
  /** Rules that allow only certain dependency patterns */
  allowed?: IRegularAllowedRuleType[];
  
  /** Rules that require certain dependency patterns to exist */
  required?: IRegularRequiredRuleType[];
  
  /** Default severity level for allowed rule violations */
  allowedSeverity?: SeverityType;
  
  /** Global options for rule processing */
  options?: IRuleSetOptions;
}

type SeverityType = "error" | "warn" | "info" | "ignore";

Usage Examples:

import { cruise } from "dependency-cruiser";

const ruleSet = {
  forbidden: [
    {
      name: "no-circular",
      comment: "Circular dependencies create maintenance problems",
      severity: "error",
      from: {},
      to: { circular: true }
    },
    {
      name: "no-orphans", 
      comment: "Orphaned modules may indicate dead code",
      severity: "warn",
      from: { orphan: true },
      to: {}
    }
  ],
  allowed: [
    {
      name: "only-src-imports",
      comment: "Source code should only import from src or node_modules",
      from: { path: "^src/" },
      to: { path: "^(src/|node_modules/)" }
    }
  ],
  options: {
    doNotFollow: "node_modules"
  }
};

const result = await cruise(
  ["src"],
  { validate: true, ruleSet }
);

Forbidden Rules

Rules that prevent specific dependency patterns.

interface IRegularForbiddenRuleType extends IBaseRuleType {
  /** Criteria for the source module of a dependency */
  from: IFromRestriction;
  
  /** Criteria for the target module of a dependency */
  to: IToRestriction;
  
  /** Scope to apply rule to - 'module' (default) or 'folder' */
  scope?: RuleScopeType;
}

interface IBaseRuleType {
  /** Short name for the rule (appears in violation reports) */
  name?: string;
  
  /** Severity level for violations */
  severity?: SeverityType;
  
  /** Documentation explaining why the rule exists */
  comment?: string;
}

type RuleScopeType = "module" | "folder";

Forbidden Rule Examples:

// Prevent circular dependencies
{
  name: "no-circular",
  severity: "error", 
  from: {},
  to: { circular: true }
}

// Prevent importing core modules
{
  name: "no-core-modules",
  severity: "warn",
  from: { path: "^src/" },
  to: { dependencyTypes: ["core"] }
}

// Prevent test imports in production code
{
  name: "no-test-imports-in-src",
  severity: "error",
  from: { path: "^src/" },
  to: { path: "test/" }
}

// Prevent deprecated npm packages
{
  name: "no-deprecated",
  severity: "warn",
  from: {},
  to: { 
    dependencyTypes: ["npm"],
    path: "^(left-pad|event-stream)$" 
  }
}

// Prevent unstable folder dependencies
{
  name: "no-unstable-deps",
  severity: "error",
  scope: "folder",
  from: {},
  to: { moreUnstable: true }
}

Allowed Rules

Rules that permit only specific dependency patterns (whitelist approach).

interface IRegularAllowedRuleType extends IBaseRuleType {
  /** Criteria for the source module of a dependency */
  from: IFromRestriction;
  
  /** Criteria for the target module of a dependency */  
  to: IToRestriction;
  
  /** Scope to apply rule to - 'module' (default) or 'folder' */
  scope?: RuleScopeType;
}

Allowed Rule Examples:

// Only allow specific imports from external modules
{
  name: "only-allowed-external",
  severity: "error",
  from: { path: "^src/" },
  to: { 
    path: "^(lodash|react|@types/)",
    dependencyTypes: ["npm"]
  }
}

// Only allow local and npm dependencies
{
  name: "only-local-and-npm",
  severity: "error", 
  from: {},
  to: { dependencyTypes: ["local", "npm"] }
}

// Restrict component imports
{
  name: "components-only-from-index",
  severity: "error",
  from: { path: "^src/(?!components/)" },
  to: { 
    path: "^src/components/",
    pathNot: "^src/components/index"
  }
}

Required Rules

Rules that enforce the existence of specific dependency patterns.

interface IRegularRequiredRuleType extends IBaseRuleType {
  /** Criteria for modules that must have the required dependency */
  from: IFromRestriction;
  
  /** Criteria for the required dependency target */
  to: IRequiredToRestrictionType;
  
  /** Scope to apply rule to - 'module' (default) or 'folder' */
  scope?: RuleScopeType;
}

Required Rule Examples:

// Require test files for all source modules
{
  name: "test-required",
  severity: "warn",
  from: { path: "^src/.*\\.js$" },
  to: { 
    path: "^test/.*\\.test\\.js$",
    pathNot: "node_modules"
  }
}

// Require logging in error handlers
{
  name: "logging-required",
  severity: "error",
  from: { path: "error-handler" },
  to: { path: "logger" }
}

Rule Restrictions

Detailed criteria for matching modules in rules.

interface IFromRestriction {
  /** Path pattern (regular expression) for source modules */
  path?: string;
  
  /** Inverse path pattern - modules NOT matching this pattern */
  pathNot?: string;
  
  /** Whether to match orphaned modules */
  orphan?: boolean;
  
  /** Whether to match reachable modules */
  reachable?: boolean;
  
  /** License pattern for npm modules */
  license?: string;
  
  /** License pattern to exclude */
  licenseNot?: string;
}

interface IToRestriction {
  /** Path pattern (regular expression) for target modules */
  path?: string;
  
  /** Inverse path pattern - modules NOT matching this pattern */
  pathNot?: string;
  
  /** Whether to match circular dependencies */
  circular?: boolean;
  
  /** Whether to match dynamic imports */
  dynamic?: boolean;
  
  /** Whether to match exotic requires */
  exoticallyRequired?: boolean;
  
  /** Whether to match modules that could not be resolved */
  couldNotResolve?: boolean;
  
  /** Whether to match pre-compilation only dependencies */
  preCompilationOnly?: boolean;
  
  /** Whether to match type-only imports */
  typeOnly?: boolean;
  
  /** Whether to match more unstable dependencies (folder scope) */
  moreUnstable?: boolean;
  
  /** Dependency types to match */
  dependencyTypes?: DependencyType[];
  
  /** Dependency types to exclude */
  dependencyTypesNot?: DependencyType[];
  
  /** Module systems to match */
  moduleSystems?: ModuleSystemType[];
  
  /** Module systems to exclude */
  moduleSystemsNot?: ModuleSystemType[];
  
  /** License pattern for npm modules */
  license?: string;
  
  /** License pattern to exclude */
  licenseNot?: string;
  
  /** Whether to match reachable modules */
  reachable?: boolean;
  
  /** Whether to match via reachability pattern */
  via?: IViaRestrictionType[];
  
  /** Whether to match via reachability NOT pattern */
  viaNot?: IViaRestrictionType[];
  
  /** Whether to match via only specified patterns */
  viaOnly?: IViaRestrictionType[];
}

Rule Scope and Application

Rules can be applied at different scopes for architectural analysis.

Module Scope (Default):

{
  name: "no-module-circular",
  scope: "module", // or omit for default
  from: {},
  to: { circular: true }
}

Folder Scope:

{
  name: "no-folder-circular", 
  scope: "folder",
  from: {},
  to: { circular: true }
}

{
  name: "stable-dependencies-principle",
  scope: "folder",
  from: {},
  to: { moreUnstable: true }
}

Advanced Rule Patterns

Complex rule patterns for sophisticated architectural constraints.

Layered Architecture:

{
  forbidden: [
    {
      name: "no-skip-layers",
      comment: "Don't skip layers in the architecture",
      from: { path: "^src/presentation/" },
      to: { path: "^src/data/" } // Skip business layer
    },
    {
      name: "no-reverse-dependencies", 
      comment: "Lower layers shouldn't depend on higher layers",
      from: { path: "^src/data/" },
      to: { path: "^src/(presentation|business)/" }
    }
  ]
}

Domain-Driven Design:

{
  forbidden: [
    {
      name: "no-cross-domain-deps",
      comment: "Domains should not directly depend on each other",
      from: { path: "^src/domains/user/" },
      to: { path: "^src/domains/order/" }
    }
  ],
  allowed: [
    {
      name: "domains-via-shared-only",
      comment: "Cross-domain communication via shared interfaces only",
      from: { path: "^src/domains/" },
      to: { path: "^src/(shared/|domains/[^/]+/)" }
    }
  ]
}

Reachability Rules:

{
  forbidden: [
    {
      name: "no-unreachable-from-index",
      comment: "All modules should be reachable from entry points",
      from: { 
        path: "^src/",
        reachable: false
      },
      to: {}
    }
  ]
}

Rule Violation Handling

Understanding how violations are reported and handled.

interface IViolation {
  /** Type of violation */
  type: ViolationType;
  
  /** Source module involved in violation */
  from: string;
  
  /** Target module involved in violation */
  to: string;
  
  /** Rule that was violated */
  rule: IRuleSummary;
  
  /** Path through dependency graph (for cycles) */
  cycle?: IMiniDependency[];
  
  /** Via path for reachability violations */
  via?: IMiniDependency[];
}

interface IRuleSummary {
  /** Rule name */
  name: string;
  
  /** Rule severity */
  severity: SeverityType;
  
  /** Comment explaining the rule */
  comment?: string;
}

type ViolationType = "dependency" | "module" | "cycle" | "reachability" | "instability";

Processing Violations:

import { cruise } from "dependency-cruiser";

const result = await cruise(["src"], { 
  validate: true, 
  ruleSet: myRuleSet 
});

// Check for violations
if (result.exitCode !== 0) {
  console.log(`Found ${result.output.summary.error} errors`);
  console.log(`Found ${result.output.summary.warn} warnings`);
  
  // Process each violation
  result.output.summary.violations.forEach(violation => {
    console.log(`${violation.rule.severity}: ${violation.rule.name}`);
    console.log(`  ${violation.from} -> ${violation.to}`);
    if (violation.rule.comment) {
      console.log(`  ${violation.rule.comment}`);
    }
  });
}

Performance Optimization

Optimize rule processing for large codebases.

const optimizedOptions = {
  validate: true,
  ruleSet: myRuleSet,
  
  // Skip analyses not needed by any rules
  skipAnalysisNotInRules: true,
  
  // Use caching for repeated analyses
  cache: {
    folder: "node_modules/.cache/dependency-cruiser",
    strategy: "metadata"
  },
  
  // Exclude irrelevant paths early
  doNotFollow: "node_modules",
  exclude: ["test/fixtures", "docs"]
};

Rule Testing and Validation

Test rules before applying them to ensure they work as intended.

// Test rule on small subset first
const testResult = await cruise(
  ["src/core"], // Small subset
  { 
    validate: true, 
    ruleSet: {
      forbidden: [newRule] // Test single rule
    }
  }
);

// Validate rule catches expected violations
if (testResult.output.summary.violations.length === 0) {
  console.log("Rule may be too permissive");
} else {
  console.log("Rule found violations as expected");
}