diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index f81e575..c7cb6eb 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -13,7 +13,7 @@ A clear description of the bug. ## Steps to Reproduce 1. Create config with... -2. Run `archgate check` +2. Run `layerguard check` 3. See error ## Expected Behavior @@ -26,7 +26,7 @@ What actually happened. ## Environment -- Archgate version: +- Layerguard version: - Node.js version: - TypeScript version: - OS: @@ -34,7 +34,7 @@ What actually happened. ## Config File ```typescript -// archgate.config.ts (redacted if needed) +// layerguard.config.ts (redacted if needed) ``` ## Additional Context diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78e0ed9..810e34d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,12 +35,12 @@ jobs: - name: Lint run: pnpm lint - - name: Run tests - run: pnpm test - - name: Build run: pnpm build + - name: Run tests + run: pnpm test + - name: Self-hosting test run: pnpm test:self @@ -63,6 +63,9 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Build + run: pnpm build + - name: Run tests with coverage run: pnpm test:coverage diff --git a/.gitignore b/.gitignore index b4c74fa..6aa138c 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,8 @@ dist/ *.swp *.swo -# Archgate cache -.archgate-cache/ +# Layerguard cache +.layerguard-cache/ # OS files .DS_Store @@ -30,7 +30,7 @@ npm-debug.log* .cache/ coverage/ -archgate-report.html +layerguard-report.html # VS Code extension build artifacts *.vsix diff --git a/AGENTS.md b/AGENTS.md index cea612b..c4de9d8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,10 +1,10 @@ -# Archgate Development Guide for Agentic Coding Agents +# Layerguard Development Guide for Agentic Coding Agents -This guide provides essential information for agentic coding agents working with the Archgate codebase. +This guide provides essential information for agentic coding agents working with the Layerguard codebase. ## Project Overview -Archgate is a framework-agnostic CLI tool that enforces architectural layer boundaries in TypeScript/JavaScript projects. It helps maintain clean architecture by preventing inappropriate dependencies between layers. +Layerguard is a framework-agnostic CLI tool that enforces architectural layer boundaries in TypeScript/JavaScript projects. It helps maintain clean architecture by preventing inappropriate dependencies between layers. ## Build Commands @@ -41,7 +41,7 @@ pnpm test:watch # Run tests with coverage report pnpm test:coverage -# Run self-check (archgate checking itself) +# Run self-check (layerguard checking itself) pnpm test:self # Run a single test file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5af0c9c..66ba1d6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,13 +1,13 @@ -# Contributing to Archgate +# Contributing to Layerguard -Thank you for your interest in contributing to Archgate! This document provides guidelines and information for contributors. +Thank you for your interest in contributing to Layerguard! This document provides guidelines and information for contributors. ## Development Setup 1. **Clone the repository** ```bash - git clone https://github.com/yourusername/archgate.git - cd archgate + git clone https://github.com/yourusername/layerguard.git + cd layerguard ``` 2. **Install dependencies** @@ -28,7 +28,7 @@ Thank you for your interest in contributing to Archgate! This document provides ## Project Structure ``` -archgate/ +layerguard/ src/ cli/ # CLI commands (check, init, show) config/ # Config loading and validation @@ -40,7 +40,7 @@ archgate/ unit/ # Unit tests integration/ # Integration tests with fixtures bin/ - archgate.js # CLI entry point + layerguard.js # CLI entry point ``` ## Development Scripts @@ -64,7 +64,7 @@ npm run test:coverage # Type check without emitting npm run typecheck -# Run archgate on itself (self-hosting test) +# Run layerguard on itself (self-hosting test) npm run test:self ``` @@ -94,7 +94,7 @@ describe('parseFlowRules', () => { ## Adding a Framework Plugin -Framework plugins help Archgate understand framework-specific conventions. To add a new plugin: +Framework plugins help Layerguard understand framework-specific conventions. To add a new plugin: 1. **Create the plugin file** in `src/plugins/`: @@ -195,7 +195,7 @@ test: add edge case tests for sublayer flow When reporting issues, please include: -1. **Archgate version** (`npx archgate --version`) +1. **Layerguard version** (`npx layerguard --version`) 2. **Node.js version** (`node --version`) 3. **TypeScript version** (`npx tsc --version`) 4. **Your config file** (redacted if needed) diff --git a/LICENSE b/LICENSE index 712df3c..65d5531 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Archgate Contributors +Copyright (c) 2024 Layerguard Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 4ac3646..f6d6e30 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@

- npm version - build status - license - node version + npm version + build status + license + node version

-# Archgate +# Layerguard Architectural layer enforcement for TypeScript and JavaScript projects. -Archgate prevents architectural violations before they happen. Define your layers, declare how dependencies can flow between them, and Archgate enforces those rules in CI, pre-commit hooks, or your editor. +Layerguard prevents architectural violations before they happen. Define your layers, declare how dependencies can flow between them, and Layerguard enforces those rules in CI, pre-commit hooks, or your editor. -## Why Archgate? +## Why Layerguard? - **Catch violations early** - Get instant feedback when code violates your architecture - **Framework-agnostic** - Works with Next.js, Vite, Angular, Node backends, and more @@ -48,14 +48,14 @@ Archgate prevents architectural violations before they happen. Define your layer ## Installation ```bash -npm install --save-dev archgate +npm install --save-dev layerguard ``` Or with your preferred package manager: ```bash -pnpm add -D archgate -yarn add -D archgate +pnpm add -D layerguard +yarn add -D layerguard ``` **Requirements:** Node.js 18.0.0 or higher, TypeScript 4.7.0 or higher @@ -65,21 +65,21 @@ yarn add -D archgate Run the interactive setup wizard: ```bash -npx archgate init +npx layerguard init ``` -The wizard detects your project structure, suggests layers, and generates `archgate.config.ts`. +The wizard detects your project structure, suggests layers, and generates `layerguard.config.ts`. Then validate your architecture: ```bash -npx archgate check +npx layerguard check ``` If code violates the rules: ``` -archgate check +layerguard check ✗ 1 violation @@ -91,10 +91,10 @@ archgate check ## Configuration -Create `archgate.config.ts` in your project root: +Create `layerguard.config.ts` in your project root: ```typescript -import { defineConfig } from 'archgate' +import { defineConfig } from 'layerguard' export default defineConfig({ layers: { @@ -273,7 +273,7 @@ tsconfig: ['tsconfig.app.json', 'tsconfig.server.json'], Validate architecture rules: ```bash -archgate check [options] +layerguard check [options] ``` | Option | Description | @@ -292,12 +292,12 @@ archgate check [options] **Examples:** ```bash -archgate check # Standard check -archgate check --ci # GitHub Actions annotations -archgate check --json # JSON output for tooling -archgate check --watch # Watch mode -archgate check --package apps/web # Check specific package -archgate check --all # Check all packages in monorepo +layerguard check # Standard check +layerguard check --ci # GitHub Actions annotations +layerguard check --json # JSON output for tooling +layerguard check --watch # Watch mode +layerguard check --package apps/web # Check specific package +layerguard check --all # Check all packages in monorepo ``` ### show @@ -305,7 +305,7 @@ archgate check --all # Check all packages in monorepo Display architecture diagram: ```bash -archgate show [options] +layerguard show [options] ``` | Option | Description | @@ -318,7 +318,7 @@ archgate show [options] Interactive setup wizard: ```bash -archgate init [options] +layerguard init [options] ``` | Option | Description | @@ -330,12 +330,12 @@ archgate init [options] Generate HTML or Markdown report: ```bash -archgate report [options] +layerguard report [options] ``` | Option | Description | |--------|-------------| -| `--output`, `-o` | Output file path (default: `archgate-report.html`) | +| `--output`, `-o` | Output file path (default: `layerguard-report.html`) | | `--markdown`, `--md` | Output as Markdown instead of HTML | | `--stdout` | Print to stdout instead of file | | `--from` | Load historical data from JSON for trend charts | @@ -344,48 +344,48 @@ archgate report [options] **Examples:** ```bash -archgate report # Generate HTML report -archgate report --markdown # Markdown summary -archgate report -o reports/arch.html # Custom output path -archgate report --from history.json # Include trend data +layerguard report # Generate HTML report +layerguard report --markdown # Markdown summary +layerguard report -o reports/arch.html # Custom output path +layerguard report --from history.json # Include trend data ``` ## Monorepo Support -Archgate detects pnpm, npm, and Yarn workspaces automatically. +Layerguard detects pnpm, npm, and Yarn workspaces automatically. ### Per-package Configuration -Each package can have its own `archgate.config.ts`: +Each package can have its own `layerguard.config.ts`: ``` my-monorepo/ ├── package.json # workspaces: ["packages/*", "apps/*"] ├── packages/ │ └── shared/ -│ └── archgate.config.ts +│ └── layerguard.config.ts └── apps/ └── web/ - └── archgate.config.ts + └── layerguard.config.ts ``` ### Check Specific Package ```bash # By name -archgate check --package @myorg/web +layerguard check --package @myorg/web # By path -archgate check --package apps/web +layerguard check --package apps/web ``` ### Check All Packages ```bash -archgate check --all +layerguard check --all ``` -This finds all packages with `archgate.config.ts` and checks them in sequence. +This finds all packages with `layerguard.config.ts` and checks them in sequence. ### Cross-package Imports @@ -423,7 +423,7 @@ export default defineConfig({ Framework detection enables: - Entry point recognition (excluded from orphan detection) - Framework-specific file patterns -- Better layer suggestions in `archgate init` +- Better layer suggestions in `layerguard init` ## ESLint Integration @@ -431,15 +431,15 @@ Get inline editor feedback with the ESLint plugin: ```javascript // eslint.config.js -import archgate from 'archgate/eslint' +import layerguard from 'layerguard/eslint' export default [ - ...archgate.configs.recommended, + ...layerguard.configs.recommended, // your other config... ] ``` -The plugin reads your `archgate.config.ts` and reports violations as you type. +The plugin reads your `layerguard.config.ts` and reports violations as you type. ## GitHub Actions @@ -451,7 +451,7 @@ name: Architecture Check on: [push, pull_request] jobs: - archgate: + layerguard: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -459,7 +459,7 @@ jobs: with: node-version: '20' - run: npm ci - - run: npx archgate check --ci + - run: npx layerguard check --ci ``` The `--ci` flag outputs GitHub Actions annotations, showing violations inline in the PR diff. @@ -469,7 +469,7 @@ The `--ci` flag outputs GitHub Actions annotations, showing violations inline in Post a summary comment on pull requests: ```yaml -- run: npx archgate check --github-pr-comment +- run: npx layerguard check --github-pr-comment env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` @@ -478,7 +478,7 @@ This requires the `gh` CLI (pre-installed on GitHub-hosted runners). ## VS Code Extension -Install the [Archgate extension](https://marketplace.visualstudio.com/items?itemName=archgate.archgate-vscode) for: +Install the [Layerguard extension](https://marketplace.visualstudio.com/items?itemName=layerguard.layerguard-vscode) for: - Inline diagnostics showing violations as you type - Quick fixes for common issues @@ -486,12 +486,12 @@ Install the [Archgate extension](https://marketplace.visualstudio.com/items?item ## Programmatic API -Use Archgate programmatically in your tools: +Use Layerguard programmatically in your tools: ```typescript -import { loadConfig, validateConfig } from 'archgate/config' -import { buildDependencyGraph } from 'archgate/parser' -import { createFlowChecker } from 'archgate/enforcer' +import { loadConfig, validateConfig } from 'layerguard/config' +import { buildDependencyGraph } from 'layerguard/parser' +import { createFlowChecker } from 'layerguard/enforcer' // Load and validate config const { config } = await loadConfig(process.cwd()) @@ -519,12 +519,12 @@ console.log(`Found ${result.violations.length} violations`) | Export | Description | |--------|-------------| -| `archgate` | Main entry point | -| `archgate/config` | Config loading and validation | -| `archgate/parser` | Dependency graph building | -| `archgate/enforcer` | Violation checking | -| `archgate/plugins` | Framework plugin interfaces | -| `archgate/eslint` | ESLint plugin | +| `layerguard` | Main entry point | +| `layerguard/config` | Config loading and validation | +| `layerguard/parser` | Dependency graph building | +| `layerguard/enforcer` | Violation checking | +| `layerguard/plugins` | Framework plugin interfaces | +| `layerguard/eslint` | ESLint plugin | ## License diff --git a/bin/archgate.js b/bin/layerguard.js similarity index 60% rename from bin/archgate.js rename to bin/layerguard.js index 69cb3eb..a4ca06d 100644 --- a/bin/archgate.js +++ b/bin/layerguard.js @@ -1,6 +1,6 @@ #!/usr/bin/env node import('../dist/cli/index.js').catch((err) => { - console.error('Failed to start archgate:', err.message) + console.error('Failed to start layerguard:', err.message) process.exit(1) }) diff --git a/archgate.config.ts b/layerguard.config.ts similarity index 94% rename from archgate.config.ts rename to layerguard.config.ts index bcf835b..76df026 100644 --- a/archgate.config.ts +++ b/layerguard.config.ts @@ -1,5 +1,5 @@ /** - * Archgate configuration for the archgate project itself (dogfooding) + * Layerguard configuration for the layerguard project itself (dogfooding) */ import { defineConfig } from './src/config/types.js' @@ -70,7 +70,7 @@ export default defineConfig({ // CLI entry point 'bin/**', // Config file itself - 'archgate.config.ts', + 'layerguard.config.ts', // VS Code extension has its own architecture 'vscode-extension/**', ], diff --git a/package.json b/package.json index 2f7cf12..565c281 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { - "name": "archgate", + "name": "layerguard", "version": "0.1.0", "description": "Framework-agnostic CLI tool that enforces architectural layer boundaries in TypeScript/JavaScript projects", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", "bin": { - "archgate": "./bin/archgate.js" + "layerguard": "./bin/layerguard.js" }, "exports": { ".": { @@ -43,11 +43,11 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/caprado/archgate.git" + "url": "git+https://github.com/caprado/layerguard.git" }, - "homepage": "https://github.com/caprado/archgate#readme", + "homepage": "https://github.com/caprado/layerguard#readme", "bugs": { - "url": "https://github.com/caprado/archgate/issues" + "url": "https://github.com/caprado/layerguard/issues" }, "scripts": { "build": "tsc -p tsconfig.build.json", @@ -57,7 +57,7 @@ "test:watch": "vitest", "test:coverage": "vitest run --coverage", "test:integration": "vitest run --config vitest.integration.config.ts", - "test:self": "node bin/archgate.js check", + "test:self": "node bin/layerguard.js check", "lint": "eslint src/", "prepublishOnly": "npm run build" }, diff --git a/src/cache/manager.ts b/src/cache/manager.ts index 3b66a5d..3be9ecf 100644 --- a/src/cache/manager.ts +++ b/src/cache/manager.ts @@ -8,7 +8,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync, rmSync } import { join, dirname } from 'node:path' import { createHash } from 'node:crypto' import type { DependencyGraph } from '../parser/graph.js' -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' import { CACHE_VERSION, CACHE_DIR, @@ -40,7 +40,7 @@ export function getFileMtime(filePath: string): number | null { /** * Create a hash of the config for cache invalidation */ -export function hashConfig(config: ArchgateConfig): string { +export function hashConfig(config: LayerguardConfig): string { const configStr = JSON.stringify(config) return createHash('md5').update(configStr).digest('hex') } @@ -112,7 +112,7 @@ export function validateCache( cache: CacheData, projectRoot: string, currentFiles: string[], - config: ArchgateConfig, + config: LayerguardConfig, tsconfigPath?: string ): CacheValidation { // Check version @@ -188,7 +188,7 @@ export function validateCache( */ export function graphToCache( graph: DependencyGraph, - config: ArchgateConfig, + config: LayerguardConfig, tsconfigPath?: string ): CacheData { const files: Record = {} diff --git a/src/cache/types.ts b/src/cache/types.ts index 1b8c4b8..38df218 100644 --- a/src/cache/types.ts +++ b/src/cache/types.ts @@ -12,7 +12,7 @@ export const CACHE_VERSION = '1.0.0' /** * Default cache directory name */ -export const CACHE_DIR = '.archgate-cache' +export const CACHE_DIR = '.layerguard-cache' /** * Cache file name @@ -64,7 +64,7 @@ export interface CacheData { tsconfigMtime?: number /** - * Hash of the archgate config (to invalidate on config changes) + * Hash of the layerguard config (to invalidate on config changes) */ configHash?: string diff --git a/src/cli/check.ts b/src/cli/check.ts index fce6604..d4c9141 100644 --- a/src/cli/check.ts +++ b/src/cli/check.ts @@ -1,5 +1,5 @@ /** - * archgate check command + * layerguard check command * * Validates the project against architectural rules */ @@ -61,7 +61,7 @@ export interface CheckCommandOptions { package?: string /** - * Check all workspace packages with archgate configs + * Check all workspace packages with layerguard configs */ all?: boolean } @@ -260,7 +260,7 @@ async function runWorkspaceCheck(options: CheckCommandOptions): Promise pc.package.name).join(', ') - console.error(formatError(`Package "${packageFilter}" not found or has no archgate config.\nAvailable packages: ${available}`, { colors: !noColors })) + console.error(formatError(`Package "${packageFilter}" not found or has no layerguard config.\nAvailable packages: ${available}`, { colors: !noColors })) return { passed: false, exitCode: 1, errorCount: 1, warningCount: 0, violations: [] } } packagesToCheck = [found] diff --git a/src/cli/generator.ts b/src/cli/generator.ts index 765aa4e..7848126 100644 --- a/src/cli/generator.ts +++ b/src/cli/generator.ts @@ -1,12 +1,12 @@ /** * Config file generator * - * Generates archgate.config.ts/js files from config objects + * Generates layerguard.config.ts/js files from config objects */ import * as fs from 'node:fs' import * as path from 'node:path' -import type { ArchgateConfig, LayerConfig } from '../config/types.js' +import type { LayerguardConfig, LayerConfig } from '../config/types.js' /** * Options for generating config @@ -27,7 +27,7 @@ export interface GenerateOptions { * Generate config file content */ export function generateConfigContent( - config: ArchgateConfig, + config: LayerguardConfig, options: GenerateOptions = {} ): string { const { typescript = true, includeComments = true } = options @@ -35,11 +35,11 @@ export function generateConfigContent( // Import statement if (typescript) { - lines.push("import { defineConfig } from 'archgate'") + lines.push("import { defineConfig } from 'layerguard'") } else { lines.push( "// @ts-check", - "/** @type {import('archgate').ArchgateConfig} */" + "/** @type {import('layerguard').LayerguardConfig} */" ) } lines.push('') @@ -197,11 +197,11 @@ function formatLayer( */ export function writeConfigFile( projectRoot: string, - config: ArchgateConfig, + config: LayerguardConfig, options: GenerateOptions = {} ): string { const { typescript = true } = options - const filename = typescript ? 'archgate.config.ts' : 'archgate.config.js' + const filename = typescript ? 'layerguard.config.ts' : 'layerguard.config.js' const filepath = path.join(projectRoot, filename) const content = generateConfigContent(config, options) @@ -215,10 +215,10 @@ export function writeConfigFile( */ export function configFileExists(projectRoot: string): string | null { const candidates = [ - 'archgate.config.ts', - 'archgate.config.js', - 'archgate.config.mjs', - 'archgate.config.cjs', + 'layerguard.config.ts', + 'layerguard.config.js', + 'layerguard.config.mjs', + 'layerguard.config.cjs', ] for (const filename of candidates) { diff --git a/src/cli/index.ts b/src/cli/index.ts index a7d0f62..f38addd 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,5 +1,5 @@ /** - * Archgate CLI entry point + * Layerguard CLI entry point */ import { runCheck } from './check.js' @@ -155,17 +155,17 @@ export function parseArgs(args: string[]): ParsedArgs { */ export function printHelp(): void { console.log(` -archgate v${VERSION} +layerguard v${VERSION} Enforce architectural layer boundaries in TypeScript/JavaScript projects. Usage: - archgate [options] + layerguard [options] Commands: check Validate architecture rules, exit 1 on violations show Print the architecture as a text diagram - init Interactive setup to create archgate.config.ts + init Interactive setup to create layerguard.config.ts report Generate HTML report of violations Options: @@ -180,7 +180,7 @@ Check options: --watch, -w Watch mode: re-check on file changes --no-cache Disable incremental caching, force full rescan --package, -p Check a specific workspace package (name or path) - --all Check all workspace packages with archgate configs + --all Check all workspace packages with layerguard configs --github-pr-comment Post results as a PR comment (requires gh CLI) --pr-number PR number for comment (auto-detected in GitHub Actions) @@ -192,26 +192,26 @@ Init options: -y, --yes Skip prompts and use defaults Report options: - --output, -o Output file path (default: archgate-report.html) + --output, -o Output file path (default: layerguard-report.html) --markdown Output as Markdown instead of HTML --stdout Print to stdout instead of file --from Load historical data from JSON file for trends --title Report title Examples: - archgate check Run validation - archgate check --ci Run with GitHub Actions annotations - archgate check --json Output as JSON - archgate check --watch Watch for changes and re-check - archgate check --package apps/web Check a specific package - archgate check --all Check all packages in monorepo - archgate show Display architecture diagram - archgate show --ascii Display with ASCII characters - archgate init Interactive setup wizard - archgate init -y Quick setup with defaults - archgate report Generate HTML report - archgate report --markdown Generate Markdown summary - archgate report -o report.html Save report to custom path + layerguard check Run validation + layerguard check --ci Run with GitHub Actions annotations + layerguard check --json Output as JSON + layerguard check --watch Watch for changes and re-check + layerguard check --package apps/web Check a specific package + layerguard check --all Check all packages in monorepo + layerguard show Display architecture diagram + layerguard show --ascii Display with ASCII characters + layerguard init Interactive setup wizard + layerguard init -y Quick setup with defaults + layerguard report Generate HTML report + layerguard report --markdown Generate Markdown summary + layerguard report -o report.html Save report to custom path `) } @@ -219,7 +219,7 @@ Examples: * Print version */ export function printVersion(): void { - console.log(`archgate v${VERSION}`) + console.log(`layerguard v${VERSION}`) } /** @@ -325,13 +325,13 @@ export async function main(argv: string[] = process.argv.slice(2)): Promise { diff --git a/src/cli/init.ts b/src/cli/init.ts index 76fe846..f720ac7 100644 --- a/src/cli/init.ts +++ b/src/cli/init.ts @@ -1,13 +1,13 @@ /** - * archgate init command + * layerguard init command * - * Interactive setup to create archgate.config.ts + * Interactive setup to create layerguard.config.ts */ import * as p from '@clack/prompts' import * as fs from 'node:fs' import * as path from 'node:path' -import type { ArchgateConfig, LayerConfig, SublayerConfig } from '../config/types.js' +import type { LayerguardConfig, LayerConfig, SublayerConfig } from '../config/types.js' import { detectFramework, scanForLayers, @@ -47,7 +47,7 @@ export async function runInit(options: InitCommandOptions = {}): Promise { // Check if config already exists const existingConfig = configFileExists(cwd) if (existingConfig) { - p.intro('archgate init') + p.intro('layerguard init') p.log.warn(`Config file already exists: ${existingConfig}`) if (!yes) { @@ -64,7 +64,7 @@ export async function runInit(options: InitCommandOptions = {}): Promise { } // Start the interactive flow - p.intro('Welcome to archgate') + p.intro('Welcome to layerguard') // Detect framework const detection = detectFramework(cwd) @@ -113,7 +113,7 @@ export async function runInit(options: InitCommandOptions = {}): Promise { } } - let config: ArchgateConfig + let config: LayerguardConfig if (usePreset && selectedPreset) { // Use preset config @@ -129,7 +129,7 @@ export async function runInit(options: InitCommandOptions = {}): Promise { if (!yes) { // Ask if they want to choose a preset or go custom const presetChoice = await p.select({ - message: 'How would you like to set up archgate?', + message: 'How would you like to set up layerguard?', options: [ { value: 'scan', @@ -230,8 +230,8 @@ export async function runInit(options: InitCommandOptions = {}): Promise { p.outro(`Config written to ${path.basename(filepath)}`) console.log('') - console.log('Run `archgate check` to validate your architecture.') - console.log('Run `archgate show` to visualize the architecture.') + console.log('Run `layerguard check` to validate your architecture.') + console.log('Run `layerguard show` to visualize the architecture.') } /** @@ -240,7 +240,7 @@ export async function runInit(options: InitCommandOptions = {}): Promise { async function runCustomSetup( cwd: string, framework?: DetectedFramework -): Promise { +): Promise { // Scan for directories const directories = scanForLayers(cwd) @@ -425,7 +425,7 @@ async function runCustomSetup( .filter((r) => r) } - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers, flow, } diff --git a/src/cli/presets.ts b/src/cli/presets.ts index 996aa7d..eb3ba44 100644 --- a/src/cli/presets.ts +++ b/src/cli/presets.ts @@ -2,7 +2,7 @@ * Preset templates for common project structures */ -import type { ArchgateConfig, LayerConfig, SublayerConfig } from '../config/types.js' +import type { LayerguardConfig, LayerConfig, SublayerConfig } from '../config/types.js' /** * Preset template @@ -31,7 +31,7 @@ export interface Preset { /** * Optional framework setting */ - framework?: ArchgateConfig['framework'] + framework?: LayerguardConfig['framework'] } /** @@ -272,8 +272,8 @@ export function createCustomConfig( sublayers?: Array<{ name: string; path: string; isolated?: boolean }> }>, flowRules: string[], - framework?: ArchgateConfig['framework'] -): ArchgateConfig { + framework?: LayerguardConfig['framework'] +): LayerguardConfig { const layersConfig: Record = {} for (const layer of layers) { @@ -295,7 +295,7 @@ export function createCustomConfig( layersConfig[layer.name] = config } - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: layersConfig, flow: flowRules, } diff --git a/src/cli/report.ts b/src/cli/report.ts index 10b6186..dc6402d 100644 --- a/src/cli/report.ts +++ b/src/cli/report.ts @@ -1,5 +1,5 @@ /** - * archgate report command + * layerguard report command * * Generates HTML reports from check results or historical data */ @@ -26,7 +26,7 @@ export interface ReportCommandOptions { cwd?: string /** - * Output file path (default: archgate-report.html) + * Output file path (default: layerguard-report.html) */ output?: string @@ -92,12 +92,12 @@ export interface ReportResult { export async function runReport(options: ReportCommandOptions = {}): Promise { const { cwd = process.cwd(), - output = 'archgate-report.html', + output = 'layerguard-report.html', format = 'html', from, typeOnlyImports = false, noColors = false, - title = 'Archgate Report', + title = 'Layerguard Report', stdout = false, } = options @@ -232,7 +232,7 @@ function loadHistoricalData(path: string): HistoricalDataPoint[] { } } } else if (data.history) { - // Support archgate-history.json format + // Support layerguard-history.json format for (const item of data.history) { const point = parseHistoricalItem(item) if (point) { diff --git a/src/cli/show.ts b/src/cli/show.ts index bf3b63f..3fe47e2 100644 --- a/src/cli/show.ts +++ b/src/cli/show.ts @@ -1,5 +1,5 @@ /** - * archgate show command + * layerguard show command * * Displays the architecture diagram */ diff --git a/src/cli/watch.ts b/src/cli/watch.ts index 8c922b0..415a5bd 100644 --- a/src/cli/watch.ts +++ b/src/cli/watch.ts @@ -1,5 +1,5 @@ /** - * Watch mode for archgate + * Watch mode for layerguard * * Watches for file changes and re-runs checks incrementally */ @@ -124,7 +124,7 @@ export async function startWatch(options: WatchOptions = {}): Promise ` - ${p}`).join('\n')}\n\nRun 'archgate init' to create one.` + `No layerguard config file found. Searched for:\n${searchedPaths.map((p) => ` - ${p}`).join('\n')}\n\nRun 'layerguard init' to create one.` ) this.name = 'ConfigNotFoundError' } @@ -60,7 +60,7 @@ export function findConfigFile(cwd: string): string | null { } /** - * Load and parse the archgate config file + * Load and parse the layerguard config file * * @param cwd - The directory to search for the config file (defaults to process.cwd()) * @returns The loaded config and its path @@ -82,7 +82,7 @@ export async function loadConfig(cwd: string = process.cwd()): Promise> /** * Helper function for type-safe config definition */ -export function defineConfig(config: ArchgateConfig): ArchgateConfig { +export function defineConfig(config: LayerguardConfig): LayerguardConfig { return config } diff --git a/src/config/validator.ts b/src/config/validator.ts index 2b2e96f..b8d3b66 100644 --- a/src/config/validator.ts +++ b/src/config/validator.ts @@ -1,12 +1,12 @@ /** * Config validator * - * Validates the archgate config structure and ensures all references are valid. + * Validates the layerguard config structure and ensures all references are valid. */ import { existsSync } from 'node:fs' import { resolve } from 'node:path' -import type { ArchgateConfig, LayerConfig, SublayerConfig } from './types.js' +import type { LayerguardConfig, LayerConfig, SublayerConfig } from './types.js' import { parseFlowRules, buildFlowGraph, findIsolatedLayers, type FlowParseError } from './parser.js' import type { FlowGraph, ParsedFlowRule } from './types.js' @@ -26,13 +26,13 @@ export interface ValidationResult { } /** - * Validate the archgate config + * Validate the layerguard config * * @param config - The config to validate * @param cwd - The project root directory for path validation * @returns Validation result with errors, warnings, and parsed flow graph */ -export function validateConfig(config: ArchgateConfig, cwd: string): ValidationResult { +export function validateConfig(config: LayerguardConfig, cwd: string): ValidationResult { const errors: ValidationError[] = [] const warnings: ValidationError[] = [] let flowGraph: FlowGraph | null = null @@ -352,7 +352,7 @@ function validateSublayerFlow( /** * Validate rules configuration */ -function validateRulesConfig(rules: NonNullable): ValidationError[] { +function validateRulesConfig(rules: NonNullable): ValidationError[] { const errors: ValidationError[] = [] if (rules.circular !== undefined) { diff --git a/src/enforcer/advanced-rules.ts b/src/enforcer/advanced-rules.ts index 317ab5c..6119901 100644 --- a/src/enforcer/advanced-rules.ts +++ b/src/enforcer/advanced-rules.ts @@ -8,7 +8,7 @@ * - maxImportsPerFile: Import count limits */ -import type { ArchgateConfig, LayerConfig } from '../config/types.js' +import type { LayerguardConfig, LayerConfig } from '../config/types.js' import type { DependencyGraph } from '../parser/graph.js' import type { LayerMapper } from './mapper.js' import { @@ -126,7 +126,7 @@ function findLongestChain( */ export function checkPublicApi( graph: DependencyGraph, - config: ArchgateConfig, + config: LayerguardConfig, mapper: LayerMapper ): PublicApiViolation[] { const violations: PublicApiViolation[] = [] @@ -221,7 +221,7 @@ function normalizePathForComparison(path: string): string { */ export function checkDependentBudget( graph: DependencyGraph, - config: ArchgateConfig, + config: LayerguardConfig, mapper: LayerMapper ): DependentBudgetViolation[] { const violations: DependentBudgetViolation[] = [] @@ -306,7 +306,7 @@ export function checkImportCount( */ export function checkAdvancedRules( graph: DependencyGraph, - config: ArchgateConfig, + config: LayerguardConfig, mapper: LayerMapper, options: AdvancedRulesOptions = {} ): Violation[] { diff --git a/src/enforcer/checker.ts b/src/enforcer/checker.ts index dae1e6e..b067bcf 100644 --- a/src/enforcer/checker.ts +++ b/src/enforcer/checker.ts @@ -5,7 +5,7 @@ */ import { join } from 'node:path' -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' import type { FlowGraph } from '../config/types.js' import { parseFlowRules, buildFlowGraph, canImport } from '../config/parser.js' import type { DependencyGraph, DependencyEdge } from '../parser/graph.js' @@ -130,13 +130,13 @@ export interface EdgeCheckResult { * Flow checker instance */ export class FlowChecker { - private config: ArchgateConfig + private config: LayerguardConfig private mapper: LayerMapper private topLevelFlowGraph: FlowGraph private sublayerFlowGraphs: Map = new Map() private plugin: FrameworkPlugin | undefined - constructor(config: ArchgateConfig) { + constructor(config: LayerguardConfig) { this.config = config this.mapper = new LayerMapper(config) @@ -502,7 +502,7 @@ export class FlowChecker { /** * Create a flow checker from config */ -export function createFlowChecker(config: ArchgateConfig): FlowChecker { +export function createFlowChecker(config: LayerguardConfig): FlowChecker { return new FlowChecker(config) } @@ -511,7 +511,7 @@ export function createFlowChecker(config: ArchgateConfig): FlowChecker { */ export function checkDependencyGraph( graph: DependencyGraph, - config: ArchgateConfig, + config: LayerguardConfig, options: CheckOptions = {} ): Violation[] { const checker = createFlowChecker(config) diff --git a/src/enforcer/mapper.ts b/src/enforcer/mapper.ts index 251b8db..4c9e842 100644 --- a/src/enforcer/mapper.ts +++ b/src/enforcer/mapper.ts @@ -4,7 +4,7 @@ * Maps file paths to their corresponding layers and sublayers */ -import type { ArchgateConfig, LayerConfig, SublayerConfig } from '../config/types.js' +import type { LayerguardConfig, LayerConfig, SublayerConfig } from '../config/types.js' /** * Result of mapping a file to a layer @@ -69,14 +69,14 @@ interface ProcessedSublayer { export class LayerMapper { private layers: ProcessedLayer[] = [] - constructor(config: ArchgateConfig) { + constructor(config: LayerguardConfig) { this.processConfig(config) } /** * Process the config into an efficient structure for matching */ - private processConfig(config: ArchgateConfig): void { + private processConfig(config: LayerguardConfig): void { for (const [layerName, layerConfig] of Object.entries(config.layers)) { const processedLayer: ProcessedLayer = { name: layerName, @@ -249,6 +249,6 @@ export class LayerMapper { /** * Create a layer mapper from config */ -export function createLayerMapper(config: ArchgateConfig): LayerMapper { +export function createLayerMapper(config: LayerguardConfig): LayerMapper { return new LayerMapper(config) } diff --git a/src/eslint/config-cache.ts b/src/eslint/config-cache.ts index 658a6f1..1845a44 100644 --- a/src/eslint/config-cache.ts +++ b/src/eslint/config-cache.ts @@ -1,7 +1,7 @@ /** * Configuration cache for ESLint plugin * - * ESLint processes files individually, so we cache the archgate config + * ESLint processes files individually, so we cache the layerguard config * to avoid reloading it for every file. */ @@ -22,7 +22,7 @@ const configCache = new Map() const CACHE_TTL = 5 * 60 * 1000 /** - * Get or load the archgate configuration for a file + * Get or load the layerguard configuration for a file * * @param filePath - The file being linted * @returns The cached configuration or null if not found/invalid @@ -85,7 +85,7 @@ export function getConfig(filePath: string): CachedConfig | null { /** * Find the project root for a file * - * Looks for package.json or archgate config file + * Looks for package.json or layerguard config file */ function findProjectRoot(filePath: string): string | null { let dir = dirname(filePath) @@ -105,7 +105,7 @@ function findProjectRoot(filePath: string): string | null { while (!isRoot(dir)) { // console.log('Checking directory:', dir) - // Check for archgate config + // Check for layerguard config try { const result = loadConfigSync(dir) // console.log('loadConfigSync result for', dir, ':', result) @@ -113,8 +113,7 @@ function findProjectRoot(filePath: string): string | null { // console.log('Found config at:', dir) return dir } - } catch (error) { - // console.log('loadConfigSync error for', dir, ':', error) + } catch { // No config in this directory } diff --git a/src/eslint/index.ts b/src/eslint/index.ts index 9c95998..69968c5 100644 --- a/src/eslint/index.ts +++ b/src/eslint/index.ts @@ -1,22 +1,22 @@ /** - * Archgate ESLint Plugin + * Layerguard ESLint Plugin * * Provides ESLint rules for enforcing architectural boundaries defined - * in archgate configuration. + * in layerguard configuration. * * Usage in eslint.config.js: * * ```js - * import archgate from 'archgate/eslint' + * import layerguard from 'layerguard/eslint' * * export default [ * { * plugins: { - * archgate, + * layerguard, * }, * rules: { - * 'archgate/layer-boundaries': 'error', - * 'archgate/unlayered-imports': 'warn', + * 'layerguard/layer-boundaries': 'error', + * 'layerguard/unlayered-imports': 'warn', * }, * }, * ] @@ -28,11 +28,11 @@ import layerBoundaries from './rules/layer-boundaries.js' import unlayeredImports from './rules/unlayered-imports.js' /** - * Archgate ESLint plugin + * Layerguard ESLint plugin */ const plugin: ESLint.Plugin = { meta: { - name: 'archgate', + name: 'layerguard', version: '0.1.0', }, @@ -49,15 +49,15 @@ const plugin: ESLint.Plugin = { * * Usage: * ```js - * import archgate from 'archgate/eslint' - * export default [archgate.configs.recommended] + * import layerguard from 'layerguard/eslint' + * export default [layerguard.configs.recommended] * ``` */ get recommended(): Linter.Config { return { - plugins: { archgate: plugin }, + plugins: { layerguard: plugin }, rules: { - 'archgate/layer-boundaries': 'error', + 'layerguard/layer-boundaries': 'error', }, } }, @@ -69,16 +69,16 @@ const plugin: ESLint.Plugin = { * * Usage: * ```js - * import archgate from 'archgate/eslint' - * export default [archgate.configs.strict] + * import layerguard from 'layerguard/eslint' + * export default [layerguard.configs.strict] * ``` */ get strict(): Linter.Config { return { - plugins: { archgate: plugin }, + plugins: { layerguard: plugin }, rules: { - 'archgate/layer-boundaries': 'error', - 'archgate/unlayered-imports': 'error', + 'layerguard/layer-boundaries': 'error', + 'layerguard/unlayered-imports': 'error', }, } }, @@ -90,4 +90,4 @@ export default plugin // Named exports for convenience export { layerBoundaries, unlayeredImports } export { clearConfigCache, getCacheStats } from './config-cache.js' -export type { CachedConfig, ArchgateRuleOptions } from './types.js' +export type { CachedConfig, LayerguardRuleOptions } from './types.js' diff --git a/src/eslint/rules/layer-boundaries.ts b/src/eslint/rules/layer-boundaries.ts index 120ba8d..2e5b60d 100644 --- a/src/eslint/rules/layer-boundaries.ts +++ b/src/eslint/rules/layer-boundaries.ts @@ -1,7 +1,7 @@ /** - * ESLint rule: archgate/layer-boundaries + * ESLint rule: layerguard/layer-boundaries * - * Flags imports that violate flow rules defined in archgate config. + * Flags imports that violate flow rules defined in layerguard config. */ import type { Rule } from 'eslint' @@ -18,13 +18,13 @@ const rule: Rule.RuleModule = { meta: { type: 'problem', docs: { - description: 'Enforce architectural layer boundaries defined in archgate config', + description: 'Enforce architectural layer boundaries defined in layerguard config', recommended: true, }, messages: { violation: 'Import from "{{importPath}}" violates layer boundaries: {{fromLayer}} cannot import from {{toLayer}}', - noConfig: 'No archgate configuration found', + noConfig: 'No layerguard configuration found', }, schema: [ { @@ -32,7 +32,7 @@ const rule: Rule.RuleModule = { properties: { configPath: { type: 'string', - description: 'Path to archgate config file', + description: 'Path to layerguard config file', }, }, additionalProperties: false, diff --git a/src/eslint/rules/unlayered-imports.ts b/src/eslint/rules/unlayered-imports.ts index 0bef8cd..30dc7fc 100644 --- a/src/eslint/rules/unlayered-imports.ts +++ b/src/eslint/rules/unlayered-imports.ts @@ -1,8 +1,8 @@ /** - * ESLint rule: archgate/unlayered-imports + * ESLint rule: layerguard/unlayered-imports * * Flags imports from layered files to unlayered files when the - * unlayeredImports rule is set to 'error' or 'warn' in archgate config. + * unlayeredImports rule is set to 'error' or 'warn' in layerguard config. */ import type { Rule } from 'eslint' @@ -31,7 +31,7 @@ const rule: Rule.RuleModule = { properties: { configPath: { type: 'string', - description: 'Path to archgate config file', + description: 'Path to layerguard config file', }, }, additionalProperties: false, diff --git a/src/eslint/types.ts b/src/eslint/types.ts index 29db933..518065d 100644 --- a/src/eslint/types.ts +++ b/src/eslint/types.ts @@ -3,16 +3,16 @@ */ import type { Rule } from 'eslint' -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' /** - * Cached archgate configuration for ESLint + * Cached layerguard configuration for ESLint */ export interface CachedConfig { /** - * The loaded archgate configuration + * The loaded layerguard configuration */ - config: ArchgateConfig + config: LayerguardConfig /** * Path to the config file @@ -31,21 +31,21 @@ export interface CachedConfig { } /** - * ESLint rule context with archgate extensions + * ESLint rule context with layerguard extensions */ -export interface ArchgateRuleContext extends Rule.RuleContext { +export interface LayerguardRuleContext extends Rule.RuleContext { /** - * Get the archgate configuration + * Get the layerguard configuration */ - getArchgateConfig?: () => CachedConfig | null + getLayerguardConfig?: () => CachedConfig | null } /** - * Rule options for archgate ESLint rules + * Rule options for layerguard ESLint rules */ -export interface ArchgateRuleOptions { +export interface LayerguardRuleOptions { /** - * Path to archgate config file (optional, auto-detected if not specified) + * Path to layerguard config file (optional, auto-detected if not specified) */ configPath?: string } diff --git a/src/index.ts b/src/index.ts index dd187a3..2901967 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ /** - * Archgate - Framework-agnostic architectural layer enforcement + * Layerguard - Framework-agnostic architectural layer enforcement * * Public API for programmatic use */ @@ -7,7 +7,7 @@ // Config types and helpers export { defineConfig, - type ArchgateConfig, + type LayerguardConfig, type LayerConfig, type SublayerConfig, type RulesConfig, diff --git a/src/output/diagram.ts b/src/output/diagram.ts index 990ae53..25fceb9 100644 --- a/src/output/diagram.ts +++ b/src/output/diagram.ts @@ -4,7 +4,7 @@ * Creates text-based diagrams of the architecture */ -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' import { parseFlowRules } from '../config/parser.js' /** @@ -63,13 +63,13 @@ const boxChars = { /** * Generate an architecture diagram from config */ -export function generateDiagram(config: ArchgateConfig, options: DiagramOptions = {}): string { +export function generateDiagram(config: LayerguardConfig, options: DiagramOptions = {}): string { const { unicode = true, showSublayers = true, showFlow = true } = options const chars = unicode ? boxChars.unicode : boxChars.ascii const lines: string[] = [] // Title - lines.push('Archgate Architecture') + lines.push('Layerguard Architecture') lines.push('') // Parse flow rules to understand relationships @@ -109,7 +109,7 @@ export function generateDiagram(config: ArchgateConfig, options: DiagramOptions * Build a simple layer order based on flow rules */ function buildLayerOrder( - config: ArchgateConfig, + config: LayerguardConfig, parsedRules: Array<{ from: string; to: string; direction: string }> ): string[] { const layers = Object.keys(config.layers) @@ -204,7 +204,7 @@ function padRight(str: string, width: number): string { /** * Generate a simple flow summary */ -export function generateFlowSummary(config: ArchgateConfig): string { +export function generateFlowSummary(config: LayerguardConfig): string { const lines: string[] = [] lines.push('Layer dependencies:') diff --git a/src/output/github.ts b/src/output/github.ts index d854b40..53c1d8d 100644 --- a/src/output/github.ts +++ b/src/output/github.ts @@ -110,7 +110,7 @@ export function generatePrCommentBody(report: ViolationReport, options: { const { showDetails = true, commitSha, workflowName } = options const status = report.passed ? '✅ Passed' : '❌ Failed' - let md = `## Archgate Architecture Check ${status}\n\n` + let md = `## Layerguard Architecture Check ${status}\n\n` // Summary table md += `| Metric | Count |\n` @@ -165,19 +165,19 @@ export function generatePrCommentBody(report: ViolationReport, options: { if (workflowName) { md += `Workflow: ${workflowName}\n` } - md += `\n*Generated by [Archgate](https://github.com/caprado/archgate)*` + md += `\n*Generated by [Layerguard](https://github.com/caprado/layerguard)*` return md } /** - * Find existing Archgate comment on a PR + * Find existing Layerguard comment on a PR */ function findExistingComment(prNumber: number, repo?: string): string | undefined { try { const repoArg = repo ? `--repo ${repo}` : '' const result = execSync( - `gh pr view ${prNumber} ${repoArg} --json comments --jq '.comments[] | select(.body | contains("Archgate Architecture Check")) | .id' | head -1`, + `gh pr view ${prNumber} ${repoArg} --json comments --jq '.comments[] | select(.body | contains("Layerguard Architecture Check")) | .id' | head -1`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] } ) const commentId = result.trim() diff --git a/src/output/html.ts b/src/output/html.ts index 5a90fd1..a0324bd 100644 --- a/src/output/html.ts +++ b/src/output/html.ts @@ -6,7 +6,7 @@ */ import type { ViolationReport, Violation } from '../enforcer/violations.js' -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' /** * Historical data point for trend analysis @@ -68,9 +68,9 @@ export interface HtmlReportOptions { history?: HistoricalDataPoint[] /** - * Archgate configuration (for layer info) + * Layerguard configuration (for layer info) */ - config?: ArchgateConfig + config?: LayerguardConfig /** * File and import counts @@ -86,7 +86,7 @@ export interface HtmlReportOptions { */ export function generateHtmlReport(report: ViolationReport, options: HtmlReportOptions = {}): string { const { - title = 'Archgate Report', + title = 'Layerguard Report', projectName = 'Project', history = [], stats, @@ -527,7 +527,7 @@ export function generateHtmlReport(report: ViolationReport, options: HtmlReportO ` : ''} @@ -656,7 +656,7 @@ export function generateMarkdownSummary(report: ViolationReport, options: { show const status = report.passed ? '✅ **Passed**' : '❌ **Failed**' - let md = `## Archgate Check ${status}\n\n` + let md = `## Layerguard Check ${status}\n\n` md += `| Metric | Count |\n` md += `|--------|-------|\n` @@ -687,7 +687,7 @@ export function generateMarkdownSummary(report: ViolationReport, options: { show } } - md += `\n---\n*Generated by [Archgate](https://github.com/caprado/archgate)*` + md += `\n---\n*Generated by [Layerguard](https://github.com/caprado/layerguard)*` return md } diff --git a/src/output/terminal.ts b/src/output/terminal.ts index d1a5c1b..25b5a92 100644 --- a/src/output/terminal.ts +++ b/src/output/terminal.ts @@ -116,7 +116,7 @@ export function formatReport(report: ViolationReport, options: TerminalOptions = // Header lines.push('') - lines.push(color('archgate check', colors.bold, useColors)) + lines.push(color('layerguard check', colors.bold, useColors)) lines.push('') if (report.violations.length === 0) { diff --git a/src/parser/incremental.ts b/src/parser/incremental.ts index 2e587e1..4594c8f 100644 --- a/src/parser/incremental.ts +++ b/src/parser/incremental.ts @@ -9,7 +9,7 @@ import { scanDirectory, type ScanOptions } from './scanner.js' import { extractImports, type ExtractOptions } from './extractor.js' import { createResolverContext, resolveImport, toRelativePath } from './resolver.js' import type { DependencyGraph, DependencyEdge, BuildGraphOptions } from './graph.js' -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' import { loadCache, saveCache, @@ -27,9 +27,9 @@ import { */ export interface IncrementalBuildOptions extends BuildGraphOptions { /** - * Archgate config (needed for cache invalidation) + * Layerguard config (needed for cache invalidation) */ - config: ArchgateConfig + config: LayerguardConfig /** * Whether to use caching @@ -168,9 +168,8 @@ export function buildDependencyGraphIncremental( try { saveCache(projectRoot, updatedCache) - } catch (error) { + } catch { // Cache save errors should not break the build - // Silently ignore cache errors } onProgress?.({ @@ -208,9 +207,8 @@ export function buildDependencyGraphIncremental( const cache = graphToCache(graph, config, tsconfigPath) try { saveCache(projectRoot, cache) - } catch (error) { + } catch { // Cache save errors should not break the build - // Silently ignore cache errors } } diff --git a/src/plugins/CONTRIBUTING.md b/src/plugins/CONTRIBUTING.md index 4708bb8..27a38f9 100644 --- a/src/plugins/CONTRIBUTING.md +++ b/src/plugins/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Plugin Contribution Guide -This guide explains how to create framework plugins for Archgate. +This guide explains how to create framework plugins for Layerguard. ## Overview @@ -220,4 +220,4 @@ Reference these existing plugins for patterns: 3. Ensure all tests pass: `npm test` 4. Submit a pull request -Your plugin will be reviewed and merged to make it available for all Archgate users. +Your plugin will be reviewed and merged to make it available for all Layerguard users. diff --git a/src/workspace/configs.ts b/src/workspace/configs.ts index 354f288..1fa21ff 100644 --- a/src/workspace/configs.ts +++ b/src/workspace/configs.ts @@ -1,14 +1,14 @@ /** - * Per-package Archgate config discovery + * Per-package Layerguard config discovery * - * Finds and loads archgate configs from workspace packages + * Finds and loads layerguard configs from workspace packages */ import { existsSync } from 'node:fs' import { join } from 'node:path' import type { WorkspaceConfig, WorkspacePackage } from './detector.js' import { loadConfig } from '../config/loader.js' -import type { ArchgateConfig } from '../config/types.js' +import type { LayerguardConfig } from '../config/types.js' /** * Package config information @@ -20,14 +20,14 @@ export interface PackageConfig { package: WorkspacePackage /** - * Path to the archgate config file + * Path to the layerguard config file */ configPath: string /** * Loaded config (null if not loaded yet) */ - config: ArchgateConfig | null + config: LayerguardConfig | null } /** @@ -46,23 +46,23 @@ export interface PackageConfigDiscovery { } /** - * Known archgate config file names + * Known layerguard config file names */ const CONFIG_FILE_NAMES = [ - 'archgate.config.ts', - 'archgate.config.js', - 'archgate.config.mjs', - '.archgaterc.ts', - '.archgaterc.js', + 'layerguard.config.ts', + 'layerguard.config.js', + 'layerguard.config.mjs', + '.layerguardrc.ts', + '.layerguardrc.js', ] /** - * Discover archgate configs in a workspace + * Discover layerguard configs in a workspace */ export function discoverPackageConfigs(workspace: WorkspaceConfig): PackageConfigDiscovery { const packageConfigs: PackageConfig[] = [] - // Check each package for an archgate config + // Check each package for a layerguard config for (const pkg of workspace.packages) { const configPath = findConfigInDirectory(pkg.path) if (configPath) { @@ -96,7 +96,7 @@ export function discoverPackageConfigs(workspace: WorkspaceConfig): PackageConfi } /** - * Find archgate config file in a directory + * Find layerguard config file in a directory */ function findConfigInDirectory(dir: string): string | null { for (const name of CONFIG_FILE_NAMES) { @@ -113,7 +113,7 @@ function findConfigInDirectory(dir: string): string | null { */ export async function loadPackageConfig( packageConfig: PackageConfig -): Promise { +): Promise { const { config } = await loadConfig(packageConfig.package.path) return config } @@ -147,7 +147,7 @@ export function findPackageConfig( } /** - * Get all package names that have archgate configs + * Get all package names that have layerguard configs */ export function getConfiguredPackageNames(discovery: PackageConfigDiscovery): string[] { return discovery.packageConfigs.map((pc) => pc.package.name) diff --git a/tests/fixtures/barrel-exports/archgate.config.ts b/tests/fixtures/barrel-exports/layerguard.config.ts similarity index 82% rename from tests/fixtures/barrel-exports/archgate.config.ts rename to tests/fixtures/barrel-exports/layerguard.config.ts index 96e121c..e3d409d 100644 --- a/tests/fixtures/barrel-exports/archgate.config.ts +++ b/tests/fixtures/barrel-exports/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/circular-deps/archgate.config.ts b/tests/fixtures/circular-deps/layerguard.config.ts similarity index 80% rename from tests/fixtures/circular-deps/archgate.config.ts rename to tests/fixtures/circular-deps/layerguard.config.ts index d509a67..e1746d4 100644 --- a/tests/fixtures/circular-deps/archgate.config.ts +++ b/tests/fixtures/circular-deps/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/clean-architecture/archgate.config.ts b/tests/fixtures/clean-architecture/layerguard.config.ts similarity index 83% rename from tests/fixtures/clean-architecture/archgate.config.ts rename to tests/fixtures/clean-architecture/layerguard.config.ts index 9c83fba..07e1b2a 100644 --- a/tests/fixtures/clean-architecture/archgate.config.ts +++ b/tests/fixtures/clean-architecture/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/isolated-features/archgate.config.ts b/tests/fixtures/isolated-features/layerguard.config.ts similarity index 88% rename from tests/fixtures/isolated-features/archgate.config.ts rename to tests/fixtures/isolated-features/layerguard.config.ts index 29a5911..bd7ed1b 100644 --- a/tests/fixtures/isolated-features/archgate.config.ts +++ b/tests/fixtures/isolated-features/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/monorepo-pnpm/README.md b/tests/fixtures/monorepo-pnpm/README.md index e61bd79..07a238f 100644 --- a/tests/fixtures/monorepo-pnpm/README.md +++ b/tests/fixtures/monorepo-pnpm/README.md @@ -11,23 +11,23 @@ monorepo-pnpm/ ├── tsconfig.json # Root tsconfig with path mappings ├── packages/ │ ├── web-api/ # Backend API package -│ │ ├── archgate.config.ts +│ │ ├── layerguard.config.ts │ │ └── src/ │ │ ├── handlers/ │ │ └── services/ │ ├── shared-utils/ # Shared utilities -│ │ ├── archgate.config.ts +│ │ ├── layerguard.config.ts │ │ └── src/ │ │ ├── helpers/ │ │ └── validators/ │ └── ui-components/ # UI component library -│ ├── archgate.config.ts +│ ├── layerguard.config.ts │ └── src/ │ ├── components/ │ └── hooks/ └── apps/ └── web/ # Web application - ├── archgate.config.ts + ├── layerguard.config.ts └── src/ ├── pages/ └── components/ @@ -75,17 +75,17 @@ flow: ['pages -> components'] ### Check Single Package by Path ```bash -archgate check --package packages/web-api +layerguard check --package packages/web-api ``` ### Check Single Package by Name ```bash -archgate check --package @monorepo/web-api +layerguard check --package @monorepo/web-api ``` ### Check All Packages ```bash -archgate check --all +layerguard check --all ``` ## Cross-Package Imports @@ -100,7 +100,7 @@ These imports resolve through the tsconfig.json path mappings. ## Key Features Tested 1. **Workspace Detection**: Detects packages from `pnpm-workspace.yaml` -2. **Per-Package Configs**: Each package has its own `archgate.config.ts` +2. **Per-Package Configs**: Each package has its own `layerguard.config.ts` 3. **Package Selection**: `--package` flag works with paths and names 4. **Bulk Checking**: `--all` flag checks all packages 5. **Cross-Package Resolution**: Path aliases resolve correctly diff --git a/tests/fixtures/monorepo-pnpm/apps/web/archgate.config.ts b/tests/fixtures/monorepo-pnpm/apps/web/layerguard.config.ts similarity index 77% rename from tests/fixtures/monorepo-pnpm/apps/web/archgate.config.ts rename to tests/fixtures/monorepo-pnpm/apps/web/layerguard.config.ts index 0acb1fd..befcc7c 100644 --- a/tests/fixtures/monorepo-pnpm/apps/web/archgate.config.ts +++ b/tests/fixtures/monorepo-pnpm/apps/web/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/monorepo-pnpm/expected-results.json b/tests/fixtures/monorepo-pnpm/expected-results.json index fe46bbb..496fb23 100644 --- a/tests/fixtures/monorepo-pnpm/expected-results.json +++ b/tests/fixtures/monorepo-pnpm/expected-results.json @@ -22,24 +22,24 @@ } ], "workspaceNotes": [ - "Each package has its own archgate.config.ts", + "Each package has its own layerguard.config.ts", "Workspace packages are detected from pnpm-workspace.yaml", "Cross-package imports (e.g., @monorepo/web-api) are handled", - "archgate check --all checks all packages", - "archgate check --package @monorepo/web-api checks specific package" + "layerguard check --all checks all packages", + "layerguard check --package @monorepo/web-api checks specific package" ], "testScenarios": [ { - "command": "archgate check --package packages/web-api", + "command": "layerguard check --package packages/web-api", "description": "Check specific package by path" }, { - "command": "archgate check --package @monorepo/web-api", + "command": "layerguard check --package @monorepo/web-api", "description": "Check specific package by name" }, { - "command": "archgate check --all", - "description": "Check all packages with archgate configs" + "command": "layerguard check --all", + "description": "Check all packages with layerguard configs" } ] } diff --git a/tests/fixtures/monorepo-pnpm/packages/internal-api/archgate.config.ts b/tests/fixtures/monorepo-pnpm/packages/internal-api/layerguard.config.ts similarity index 68% rename from tests/fixtures/monorepo-pnpm/packages/internal-api/archgate.config.ts rename to tests/fixtures/monorepo-pnpm/packages/internal-api/layerguard.config.ts index 89bfc53..81d8645 100644 --- a/tests/fixtures/monorepo-pnpm/packages/internal-api/archgate.config.ts +++ b/tests/fixtures/monorepo-pnpm/packages/internal-api/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/monorepo-pnpm/packages/shared-utils/archgate.config.ts b/tests/fixtures/monorepo-pnpm/packages/shared-utils/layerguard.config.ts similarity index 78% rename from tests/fixtures/monorepo-pnpm/packages/shared-utils/archgate.config.ts rename to tests/fixtures/monorepo-pnpm/packages/shared-utils/layerguard.config.ts index 32d4090..05c2eef 100644 --- a/tests/fixtures/monorepo-pnpm/packages/shared-utils/archgate.config.ts +++ b/tests/fixtures/monorepo-pnpm/packages/shared-utils/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/monorepo-pnpm/packages/ui-components/archgate.config.ts b/tests/fixtures/monorepo-pnpm/packages/ui-components/layerguard.config.ts similarity index 77% rename from tests/fixtures/monorepo-pnpm/packages/ui-components/archgate.config.ts rename to tests/fixtures/monorepo-pnpm/packages/ui-components/layerguard.config.ts index fd8b8a6..1d3df80 100644 --- a/tests/fixtures/monorepo-pnpm/packages/ui-components/archgate.config.ts +++ b/tests/fixtures/monorepo-pnpm/packages/ui-components/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/monorepo-pnpm/packages/web-api/archgate.config.ts b/tests/fixtures/monorepo-pnpm/packages/web-api/layerguard.config.ts similarity index 78% rename from tests/fixtures/monorepo-pnpm/packages/web-api/archgate.config.ts rename to tests/fixtures/monorepo-pnpm/packages/web-api/layerguard.config.ts index 15711b0..c8163b5 100644 --- a/tests/fixtures/monorepo-pnpm/packages/web-api/archgate.config.ts +++ b/tests/fixtures/monorepo-pnpm/packages/web-api/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/unlayered-bypass/README.md b/tests/fixtures/unlayered-bypass/README.md index e933c9d..a5abffb 100644 --- a/tests/fixtures/unlayered-bypass/README.md +++ b/tests/fixtures/unlayered-bypass/README.md @@ -7,7 +7,7 @@ Tests detection of imports to files outside declared layers. Without enforcement, files outside declared layers create a backdoor: 1. Put shared logic in `src/misc/helpers.ts` (not in any layer) 2. Every layer imports it -3. Archgate says nothing - boundaries are silently bypassed +3. Layerguard says nothing - boundaries are silently bypassed ## Configuration diff --git a/tests/fixtures/unlayered-bypass/archgate.config.ts b/tests/fixtures/unlayered-bypass/layerguard.config.ts similarity index 80% rename from tests/fixtures/unlayered-bypass/archgate.config.ts rename to tests/fixtures/unlayered-bypass/layerguard.config.ts index 5d52faa..6b14f6d 100644 --- a/tests/fixtures/unlayered-bypass/archgate.config.ts +++ b/tests/fixtures/unlayered-bypass/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/fixtures/windows-paths/README.md b/tests/fixtures/windows-paths/README.md index f368da6..3a4ebc7 100644 --- a/tests/fixtures/windows-paths/README.md +++ b/tests/fixtures/windows-paths/README.md @@ -5,7 +5,7 @@ Tests cross-platform path normalization for Windows-style backslash paths. ## The Problem On Windows, paths often use backslashes (`\`), while Unix uses forward slashes (`/`). -If Archgate doesn't normalize these, layer matching can fail. +If Layerguard doesn't normalize these, layer matching can fail. ## Test Configuration diff --git a/tests/fixtures/windows-paths/archgate.config.ts b/tests/fixtures/windows-paths/layerguard.config.ts similarity index 83% rename from tests/fixtures/windows-paths/archgate.config.ts rename to tests/fixtures/windows-paths/layerguard.config.ts index 6428bd7..fcc0401 100644 --- a/tests/fixtures/windows-paths/archgate.config.ts +++ b/tests/fixtures/windows-paths/layerguard.config.ts @@ -1,4 +1,4 @@ -import { defineConfig } from 'archgate/config' +import { defineConfig } from 'layerguard/config' export default defineConfig({ layers: { diff --git a/tests/integration/fixtures.test.ts b/tests/integration/fixtures.test.ts index eec7ebc..81c2505 100644 --- a/tests/integration/fixtures.test.ts +++ b/tests/integration/fixtures.test.ts @@ -6,7 +6,7 @@ import { fileURLToPath } from 'url' const __dirname = fileURLToPath(new URL('.', import.meta.url)) const FIXTURES_DIR = resolve(__dirname, '../fixtures') -const CLI_PATH = resolve(__dirname, '../../bin/archgate.js') +const CLI_PATH = resolve(__dirname, '../../bin/layerguard.js') interface ExpectedResult { description: string diff --git a/tests/unit/cache/manager.test.ts b/tests/unit/cache/manager.test.ts index b13a50e..e227c74 100644 --- a/tests/unit/cache/manager.test.ts +++ b/tests/unit/cache/manager.test.ts @@ -1,6 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import * as fs from 'node:fs' -import * as path from 'node:path' import { loadCache, saveCache, @@ -16,7 +15,7 @@ import { import { CACHE_VERSION } from '../../../src/cache/types.js' import type { CacheData, CachedFile } from '../../../src/cache/types.js' import type { DependencyGraph } from '../../../src/parser/graph.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' vi.mock('node:fs') vi.mock('node:path', async () => { @@ -30,9 +29,8 @@ vi.mock('node:path', async () => { describe('cache manager', () => { const mockProjectRoot = '/project' - const mockCachePath = '/project/.archgate-cache/graph.json' - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, utils: { path: 'src/utils' }, @@ -79,7 +77,7 @@ describe('cache manager', () => { describe('getCachePath', () => { it('returns correct cache path', () => { const result = getCachePath('/my/project') - expect(result).toContain('.archgate-cache') + expect(result).toContain('.layerguard-cache') expect(result).toContain('graph.json') }) }) @@ -159,7 +157,7 @@ describe('cache manager', () => { saveCache(mockProjectRoot, mockCacheData) expect(fs.mkdirSync).toHaveBeenCalledWith( - expect.stringContaining('.archgate-cache'), + expect.stringContaining('.layerguard-cache'), { recursive: true } ) }) diff --git a/tests/unit/cli/check.test.ts b/tests/unit/cli/check.test.ts index 9a84240..364064e 100644 --- a/tests/unit/cli/check.test.ts +++ b/tests/unit/cli/check.test.ts @@ -3,7 +3,7 @@ import { runCheck } from '../../../src/cli/check.js' import * as loader from '../../../src/config/loader.js' import * as incrementalBuilder from '../../../src/parser/incremental.js' import * as workspace from '../../../src/workspace/index.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' import type { DependencyGraph } from '../../../src/parser/graph.js' import type { IncrementalBuildResult } from '../../../src/parser/incremental.js' @@ -13,7 +13,7 @@ vi.mock('../../../src/parser/incremental.js') vi.mock('../../../src/workspace/index.js') describe('runCheck', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -54,7 +54,7 @@ describe('runCheck', () => { it('returns passed: true when no violations found', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -69,7 +69,7 @@ describe('runCheck', () => { it('returns check result with all required fields', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -86,7 +86,7 @@ describe('runCheck', () => { it('outputs in JSON format when requested', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -100,7 +100,7 @@ describe('runCheck', () => { it('outputs in CI format when requested', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -114,7 +114,7 @@ describe('runCheck', () => { it('handles config load errors', async () => { vi.mocked(loader.loadConfig).mockRejectedValue(new Error('Config not found')) - const result = await runCheck() + const result = await runCheck({ format: 'terminal' }) expect(result.passed).toBe(false) expect(result.exitCode).toBe(1) @@ -122,7 +122,7 @@ describe('runCheck', () => { }) it('handles invalid config', async () => { - const invalidConfig: ArchgateConfig = { + const invalidConfig: LayerguardConfig = { layers: { invalid: { path: '' }, // Invalid: empty path }, @@ -131,7 +131,7 @@ describe('runCheck', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: invalidConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) const result = await runCheck() @@ -144,7 +144,7 @@ describe('runCheck', () => { it('respects noColors option', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -158,7 +158,7 @@ describe('runCheck', () => { it('passes typeOnlyImports option to graph builder', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -172,14 +172,14 @@ describe('runCheck', () => { }) it('uses config ignore patterns', async () => { - const configWithIgnore: ArchgateConfig = { + const configWithIgnore: LayerguardConfig = { ...mockConfig, ignore: ['**/*.test.ts'], } vi.mocked(loader.loadConfig).mockResolvedValue({ config: configWithIgnore, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -193,7 +193,7 @@ describe('runCheck', () => { }) it('respects circular dependency rule setting', async () => { - const configWithCircularOff: ArchgateConfig = { + const configWithCircularOff: LayerguardConfig = { ...mockConfig, rules: { circular: 'off', @@ -202,7 +202,7 @@ describe('runCheck', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: configWithCircularOff, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -216,7 +216,7 @@ describe('runCheck', () => { // Config with potential warning (e.g., framework that doesn't match project) vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -251,7 +251,7 @@ describe('runCheck', () => { it('respects noCache option', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) @@ -266,7 +266,7 @@ describe('runCheck', () => { }) describe('runCheck with workspace options', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, }, @@ -300,7 +300,7 @@ describe('runCheck with workspace options', () => { const createMockPkgConfig = (name: string, pkgPath: string) => ({ package: createMockPackage(name, pkgPath), - configPath: `${pkgPath}/archgate.config.ts`, + configPath: `${pkgPath}/layerguard.config.ts`, config: null, }) @@ -421,7 +421,7 @@ describe('runCheck with workspace options', () => { }) vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) diff --git a/tests/unit/cli/detect.test.ts b/tests/unit/cli/detect.test.ts index ccc3799..ee6cc42 100644 --- a/tests/unit/cli/detect.test.ts +++ b/tests/unit/cli/detect.test.ts @@ -14,7 +14,7 @@ describe('detectFramework', () => { let tempDir: string beforeEach(() => { - tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'archgate-test-')) + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'layerguard-test-')) }) afterEach(() => { @@ -113,7 +113,7 @@ describe('scanForLayers', () => { let tempDir: string beforeEach(() => { - tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'archgate-test-')) + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'layerguard-test-')) }) afterEach(() => { diff --git a/tests/unit/cli/generator.test.ts b/tests/unit/cli/generator.test.ts index b031924..512b96a 100644 --- a/tests/unit/cli/generator.test.ts +++ b/tests/unit/cli/generator.test.ts @@ -7,10 +7,10 @@ import { writeConfigFile, configFileExists, } from '../../../src/cli/generator.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' describe('generateConfigContent', () => { - const basicConfig: ArchgateConfig = { + const basicConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -21,7 +21,7 @@ describe('generateConfigContent', () => { it('generates TypeScript config by default', () => { const content = generateConfigContent(basicConfig) - expect(content).toContain("import { defineConfig } from 'archgate'") + expect(content).toContain("import { defineConfig } from 'layerguard'") expect(content).toContain('export default defineConfig({') }) @@ -49,7 +49,7 @@ describe('generateConfigContent', () => { }) it('includes framework when set', () => { - const configWithFramework: ArchgateConfig = { + const configWithFramework: LayerguardConfig = { ...basicConfig, framework: 'nextjs-app', } @@ -60,7 +60,7 @@ describe('generateConfigContent', () => { }) it('includes rules when set', () => { - const configWithRules: ArchgateConfig = { + const configWithRules: LayerguardConfig = { ...basicConfig, rules: { circular: 'error', @@ -76,7 +76,7 @@ describe('generateConfigContent', () => { }) it('includes ignore patterns when set', () => { - const configWithIgnore: ArchgateConfig = { + const configWithIgnore: LayerguardConfig = { ...basicConfig, ignore: ['**/*.test.ts', 'dist/**'], } @@ -103,7 +103,7 @@ describe('generateConfigContent', () => { }) it('handles complex layer with sublayers', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -139,7 +139,7 @@ describe('writeConfigFile', () => { let tempDir: string beforeEach(() => { - tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'archgate-test-')) + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'layerguard-test-')) }) afterEach(() => { @@ -147,14 +147,14 @@ describe('writeConfigFile', () => { }) it('writes TypeScript config file', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' } }, flow: [], } const filepath = writeConfigFile(tempDir, config, { typescript: true }) - expect(filepath).toBe(path.join(tempDir, 'archgate.config.ts')) + expect(filepath).toBe(path.join(tempDir, 'layerguard.config.ts')) expect(fs.existsSync(filepath)).toBe(true) const content = fs.readFileSync(filepath, 'utf-8') @@ -162,14 +162,14 @@ describe('writeConfigFile', () => { }) it('writes JavaScript config file', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' } }, flow: [], } const filepath = writeConfigFile(tempDir, config, { typescript: false }) - expect(filepath).toBe(path.join(tempDir, 'archgate.config.js')) + expect(filepath).toBe(path.join(tempDir, 'layerguard.config.js')) expect(fs.existsSync(filepath)).toBe(true) const content = fs.readFileSync(filepath, 'utf-8') @@ -181,7 +181,7 @@ describe('configFileExists', () => { let tempDir: string beforeEach(() => { - tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'archgate-test-')) + tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'layerguard-test-')) }) afterEach(() => { @@ -194,37 +194,37 @@ describe('configFileExists', () => { expect(result).toBeNull() }) - it('returns filename when archgate.config.ts exists', () => { - fs.writeFileSync(path.join(tempDir, 'archgate.config.ts'), '') + it('returns filename when layerguard.config.ts exists', () => { + fs.writeFileSync(path.join(tempDir, 'layerguard.config.ts'), '') const result = configFileExists(tempDir) - expect(result).toBe('archgate.config.ts') + expect(result).toBe('layerguard.config.ts') }) - it('returns filename when archgate.config.js exists', () => { - fs.writeFileSync(path.join(tempDir, 'archgate.config.js'), '') + it('returns filename when layerguard.config.js exists', () => { + fs.writeFileSync(path.join(tempDir, 'layerguard.config.js'), '') const result = configFileExists(tempDir) - expect(result).toBe('archgate.config.js') + expect(result).toBe('layerguard.config.js') }) it('returns first match when multiple configs exist', () => { // .ts should be checked first - fs.writeFileSync(path.join(tempDir, 'archgate.config.ts'), '') - fs.writeFileSync(path.join(tempDir, 'archgate.config.js'), '') + fs.writeFileSync(path.join(tempDir, 'layerguard.config.ts'), '') + fs.writeFileSync(path.join(tempDir, 'layerguard.config.js'), '') const result = configFileExists(tempDir) - expect(result).toBe('archgate.config.ts') + expect(result).toBe('layerguard.config.ts') }) it('returns .mjs config when it exists', () => { - fs.writeFileSync(path.join(tempDir, 'archgate.config.mjs'), '') + fs.writeFileSync(path.join(tempDir, 'layerguard.config.mjs'), '') const result = configFileExists(tempDir) - expect(result).toBe('archgate.config.mjs') + expect(result).toBe('layerguard.config.mjs') }) }) diff --git a/tests/unit/cli/index.test.ts b/tests/unit/cli/index.test.ts index b0ae6fa..540308c 100644 --- a/tests/unit/cli/index.test.ts +++ b/tests/unit/cli/index.test.ts @@ -271,7 +271,7 @@ describe('printHelp', () => { printHelp() expect(console.log).toHaveBeenCalled() const output = vi.mocked(console.log).mock.calls[0]?.[0] as string - expect(output).toContain('archgate') + expect(output).toContain('layerguard') expect(output).toContain('Usage:') expect(output).toContain('Commands:') }) @@ -303,7 +303,7 @@ describe('printVersion', () => { it('prints version', () => { printVersion() - expect(console.log).toHaveBeenCalledWith(`archgate v${VERSION}`) + expect(console.log).toHaveBeenCalledWith(`layerguard v${VERSION}`) }) }) @@ -332,7 +332,7 @@ describe('main', () => { it('prints version with --version flag', async () => { await main(['--version']) - expect(console.log).toHaveBeenCalledWith(`archgate v${VERSION}`) + expect(console.log).toHaveBeenCalledWith(`layerguard v${VERSION}`) }) it('prints help with --help flag', async () => { diff --git a/tests/unit/cli/init.test.ts b/tests/unit/cli/init.test.ts index a4de309..661a561 100644 --- a/tests/unit/cli/init.test.ts +++ b/tests/unit/cli/init.test.ts @@ -62,7 +62,7 @@ describe('runInit', () => { vi.mocked(presets.getPresetByFramework).mockReturnValue(mockPreset) vi.mocked(presets.getAllPresets).mockReturnValue([mockPreset]) vi.mocked(generator.generateConfigContent).mockReturnValue('export default {}') - vi.mocked(generator.writeConfigFile).mockReturnValue('archgate.config.ts') + vi.mocked(generator.writeConfigFile).mockReturnValue('layerguard.config.ts') vi.mocked(detect.scanForLayers).mockReturnValue([]) vi.mocked(p.isCancel).mockReturnValue(false) @@ -75,7 +75,7 @@ describe('runInit', () => { describe('existing config handling', () => { it('warns when config already exists', async () => { - vi.mocked(generator.configFileExists).mockReturnValue('archgate.config.ts') + vi.mocked(generator.configFileExists).mockReturnValue('layerguard.config.ts') vi.mocked(p.confirm).mockResolvedValue(false) await runInit() @@ -85,7 +85,7 @@ describe('runInit', () => { }) it('allows overwriting existing config when confirmed', async () => { - vi.mocked(generator.configFileExists).mockReturnValue('archgate.config.ts') + vi.mocked(generator.configFileExists).mockReturnValue('layerguard.config.ts') vi.mocked(p.confirm).mockResolvedValueOnce(true) .mockResolvedValueOnce(true) .mockResolvedValueOnce(true) @@ -97,7 +97,7 @@ describe('runInit', () => { }) it('skips overwrite prompt with --yes flag', async () => { - vi.mocked(generator.configFileExists).mockReturnValue('archgate.config.ts') + vi.mocked(generator.configFileExists).mockReturnValue('layerguard.config.ts') await runInit({ yes: true }) @@ -207,7 +207,7 @@ describe('runInit', () => { describe('cancellation handling', () => { it('handles cancel on overwrite confirmation', async () => { - vi.mocked(generator.configFileExists).mockReturnValue('archgate.config.ts') + vi.mocked(generator.configFileExists).mockReturnValue('layerguard.config.ts') vi.mocked(p.confirm).mockResolvedValue(Symbol('cancel') as unknown as boolean) vi.mocked(p.isCancel).mockReturnValue(true) diff --git a/tests/unit/cli/presets.test.ts b/tests/unit/cli/presets.test.ts index 4d24e21..e920ded 100644 --- a/tests/unit/cli/presets.test.ts +++ b/tests/unit/cli/presets.test.ts @@ -82,8 +82,8 @@ describe('createCustomConfig', () => { ['components -> hooks'] ) - expect(config.layers.components.path).toBe('src/components') - expect(config.layers.hooks.path).toBe('src/hooks') + expect(config.layers.components!.path).toBe('src/components') + expect(config.layers.hooks!.path).toBe('src/hooks') expect(config.flow).toContain('components -> hooks') }) @@ -102,10 +102,10 @@ describe('createCustomConfig', () => { [] ) - expect(config.layers.components.sublayers?.features.path).toBe('features') - expect(config.layers.components.sublayers?.features.isolated).toBe(true) - expect(config.layers.components.sublayers?.shared.path).toBe('shared') - expect(config.layers.components.sublayers?.shared.isolated).toBeUndefined() + expect(config.layers.components!.sublayers!.features!.path).toBe('features') + expect(config.layers.components!.sublayers!.features!.isolated).toBe(true) + expect(config.layers.components!.sublayers!.shared!.path).toBe('shared') + expect(config.layers.components!.sublayers!.shared!.isolated).toBeUndefined() }) it('includes framework when provided', () => { @@ -135,13 +135,13 @@ describe('nextjsAppPreset', () => { it('includes app layer', () => { expect(nextjsAppPreset.layers.app).toBeDefined() - expect(nextjsAppPreset.layers.app.path).toBe('app') + expect(nextjsAppPreset.layers.app!.path).toBe('app') }) it('includes components layer with sublayers', () => { expect(nextjsAppPreset.layers.components).toBeDefined() - expect(nextjsAppPreset.layers.components.sublayers).toBeDefined() - expect(nextjsAppPreset.layers.components.sublayers?.features.isolated).toBe(true) + expect(nextjsAppPreset.layers.components!.sublayers).toBeDefined() + expect(nextjsAppPreset.layers.components!.sublayers!.features!.isolated).toBe(true) }) it('has valid flow rules', () => { @@ -176,7 +176,7 @@ describe('genericLayeredPreset', () => { }) it('uses src/ prefix for paths', () => { - expect(genericLayeredPreset.layers.components.path).toBe('src/components') - expect(genericLayeredPreset.layers.hooks.path).toBe('src/hooks') + expect(genericLayeredPreset.layers.components!.path).toBe('src/components') + expect(genericLayeredPreset.layers.hooks!.path).toBe('src/hooks') }) }) diff --git a/tests/unit/cli/report.test.ts b/tests/unit/cli/report.test.ts index a5aaa50..49fdc1a 100644 --- a/tests/unit/cli/report.test.ts +++ b/tests/unit/cli/report.test.ts @@ -3,7 +3,7 @@ */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' import type { DependencyGraph } from '../../../src/parser/graph.js' import type { IncrementalBuildResult } from '../../../src/parser/incremental.js' import type { ViolationReport } from '../../../src/enforcer/violations.js' @@ -24,7 +24,7 @@ import * as incrementalBuilder from '../../../src/parser/incremental.js' import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'node:fs' describe('runReport', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -58,7 +58,7 @@ describe('runReport', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(incrementalBuilder.buildDependencyGraphIncremental).mockReturnValue(mockBuildResult) vi.mocked(existsSync).mockReturnValue(true) @@ -110,7 +110,7 @@ describe('runReport', () => { }) it('handles invalid config', async () => { - const invalidConfig: ArchgateConfig = { + const invalidConfig: LayerguardConfig = { layers: { invalid: { path: '' }, }, @@ -119,7 +119,7 @@ describe('runReport', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: invalidConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) const result = await runReport() @@ -138,7 +138,7 @@ describe('runReport', () => { it('creates output directory if needed', async () => { vi.mocked(existsSync).mockReturnValue(false) - await runReport({ output: 'reports/archgate-report.html' }) + await runReport({ output: 'reports/layerguard-report.html' }) expect(mkdirSync).toHaveBeenCalledWith(expect.any(String), { recursive: true }) }) @@ -191,7 +191,7 @@ describe('runReport', () => { vi.mocked(readFileSync).mockReturnValue(historicalData) - const result = await runReport({ cwd: '/project', from: 'archgate-history.json' }) + const result = await runReport({ cwd: '/project', from: 'layerguard-history.json' }) expect(result.success).toBe(true) }) @@ -211,7 +211,7 @@ describe('runReport', () => { }) it('handles missing historical data file gracefully', async () => { - vi.mocked(existsSync).mockImplementation((p: string) => { + vi.mocked(existsSync).mockImplementation((p) => { if (String(p).includes('history')) return false return true }) diff --git a/tests/unit/cli/show.test.ts b/tests/unit/cli/show.test.ts index b1ddd63..62684d8 100644 --- a/tests/unit/cli/show.test.ts +++ b/tests/unit/cli/show.test.ts @@ -1,13 +1,13 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import { runShow } from '../../../src/cli/show.js' import * as loader from '../../../src/config/loader.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' // Mock the config loader vi.mock('../../../src/config/loader.js') describe('runShow', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -17,7 +17,6 @@ describe('runShow', () => { } let exitSpy: ReturnType - let mockExit: (code: number) => never beforeEach(() => { vi.resetAllMocks() @@ -25,10 +24,9 @@ describe('runShow', () => { vi.spyOn(console, 'error').mockImplementation(() => {}) // Mock process.exit to throw so we can test exit behavior - mockExit = vi.fn((code: number) => { + exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => { throw new Error(`Process exited with code ${code}`) - }) as unknown as (code: number) => never - exitSpy = vi.spyOn(process, 'exit').mockImplementation(mockExit) + }) }) afterEach(() => { @@ -38,14 +36,14 @@ describe('runShow', () => { it('outputs an architecture diagram', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) await runShow() expect(console.log).toHaveBeenCalled() const output = vi.mocked(console.log).mock.calls[0]?.[0] as string - expect(output).toContain('Archgate Architecture') + expect(output).toContain('Layerguard Architecture') expect(output).toContain('components') expect(output).toContain('hooks') expect(output).toContain('utils') @@ -54,7 +52,7 @@ describe('runShow', () => { it('uses ASCII characters when ascii option is true', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) await runShow({ ascii: true }) @@ -68,7 +66,7 @@ describe('runShow', () => { it('outputs flow summary when flowOnly is true', async () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) await runShow({ flowOnly: true }) @@ -77,7 +75,7 @@ describe('runShow', () => { const output = vi.mocked(console.log).mock.calls[0]?.[0] as string expect(output).toContain('Layer dependencies:') expect(output).toContain('components -> hooks') - expect(output).not.toContain('Archgate Architecture') + expect(output).not.toContain('Layerguard Architecture') }) it('exits with code 1 on config load error', async () => { @@ -89,7 +87,7 @@ describe('runShow', () => { }) it('exits with code 1 on invalid config', async () => { - const invalidConfig: ArchgateConfig = { + const invalidConfig: LayerguardConfig = { layers: { invalid: { path: '' }, }, @@ -98,7 +96,7 @@ describe('runShow', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: invalidConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) await expect(runShow()).rejects.toThrow('Process exited with code 1') @@ -107,7 +105,7 @@ describe('runShow', () => { }) it('shows sublayers in the diagram', async () => { - const configWithSublayers: ArchgateConfig = { + const configWithSublayers: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -122,7 +120,7 @@ describe('runShow', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: configWithSublayers, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) await runShow() @@ -135,7 +133,7 @@ describe('runShow', () => { }) it('shows sublayer flow rules in flow summary', async () => { - const configWithSublayerFlow: ArchgateConfig = { + const configWithSublayerFlow: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -151,7 +149,7 @@ describe('runShow', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: configWithSublayerFlow, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) await runShow({ flowOnly: true }) diff --git a/tests/unit/cli/watch.test.ts b/tests/unit/cli/watch.test.ts index 9b6db40..c5d6c33 100644 --- a/tests/unit/cli/watch.test.ts +++ b/tests/unit/cli/watch.test.ts @@ -3,7 +3,7 @@ */ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' vi.mock('node:fs', () => ({ watch: vi.fn(() => ({ @@ -24,7 +24,7 @@ import * as check from '../../../src/cli/check.js' import { watch } from 'node:fs' describe('startWatch', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -49,7 +49,7 @@ describe('startWatch', () => { vi.mocked(loader.loadConfig).mockResolvedValue({ config: mockConfig, - configPath: 'archgate.config.ts', + configPath: 'layerguard.config.ts', }) vi.mocked(check.runCheck).mockResolvedValue(mockCheckResult) @@ -136,12 +136,12 @@ describe('startWatch', () => { it('should debounce file changes', async () => { let changeCallback: ((eventType: string, filename: string | null) => void) | undefined - vi.mocked(watch).mockImplementation((_path, _options, callback) => { + vi.mocked(watch).mockImplementation(((_path: unknown, _options: unknown, callback: unknown) => { changeCallback = callback as (eventType: string, filename: string | null) => void return { close: vi.fn(), - } as ReturnType - }) + } as unknown as ReturnType + }) as typeof watch) const handle = await startWatch({ debounce: 300 }) vi.mocked(check.runCheck).mockClear() @@ -161,10 +161,10 @@ describe('startWatch', () => { it('should ignore non-TypeScript files', async () => { let changeCallback: ((eventType: string, filename: string | null) => void) | undefined - vi.mocked(watch).mockImplementation((_path, _options, callback) => { + vi.mocked(watch).mockImplementation(((_path: unknown, _options: unknown, callback: unknown) => { changeCallback = callback as (eventType: string, filename: string | null) => void - return { close: vi.fn() } as ReturnType - }) + return { close: vi.fn() } as unknown as ReturnType + }) as typeof watch) const handle = await startWatch({ debounce: 100 }) vi.mocked(check.runCheck).mockClear() @@ -182,10 +182,10 @@ describe('startWatch', () => { it('should ignore node_modules changes', async () => { let changeCallback: ((eventType: string, filename: string | null) => void) | undefined - vi.mocked(watch).mockImplementation((_path, _options, callback) => { + vi.mocked(watch).mockImplementation(((_path: unknown, _options: unknown, callback: unknown) => { changeCallback = callback as (eventType: string, filename: string | null) => void - return { close: vi.fn() } as ReturnType - }) + return { close: vi.fn() } as unknown as ReturnType + }) as typeof watch) const handle = await startWatch({ debounce: 100 }) vi.mocked(check.runCheck).mockClear() @@ -203,10 +203,10 @@ describe('startWatch', () => { it('should handle null filename gracefully', async () => { let changeCallback: ((eventType: string, filename: string | null) => void) | undefined - vi.mocked(watch).mockImplementation((_path, _options, callback) => { + vi.mocked(watch).mockImplementation(((_path: unknown, _options: unknown, callback: unknown) => { changeCallback = callback as (eventType: string, filename: string | null) => void - return { close: vi.fn() } as ReturnType - }) + return { close: vi.fn() } as unknown as ReturnType + }) as typeof watch) const handle = await startWatch({ debounce: 100 }) vi.mocked(check.runCheck).mockClear() diff --git a/tests/unit/config/loader.test.ts b/tests/unit/config/loader.test.ts index 5e5ca45..d9a17c1 100644 --- a/tests/unit/config/loader.test.ts +++ b/tests/unit/config/loader.test.ts @@ -8,7 +8,7 @@ describe('findConfigFile', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-loader-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-loader-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) @@ -22,30 +22,30 @@ describe('findConfigFile', () => { expect(findConfigFile(testDir)).toBeNull() }) - it('finds archgate.config.ts', () => { - writeFileSync(join(testDir, 'archgate.config.ts'), 'export default {}') - expect(findConfigFile(testDir)).toBe(join(testDir, 'archgate.config.ts')) + it('finds layerguard.config.ts', () => { + writeFileSync(join(testDir, 'layerguard.config.ts'), 'export default {}') + expect(findConfigFile(testDir)).toBe(join(testDir, 'layerguard.config.ts')) }) - it('finds archgate.config.js', () => { - writeFileSync(join(testDir, 'archgate.config.js'), 'module.exports = {}') - expect(findConfigFile(testDir)).toBe(join(testDir, 'archgate.config.js')) + it('finds layerguard.config.js', () => { + writeFileSync(join(testDir, 'layerguard.config.js'), 'module.exports = {}') + expect(findConfigFile(testDir)).toBe(join(testDir, 'layerguard.config.js')) }) it('prioritizes .ts over .js', () => { - writeFileSync(join(testDir, 'archgate.config.ts'), 'export default {}') - writeFileSync(join(testDir, 'archgate.config.js'), 'module.exports = {}') - expect(findConfigFile(testDir)).toBe(join(testDir, 'archgate.config.ts')) + writeFileSync(join(testDir, 'layerguard.config.ts'), 'export default {}') + writeFileSync(join(testDir, 'layerguard.config.js'), 'module.exports = {}') + expect(findConfigFile(testDir)).toBe(join(testDir, 'layerguard.config.ts')) }) - it('finds archgate.config.mjs', () => { - writeFileSync(join(testDir, 'archgate.config.mjs'), 'export default {}') - expect(findConfigFile(testDir)).toBe(join(testDir, 'archgate.config.mjs')) + it('finds layerguard.config.mjs', () => { + writeFileSync(join(testDir, 'layerguard.config.mjs'), 'export default {}') + expect(findConfigFile(testDir)).toBe(join(testDir, 'layerguard.config.mjs')) }) - it('finds archgate.config.cjs', () => { - writeFileSync(join(testDir, 'archgate.config.cjs'), 'module.exports = {}') - expect(findConfigFile(testDir)).toBe(join(testDir, 'archgate.config.cjs')) + it('finds layerguard.config.cjs', () => { + writeFileSync(join(testDir, 'layerguard.config.cjs'), 'module.exports = {}') + expect(findConfigFile(testDir)).toBe(join(testDir, 'layerguard.config.cjs')) }) }) @@ -53,7 +53,7 @@ describe('loadConfig', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-loader-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-loader-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) @@ -77,14 +77,14 @@ describe('loadConfig', () => { flow: ['components -> hooks'], } ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) const result = await loadConfig(testDir) expect(result.config.layers).toHaveProperty('components') expect(result.config.layers).toHaveProperty('hooks') expect(result.config.flow).toContain('components -> hooks') - expect(result.configPath).toBe(join(testDir, 'archgate.config.ts')) + expect(result.configPath).toBe(join(testDir, 'layerguard.config.ts')) }) it('loads a JavaScript config file', async () => { @@ -96,12 +96,12 @@ describe('loadConfig', () => { flow: [], } ` - writeFileSync(join(testDir, 'archgate.config.js'), configContent) + writeFileSync(join(testDir, 'layerguard.config.js'), configContent) const result = await loadConfig(testDir) expect(result.config.layers).toHaveProperty('utils') - expect(result.configPath).toBe(join(testDir, 'archgate.config.js')) + expect(result.configPath).toBe(join(testDir, 'layerguard.config.js')) }) it('loads ESM config file', async () => { @@ -114,7 +114,7 @@ describe('loadConfig', () => { } export default config ` - writeFileSync(join(testDir, 'archgate.config.mjs'), configContent) + writeFileSync(join(testDir, 'layerguard.config.mjs'), configContent) const result = await loadConfig(testDir) @@ -133,7 +133,7 @@ describe('loadConfig', () => { flow: [], }) ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) const result = await loadConfig(testDir) @@ -156,7 +156,7 @@ describe('loadConfig', () => { flow: [], } ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) const result = await loadConfig(testDir) @@ -180,7 +180,7 @@ describe('loadConfig', () => { ignore: ['**/*.test.ts', '**/*.spec.ts'], } ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) const result = await loadConfig(testDir) @@ -195,7 +195,7 @@ describe('loadConfig', () => { invalid syntax here } ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) await expect(loadConfig(testDir)).rejects.toThrow(ConfigLoadError) }) @@ -206,7 +206,7 @@ describe('loadConfigSync', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-loader-sync-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-loader-sync-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) @@ -230,13 +230,13 @@ describe('loadConfigSync', () => { flow: [], } ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) const result = loadConfigSync(testDir) expect(result).not.toBeNull() expect(result?.config.layers).toHaveProperty('components') - expect(result?.configPath).toBe(join(testDir, 'archgate.config.ts')) + expect(result?.configPath).toBe(join(testDir, 'layerguard.config.ts')) }) it('loads a JavaScript config file synchronously', () => { @@ -248,7 +248,7 @@ describe('loadConfigSync', () => { flow: [], } ` - writeFileSync(join(testDir, 'archgate.config.js'), configContent) + writeFileSync(join(testDir, 'layerguard.config.js'), configContent) const result = loadConfigSync(testDir) @@ -262,7 +262,7 @@ describe('loadConfigSync', () => { invalid syntax } ` - writeFileSync(join(testDir, 'archgate.config.ts'), configContent) + writeFileSync(join(testDir, 'layerguard.config.ts'), configContent) const result = loadConfigSync(testDir) diff --git a/tests/unit/config/validator.test.ts b/tests/unit/config/validator.test.ts index e946589..fde5034 100644 --- a/tests/unit/config/validator.test.ts +++ b/tests/unit/config/validator.test.ts @@ -3,14 +3,14 @@ import { mkdirSync, rmSync, existsSync } from 'node:fs' import { join } from 'node:path' import { tmpdir } from 'node:os' import { validateConfig } from '../../../src/config/validator.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' describe('validateConfig', () => { let testDir: string beforeEach(() => { // Create a temp directory for testing path validation - testDir = join(tmpdir(), `archgate-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) mkdirSync(join(testDir, 'components'), { recursive: true }) mkdirSync(join(testDir, 'components', 'features'), { recursive: true }) @@ -28,7 +28,7 @@ describe('validateConfig', () => { describe('required fields', () => { it('fails if layers is missing', () => { - const config = { flow: ['A -> B'] } as unknown as ArchgateConfig + const config = { flow: ['A -> B'] } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.valid).toBe(false) @@ -36,7 +36,7 @@ describe('validateConfig', () => { }) it('fails if flow is missing', () => { - const config = { layers: { A: { path: 'a' } } } as unknown as ArchgateConfig + const config = { layers: { A: { path: 'a' } } } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.valid).toBe(false) @@ -44,7 +44,7 @@ describe('validateConfig', () => { }) it('passes with valid minimal config', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, hooks: { path: 'hooks' }, @@ -66,14 +66,14 @@ describe('validateConfig', () => { }, flow: [], } - const result = validateConfig(config as ArchgateConfig, testDir) + const result = validateConfig(config as LayerguardConfig, testDir) expect(result.valid).toBe(false) expect(result.errors.some((e) => e.code === 'MISSING_LAYER_PATH')).toBe(true) }) it('warns if layer path does not exist', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { nonexistent: { path: 'does-not-exist' }, }, @@ -87,7 +87,7 @@ describe('validateConfig', () => { describe('flow rule validation', () => { it('fails if flow rule references unknown layer', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, }, @@ -100,7 +100,7 @@ describe('validateConfig', () => { }) it('fails if flow rule has invalid syntax', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, hooks: { path: 'hooks' }, @@ -114,7 +114,7 @@ describe('validateConfig', () => { }) it('warns if a layer is not referenced in any flow rule', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, hooks: { path: 'hooks' }, @@ -128,7 +128,7 @@ describe('validateConfig', () => { }) it('builds flow graph for valid config', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, hooks: { path: 'hooks' }, @@ -144,7 +144,7 @@ describe('validateConfig', () => { describe('sublayer validation', () => { it('validates sublayer paths', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components', @@ -164,7 +164,7 @@ describe('validateConfig', () => { }) it('fails if sublayer flow references unknown sublayer', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components', @@ -185,7 +185,7 @@ describe('validateConfig', () => { describe('framework validation', () => { it('passes with valid framework', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { framework: 'nextjs-app', layers: { components: { path: 'components' }, @@ -204,7 +204,7 @@ describe('validateConfig', () => { components: { path: 'components' }, }, flow: [], - } as unknown as ArchgateConfig + } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.valid).toBe(false) @@ -214,7 +214,7 @@ describe('validateConfig', () => { describe('rules validation', () => { it('passes with valid rules', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, }, @@ -239,14 +239,14 @@ describe('validateConfig', () => { rules: { circular: 'invalid', }, - } as unknown as ArchgateConfig + } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.errors.some((e) => e.code === 'INVALID_RULES_CIRCULAR')).toBe(true) }) it('accepts orphans value of off (default behavior)', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, }, @@ -261,7 +261,7 @@ describe('validateConfig', () => { }) it('accepts orphans value of error', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, }, @@ -284,7 +284,7 @@ describe('validateConfig', () => { rules: { orphans: 'invalid', }, - } as unknown as ArchgateConfig + } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.errors.some((e) => e.code === 'INVALID_RULES_ORPHANS')).toBe(true) @@ -299,7 +299,7 @@ describe('validateConfig', () => { }, flow: [], exceptions: [{ to: 'some/path', reason: 'test' }], - } as unknown as ArchgateConfig + } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.errors.some((e) => e.code === 'INVALID_EXCEPTION')).toBe(true) @@ -312,7 +312,7 @@ describe('validateConfig', () => { }, flow: [], exceptions: [{ from: 'some/path', to: 'other/path' }], - } as unknown as ArchgateConfig + } as unknown as LayerguardConfig const result = validateConfig(config, testDir) expect(result.errors.some((e) => e.code === 'INVALID_EXCEPTION')).toBe(true) @@ -320,7 +320,7 @@ describe('validateConfig', () => { }) it('passes with valid exception', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'components' }, }, diff --git a/tests/unit/enforcer/advanced-rules.test.ts b/tests/unit/enforcer/advanced-rules.test.ts index 351eafc..561852d 100644 --- a/tests/unit/enforcer/advanced-rules.test.ts +++ b/tests/unit/enforcer/advanced-rules.test.ts @@ -11,20 +11,50 @@ import { checkAdvancedRules, } from '../../../src/enforcer/advanced-rules.js' import { LayerMapper } from '../../../src/enforcer/mapper.js' -import type { DependencyGraph } from '../../../src/parser/graph.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { DependencyGraph, DependencyEdge } from '../../../src/parser/graph.js' +import type { LayerguardConfig } from '../../../src/config/types.js' + +// Helper to create a minimal valid DependencyGraph for testing +function createTestGraph( + files: string[], + edges: Array<{ source: string; target: string; specifier: string }> +): DependencyGraph { + const fullEdges: DependencyEdge[] = edges.map((e) => ({ + ...e, + isTypeOnly: false, + kind: 'static' as const, + line: 1, + })) + + const adjacencyList = new Map>() + for (const file of files) { + adjacencyList.set(file, new Set()) + } + for (const edge of fullEdges) { + adjacencyList.get(edge.source)?.add(edge.target) + } + + return { + projectRoot: '/project', + files: new Set(files), + adjacencyList, + edges: fullEdges, + parseErrors: new Map(), + unresolvedImports: [], + externalImports: new Set(), + } +} describe('Advanced enforcement rules', () => { describe('checkImportDepth', () => { it('should not flag chains within the limit', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'b.ts', target: 'c.ts', specifier: './c' }, - ], - } + ] + ) const violations = checkImportDepth(graph, 3) @@ -32,37 +62,35 @@ describe('Advanced enforcement rules', () => { }) it('should flag chains exceeding the limit', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'b.ts', target: 'c.ts', specifier: './c' }, { source: 'c.ts', target: 'd.ts', specifier: './d' }, { source: 'd.ts', target: 'e.ts', specifier: './e' }, - ], - } + ] + ) // maxDepth 2 means chains of length 3 (a -> b -> c) are fine // but a -> b -> c -> d is depth 3, exceeding limit const violations = checkImportDepth(graph, 2) expect(violations.length).toBeGreaterThan(0) - expect(violations[0].type).toBe('depth') - expect(violations[0].maxDepth).toBe(2) - expect(violations[0].actualDepth).toBeGreaterThan(2) + expect(violations[0]!.type).toBe('depth') + expect(violations[0]!.maxDepth).toBe(2) + expect(violations[0]!.actualDepth).toBeGreaterThan(2) }) it('should handle circular dependencies without infinite loops', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'b.ts', target: 'c.ts', specifier: './c' }, { source: 'c.ts', target: 'a.ts', specifier: './a' }, // cycle back to a - ], - } + ] + ) // Should not hang or crash const violations = checkImportDepth(graph, 2) @@ -71,14 +99,13 @@ describe('Advanced enforcement rules', () => { }) it('should handle disconnected subgraphs', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'x.ts', 'y.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'x.ts', 'y.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'x.ts', target: 'y.ts', specifier: './y' }, - ], - } + ] + ) const violations = checkImportDepth(graph, 1) @@ -86,15 +113,14 @@ describe('Advanced enforcement rules', () => { }) it('should provide detailed violation info', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts', 'd.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts', 'd.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'b.ts', target: 'c.ts', specifier: './c' }, { source: 'c.ts', target: 'd.ts', specifier: './d' }, - ], - } + ] + ) const violations = checkImportDepth(graph, 1) @@ -107,31 +133,35 @@ describe('Advanced enforcement rules', () => { }) describe('checkPublicApi', () => { - const createConfig = (publicApi?: string | string[]): ArchgateConfig => ({ - layers: { - ui: { path: 'src/ui' }, - services: { - path: 'src/services', - publicApi, + const createConfig = (publicApi?: string | string[]): LayerguardConfig => { + const config: LayerguardConfig = { + layers: { + ui: { path: 'src/ui' }, + services: { + path: 'src/services', + }, }, - }, - flow: ['ui -> services'], - }) + flow: ['ui -> services'], + } + if (publicApi !== undefined) { + config.layers.services = { path: 'src/services', publicApi } + } + return config + } it('should not flag imports when no publicApi is configured', () => { const config = createConfig() const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/Button.tsx', 'src/services/internal/helper.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/Button.tsx', 'src/services/internal/helper.ts'], + [ { source: 'src/ui/Button.tsx', target: 'src/services/internal/helper.ts', specifier: '../services/internal/helper', }, - ], - } + ] + ) const violations = checkPublicApi(graph, config, mapper) @@ -141,40 +171,38 @@ describe('Advanced enforcement rules', () => { it('should flag imports to non-public files', () => { const config = createConfig('index.ts') const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/Button.tsx', 'src/services/internal/helper.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/Button.tsx', 'src/services/internal/helper.ts'], + [ { source: 'src/ui/Button.tsx', target: 'src/services/internal/helper.ts', specifier: '../services/internal/helper', }, - ], - } + ] + ) const violations = checkPublicApi(graph, config, mapper) expect(violations).toHaveLength(1) - expect(violations[0].type).toBe('publicApi') - expect(violations[0].targetLayer).toBe('services') - expect(violations[0].publicApiFiles).toContain('index.ts') + expect(violations[0]!.type).toBe('publicApi') + expect(violations[0]!.targetLayer).toBe('services') + expect(violations[0]!.publicApiFiles).toContain('index.ts') }) it('should allow imports to public API files', () => { const config = createConfig('index.ts') const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/Button.tsx', 'src/services/index.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/Button.tsx', 'src/services/index.ts'], + [ { source: 'src/ui/Button.tsx', target: 'src/services/index.ts', specifier: '../services', }, - ], - } + ] + ) const violations = checkPublicApi(graph, config, mapper) @@ -184,17 +212,16 @@ describe('Advanced enforcement rules', () => { it('should support multiple public API files', () => { const config = createConfig(['index.ts', 'types.ts']) const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/Button.tsx', 'src/services/types.ts', 'src/services/internal.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/Button.tsx', 'src/services/types.ts', 'src/services/internal.ts'], + [ { source: 'src/ui/Button.tsx', target: 'src/services/types.ts', specifier: '../services/types', }, - ], - } + ] + ) const violations = checkPublicApi(graph, config, mapper) @@ -204,17 +231,16 @@ describe('Advanced enforcement rules', () => { it('should allow intra-layer imports regardless of publicApi', () => { const config = createConfig('index.ts') const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/services/user.ts', 'src/services/internal/helper.ts'], - edges: [ + const graph = createTestGraph( + ['src/services/user.ts', 'src/services/internal/helper.ts'], + [ { source: 'src/services/user.ts', target: 'src/services/internal/helper.ts', specifier: './internal/helper', }, - ], - } + ] + ) const violations = checkPublicApi(graph, config, mapper) @@ -223,30 +249,32 @@ describe('Advanced enforcement rules', () => { }) describe('checkDependentBudget', () => { - const createConfig = (maxDependents?: number): ArchgateConfig => ({ - layers: { - ui: { path: 'src/ui' }, - services: { path: 'src/services' }, - utils: { - path: 'src/utils', - maxDependents, + const createConfig = (maxDependents?: number): LayerguardConfig => { + const config: LayerguardConfig = { + layers: { + ui: { path: 'src/ui' }, + services: { path: 'src/services' }, + utils: { path: 'src/utils' }, + hooks: { path: 'src/hooks' }, }, - hooks: { path: 'src/hooks' }, - }, - flow: ['ui -> utils', 'services -> utils', 'hooks -> utils'], - }) + flow: ['ui -> utils', 'services -> utils', 'hooks -> utils'], + } + if (maxDependents !== undefined) { + config.layers.utils = { path: 'src/utils', maxDependents } + } + return config + } it('should not flag when no maxDependents is configured', () => { const config = createConfig() const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/a.ts', 'src/services/b.ts', 'src/utils/c.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/a.ts', 'src/services/b.ts', 'src/utils/c.ts'], + [ { source: 'src/ui/a.ts', target: 'src/utils/c.ts', specifier: '../utils/c' }, { source: 'src/services/b.ts', target: 'src/utils/c.ts', specifier: '../utils/c' }, - ], - } + ] + ) const violations = checkDependentBudget(graph, config, mapper) @@ -256,14 +284,13 @@ describe('Advanced enforcement rules', () => { it('should not flag when within budget', () => { const config = createConfig(3) const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/a.ts', 'src/services/b.ts', 'src/utils/c.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/a.ts', 'src/services/b.ts', 'src/utils/c.ts'], + [ { source: 'src/ui/a.ts', target: 'src/utils/c.ts', specifier: '../utils/c' }, { source: 'src/services/b.ts', target: 'src/utils/c.ts', specifier: '../utils/c' }, - ], - } + ] + ) const violations = checkDependentBudget(graph, config, mapper) @@ -273,57 +300,54 @@ describe('Advanced enforcement rules', () => { it('should flag when exceeding budget', () => { const config = createConfig(1) const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/a.ts', 'src/services/b.ts', 'src/hooks/c.ts', 'src/utils/d.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/a.ts', 'src/services/b.ts', 'src/hooks/c.ts', 'src/utils/d.ts'], + [ { source: 'src/ui/a.ts', target: 'src/utils/d.ts', specifier: '../utils/d' }, { source: 'src/services/b.ts', target: 'src/utils/d.ts', specifier: '../utils/d' }, { source: 'src/hooks/c.ts', target: 'src/utils/d.ts', specifier: '../utils/d' }, - ], - } + ] + ) const violations = checkDependentBudget(graph, config, mapper) expect(violations).toHaveLength(1) - expect(violations[0].type).toBe('dependentBudget') - expect(violations[0].targetLayer).toBe('utils') - expect(violations[0].maxDependents).toBe(1) - expect(violations[0].actualDependents).toBe(3) - expect(violations[0].dependentLayers).toContain('ui') - expect(violations[0].dependentLayers).toContain('services') - expect(violations[0].dependentLayers).toContain('hooks') + expect(violations[0]!.type).toBe('dependentBudget') + expect(violations[0]!.targetLayer).toBe('utils') + expect(violations[0]!.maxDependents).toBe(1) + expect(violations[0]!.actualDependents).toBe(3) + expect(violations[0]!.dependentLayers).toContain('ui') + expect(violations[0]!.dependentLayers).toContain('services') + expect(violations[0]!.dependentLayers).toContain('hooks') }) it('should provide helpful suggestion', () => { const config = createConfig(1) const mapper = new LayerMapper(config) - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/a.ts', 'src/services/b.ts', 'src/utils/c.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/a.ts', 'src/services/b.ts', 'src/utils/c.ts'], + [ { source: 'src/ui/a.ts', target: 'src/utils/c.ts', specifier: '../utils/c' }, { source: 'src/services/b.ts', target: 'src/utils/c.ts', specifier: '../utils/c' }, - ], - } + ] + ) const violations = checkDependentBudget(graph, config, mapper) - expect(violations[0].message).toContain('too many dependents') - expect(violations[0].suggestion).toContain('splitting') + expect(violations[0]!.message).toContain('too many dependents') + expect(violations[0]!.suggestion).toContain('splitting') }) }) describe('checkImportCount', () => { it('should not flag files within the limit', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'a.ts', target: 'c.ts', specifier: './c' }, - ], - } + ] + ) const violations = checkImportCount(graph, 5) @@ -331,39 +355,37 @@ describe('Advanced enforcement rules', () => { }) it('should flag files exceeding the limit', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'a.ts', target: 'c.ts', specifier: './c' }, { source: 'a.ts', target: 'd.ts', specifier: './d' }, { source: 'a.ts', target: 'e.ts', specifier: './e' }, - ], - } + ] + ) const violations = checkImportCount(graph, 2) expect(violations).toHaveLength(1) - expect(violations[0].type).toBe('importCount') - expect(violations[0].sourceFile).toBe('a.ts') - expect(violations[0].maxImports).toBe(2) - expect(violations[0].actualImports).toBe(4) + expect(violations[0]!.type).toBe('importCount') + expect(violations[0]!.sourceFile).toBe('a.ts') + expect(violations[0]!.maxImports).toBe(2) + expect(violations[0]!.actualImports).toBe(4) }) it('should flag multiple files', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts'], + [ { source: 'a.ts', target: 'c.ts', specifier: './c' }, { source: 'a.ts', target: 'd.ts', specifier: './d' }, { source: 'a.ts', target: 'e.ts', specifier: './e' }, { source: 'b.ts', target: 'c.ts', specifier: './c' }, { source: 'b.ts', target: 'd.ts', specifier: './d' }, { source: 'b.ts', target: 'e.ts', specifier: './e' }, - ], - } + ] + ) const violations = checkImportCount(graph, 2) @@ -373,25 +395,24 @@ describe('Advanced enforcement rules', () => { }) it('should provide helpful suggestion', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts', 'd.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts', 'd.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'a.ts', target: 'c.ts', specifier: './c' }, { source: 'a.ts', target: 'd.ts', specifier: './d' }, - ], - } + ] + ) const violations = checkImportCount(graph, 1) - expect(violations[0].message).toContain('Too many imports') - expect(violations[0].suggestion).toContain('splitting') + expect(violations[0]!.message).toContain('Too many imports') + expect(violations[0]!.suggestion).toContain('splitting') }) }) describe('checkAdvancedRules', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { ui: { path: 'src/ui' }, services: { @@ -405,16 +426,15 @@ describe('Advanced enforcement rules', () => { const mapper = new LayerMapper(config) it('should check all configured rules', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['src/ui/a.ts', 'src/ui/b.ts', 'src/services/internal.ts'], - edges: [ + const graph = createTestGraph( + ['src/ui/a.ts', 'src/ui/b.ts', 'src/services/internal.ts'], + [ // Public API violation { source: 'src/ui/a.ts', target: 'src/services/internal.ts', specifier: '../services/internal' }, // Multiple imports for import count check { source: 'src/ui/b.ts', target: 'src/services/internal.ts', specifier: '../services/internal' }, - ], - } + ] + ) const violations = checkAdvancedRules(graph, config, mapper, { maxImportDepth: 5, @@ -427,17 +447,16 @@ describe('Advanced enforcement rules', () => { }) it('should skip rules that are not configured', () => { - const graph: DependencyGraph = { - projectRoot: '/project', - files: ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts', 'f.ts'], - edges: [ + const graph = createTestGraph( + ['a.ts', 'b.ts', 'c.ts', 'd.ts', 'e.ts', 'f.ts'], + [ { source: 'a.ts', target: 'b.ts', specifier: './b' }, { source: 'a.ts', target: 'c.ts', specifier: './c' }, { source: 'a.ts', target: 'd.ts', specifier: './d' }, { source: 'a.ts', target: 'e.ts', specifier: './e' }, { source: 'a.ts', target: 'f.ts', specifier: './f' }, - ], - } + ] + ) // Don't pass maxImportDepth or maxImportsPerFile const violations = checkAdvancedRules(graph, config, mapper, {}) diff --git a/tests/unit/enforcer/checker.test.ts b/tests/unit/enforcer/checker.test.ts index 032cee6..c58ce1c 100644 --- a/tests/unit/enforcer/checker.test.ts +++ b/tests/unit/enforcer/checker.test.ts @@ -1,10 +1,10 @@ import { describe, it, expect } from 'vitest' -import { FlowChecker, createFlowChecker, checkDependencyGraph } from '../../../src/enforcer/checker.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import { createFlowChecker, checkDependencyGraph } from '../../../src/enforcer/checker.js' +import type { LayerguardConfig } from '../../../src/config/types.js' import type { DependencyGraph, DependencyEdge } from '../../../src/parser/graph.js' describe('FlowChecker', () => { - const basicConfig: ArchgateConfig = { + const basicConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -13,7 +13,7 @@ describe('FlowChecker', () => { flow: ['components -> hooks', 'hooks -> utils', 'components -> utils'], } - const configWithSublayers: ArchgateConfig = { + const configWithSublayers: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -28,7 +28,7 @@ describe('FlowChecker', () => { flow: ['components -> hooks'], } - const bidirectionalConfig: ArchgateConfig = { + const bidirectionalConfig: LayerguardConfig = { layers: { hooks: { path: 'src/hooks' }, api: { path: 'src/api' }, @@ -306,7 +306,7 @@ describe('FlowChecker', () => { describe('checkDependencyGraph', () => { it('is a convenience function that creates checker and runs check', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -341,7 +341,7 @@ describe('checkDependencyGraph', () => { }) describe('barrel resolution (import-site enforcement)', () => { - const barrelConfig: ArchgateConfig = { + const barrelConfig: LayerguardConfig = { layers: { handlers: { path: 'src/handlers' }, services: { path: 'src/services' }, @@ -406,7 +406,7 @@ describe('barrel resolution (import-site enforcement)', () => { describe('barrelResolution config option', () => { it('accepts import-site as a valid option', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { a: { path: 'src/a' }, b: { path: 'src/b' }, @@ -422,7 +422,7 @@ describe('barrelResolution config option', () => { }) it('accepts origin as a valid option', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { a: { path: 'src/a' }, b: { path: 'src/b' }, @@ -438,7 +438,7 @@ describe('barrelResolution config option', () => { }) it('defaults to import-site when not specified', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { handlers: { path: 'src/handlers' }, services: { path: 'src/services' }, @@ -463,7 +463,7 @@ describe('barrelResolution config option', () => { }) describe('orphan detection', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' }, utils: { path: 'src/utils' }, @@ -604,7 +604,7 @@ describe('orphan detection', () => { }) describe('advanced rules options', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' }, utils: { path: 'src/utils' }, @@ -615,16 +615,14 @@ describe('advanced rules options', () => { const createGraph = (files: string[], edges: Array<{ source: string; target: string }>): DependencyGraph => ({ projectRoot: '/test', files: new Set(files), - adjacencyList: new Map(files.map(file => [file, edges.filter(e => e.source === file).map(e => ({ - target: e.target, - isTypeOnly: false, - specifier: `./${e.target.split('/').pop()}`, - }))])), + adjacencyList: new Map(files.map(file => [file, new Set(edges.filter(e => e.source === file).map(e => e.target))])), edges: edges.map(e => ({ source: e.source, target: e.target, isTypeOnly: false, specifier: `./${e.target.split('/').pop()}`, + kind: 'static' as const, + line: 1, })), parseErrors: new Map(), unresolvedImports: [], diff --git a/tests/unit/enforcer/mapper.test.ts b/tests/unit/enforcer/mapper.test.ts index be07ee9..8eeecd7 100644 --- a/tests/unit/enforcer/mapper.test.ts +++ b/tests/unit/enforcer/mapper.test.ts @@ -1,9 +1,9 @@ import { describe, it, expect } from 'vitest' -import { LayerMapper, createLayerMapper } from '../../../src/enforcer/mapper.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import { createLayerMapper } from '../../../src/enforcer/mapper.js' +import type { LayerguardConfig } from '../../../src/config/types.js' describe('LayerMapper', () => { - const basicConfig: ArchgateConfig = { + const basicConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -12,7 +12,7 @@ describe('LayerMapper', () => { flow: ['components -> hooks', 'hooks -> utils'], } - const configWithSublayers: ArchgateConfig = { + const configWithSublayers: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -132,7 +132,7 @@ describe('LayerMapper', () => { describe('most specific matching (path overlap resolution)', () => { it('matches most specific layer path', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { src: { path: 'src' }, components: { path: 'src/components' }, @@ -148,7 +148,7 @@ describe('LayerMapper', () => { }) it('matches most specific sublayer path', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -170,7 +170,7 @@ describe('LayerMapper', () => { it('does not match layer with similar but different path prefix', () => { // Example from spec: src/components/shared/utils/ should NOT match utils layer - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { utils: { path: 'src/utils' }, components: { @@ -192,7 +192,7 @@ describe('LayerMapper', () => { }) it('matches parent layer when file is not in any sublayer', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -213,7 +213,7 @@ describe('LayerMapper', () => { }) it('handles trailing slash in config path', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components/' }, // trailing slash }, @@ -227,7 +227,7 @@ describe('LayerMapper', () => { }) it('handles leading slash in config path', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: '/src/components' }, // leading slash }, @@ -241,7 +241,7 @@ describe('LayerMapper', () => { }) it('normalizes Windows backslashes in config path', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src\\components' }, // Windows backslashes }, @@ -256,7 +256,7 @@ describe('LayerMapper', () => { it('does not match partial directory names', () => { // src/util should NOT match when layer path is src/utils - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { utils: { path: 'src/utils' }, }, diff --git a/tests/unit/eslint/config-cache.test.ts b/tests/unit/eslint/config-cache.test.ts index 6c4533a..16b0423 100644 --- a/tests/unit/eslint/config-cache.test.ts +++ b/tests/unit/eslint/config-cache.test.ts @@ -3,7 +3,7 @@ */ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' // Import modules normally import { clearConfigCache, getCacheStats, getConfig } from '../../../src/eslint/config-cache.js' @@ -80,7 +80,7 @@ describe('ESLint config cache', () => { }) it('should return correct stats when cache has entries', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' } }, flow: [], } @@ -90,7 +90,7 @@ describe('ESLint config cache', () => { if (dir === '/project') { return { config: mockConfig, - configPath: '/project/archgate.config.ts', + configPath: '/project/layerguard.config.ts', } } return null @@ -114,7 +114,7 @@ describe('ESLint config cache', () => { }) it('returns null for invalid config', () => { - const invalidConfig: ArchgateConfig = { + const invalidConfig: LayerguardConfig = { layers: { invalid: { path: '' }, // Empty path is invalid }, @@ -123,7 +123,7 @@ describe('ESLint config cache', () => { vi.mocked(loader.loadConfigSync).mockReturnValue({ config: invalidConfig, - configPath: '/project/archgate.config.ts', + configPath: '/project/layerguard.config.ts', }) // Validator returns invalid @@ -163,7 +163,7 @@ describe('ESLint config cache', () => { if (dir === '/project') { return { config: { layers: { components: { path: 'src/components' } }, flow: [] }, - configPath: '/project/archgate.config.ts', + configPath: '/project/layerguard.config.ts', } } return null @@ -177,7 +177,7 @@ describe('ESLint config cache', () => { if (result) { expect(result).toEqual(expect.objectContaining({ config: { layers: { components: { path: 'src/components' } }, flow: [] }, - configPath: '/project/archgate.config.ts', + configPath: '/project/layerguard.config.ts', projectRoot: '/project', })) // Note: loadConfigSync is called multiple times during directory traversal @@ -197,7 +197,7 @@ describe('ESLint config cache', () => { if (dir === '/project') { return { config: { layers: { components: { path: 'src/components' } }, flow: [] }, - configPath: '/project/archgate.config.ts', + configPath: '/project/layerguard.config.ts', } } return null @@ -207,17 +207,17 @@ describe('ESLint config cache', () => { expect(result).not.toBeNull() expect(result?.projectRoot).toBe('/project') - expect(result?.configPath).toBe('/project/archgate.config.ts') + expect(result?.configPath).toBe('/project/layerguard.config.ts') }) it('handles successful config loading and caching', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' } }, flow: ['components -> utils'], rules: { circular: 'error' }, } - const configPath = '/project/archgate.config.ts' + const configPath = '/project/layerguard.config.ts' // Mock the loader to return a config when called with '/project' vi.mocked(loader.loadConfigSync).mockImplementation((dir) => { diff --git a/tests/unit/eslint/index.test.ts b/tests/unit/eslint/index.test.ts index 0535d1b..3c49f50 100644 --- a/tests/unit/eslint/index.test.ts +++ b/tests/unit/eslint/index.test.ts @@ -18,7 +18,7 @@ describe('ESLint plugin', () => { it('should have meta information', () => { expect(plugin.meta).toBeDefined() - expect(plugin.meta?.name).toBe('archgate') + expect(plugin.meta?.name).toBe('layerguard') expect(plugin.meta?.version).toBe('0.1.0') }) @@ -39,19 +39,30 @@ describe('ESLint plugin', () => { it('should include layer-boundaries rule as error', () => { const config = plugin.configs?.recommended expect(config).toBeDefined() - expect(config?.rules).toBeDefined() - expect(config?.rules?.['archgate/layer-boundaries']).toBe('error') + expect(!Array.isArray(config)).toBe(true) + if (config && !Array.isArray(config)) { + expect(config.rules).toBeDefined() + expect(config.rules?.['layerguard/layer-boundaries']).toBe('error') + } }) it('should include the plugin', () => { const config = plugin.configs?.recommended - expect(config?.plugins).toBeDefined() - expect(config?.plugins?.archgate).toBeDefined() + expect(config).toBeDefined() + if (config && !Array.isArray(config)) { + expect(config.plugins).toBeDefined() + const plugins = config.plugins + if (plugins && !Array.isArray(plugins)) { + expect(plugins.layerguard).toBeDefined() + } + } }) it('should not include unlayered-imports', () => { const config = plugin.configs?.recommended - expect(config?.rules?.['archgate/unlayered-imports']).toBeUndefined() + if (config && !Array.isArray(config)) { + expect(config.rules?.['layerguard/unlayered-imports']).toBeUndefined() + } }) }) @@ -59,18 +70,28 @@ describe('ESLint plugin', () => { it('should include layer-boundaries rule as error', () => { const config = plugin.configs?.strict expect(config).toBeDefined() - expect(config?.rules?.['archgate/layer-boundaries']).toBe('error') + if (config && !Array.isArray(config)) { + expect(config.rules?.['layerguard/layer-boundaries']).toBe('error') + } }) it('should include unlayered-imports rule as error', () => { const config = plugin.configs?.strict - expect(config?.rules?.['archgate/unlayered-imports']).toBe('error') + if (config && !Array.isArray(config)) { + expect(config.rules?.['layerguard/unlayered-imports']).toBe('error') + } }) it('should include the plugin', () => { const config = plugin.configs?.strict - expect(config?.plugins).toBeDefined() - expect(config?.plugins?.archgate).toBeDefined() + expect(config).toBeDefined() + if (config && !Array.isArray(config)) { + expect(config.plugins).toBeDefined() + const plugins = config.plugins + if (plugins && !Array.isArray(plugins)) { + expect(plugins.layerguard).toBeDefined() + } + } }) }) diff --git a/tests/unit/eslint/layer-boundaries.test.ts b/tests/unit/eslint/layer-boundaries.test.ts index 882c11c..6c51832 100644 --- a/tests/unit/eslint/layer-boundaries.test.ts +++ b/tests/unit/eslint/layer-boundaries.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import type { Rule } from 'eslint' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' // Mock dependencies before importing the rule vi.mock('../../../src/eslint/config-cache.js', () => ({ @@ -25,7 +25,7 @@ vi.mock('../../../src/config/parser.js', () => ({ })) import { getConfig } from '../../../src/eslint/config-cache.js' -import { resolveImport, createResolverContext } from '../../../src/parser/resolver.js' +import { resolveImport } from '../../../src/parser/resolver.js' import { createLayerMapper } from '../../../src/enforcer/mapper.js' import { parseFlowRules } from '../../../src/config/parser.js' import rule from '../../../src/eslint/rules/layer-boundaries.js' @@ -38,11 +38,11 @@ describe('ESLint layer-boundaries rule', () => { loc?: { start: { line: number; column: number }; end: { line: number; column: number } } }> - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { - ui: ['src/components/**/*'], - services: ['src/services/**/*'], - utils: ['src/utils/**/*'], + ui: { path: 'src/components' }, + services: { path: 'src/services' }, + utils: { path: 'src/utils' }, }, flow: ['ui -> services', 'services -> utils'], } @@ -60,11 +60,10 @@ describe('ESLint layer-boundaries rule', () => { data?: Record loc?: { start: { line: number; column: number }; end: { line: number; column: number } } } - reportedErrors.push({ - messageId: d.messageId, - data: d.data, - loc: d.loc, - }) + const error: typeof reportedErrors[number] = { messageId: d.messageId } + if (d.data) error.data = d.data + if (d.loc) error.loc = d.loc + reportedErrors.push(error) }, } as unknown as Rule.RuleContext }) @@ -95,7 +94,7 @@ describe('ESLint layer-boundaries rule', () => { it('should return empty object when source file is not in any layer', () => { vi.mocked(getConfig).mockReturnValue({ config: mockConfig, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -103,7 +102,7 @@ describe('ESLint layer-boundaries rule', () => { vi.mocked(createLayerMapper).mockReturnValue({ map: vi.fn().mockReturnValue(null), // File not in any layer layers: mockConfig.layers, - }) + } as unknown as ReturnType) vi.mocked(parseFlowRules).mockReturnValue([]) @@ -115,7 +114,7 @@ describe('ESLint layer-boundaries rule', () => { it('should return listeners when source file is in a layer', () => { vi.mocked(getConfig).mockReturnValue({ config: mockConfig, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -123,7 +122,7 @@ describe('ESLint layer-boundaries rule', () => { vi.mocked(createLayerMapper).mockReturnValue({ map: vi.fn().mockReturnValue({ layer: 'ui', pattern: 'src/components/**/*' }), layers: mockConfig.layers, - }) + } as unknown as ReturnType) vi.mocked(parseFlowRules).mockReturnValue([ { from: 'ui', to: 'services', direction: 'unidirectional' }, @@ -141,7 +140,7 @@ describe('ESLint layer-boundaries rule', () => { beforeEach(() => { vi.mocked(getConfig).mockReturnValue({ config: mockConfig, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -162,8 +161,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../services/user', resolvedPath: 'C:/project/src/services/user.ts', isExternal: false, isUnresolved: false, @@ -199,8 +199,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../components/Button', resolvedPath: 'C:/project/src/components/Button.tsx', isExternal: false, isUnresolved: false, @@ -217,9 +218,9 @@ describe('ESLint layer-boundaries rule', () => { listeners.ImportDeclaration?.(importNode as unknown as Parameters['ImportDeclaration']>>[0]) expect(reportedErrors).toHaveLength(1) - expect(reportedErrors[0].messageId).toBe('violation') - expect(reportedErrors[0].data?.fromLayer).toBe('services') - expect(reportedErrors[0].data?.toLayer).toBe('ui') + expect(reportedErrors[0]!.messageId).toBe('violation') + expect(reportedErrors[0]!.data?.fromLayer).toBe('services') + expect(reportedErrors[0]!.data?.toLayer).toBe('ui') }) it('should not report for external imports', () => { @@ -228,8 +229,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: 'react', resolvedPath: null, isExternal: true, isUnresolved: false, @@ -254,8 +256,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: './Input', resolvedPath: 'C:/project/src/components/Input.tsx', isExternal: false, isUnresolved: false, @@ -291,8 +294,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../components/Button', resolvedPath: 'C:/project/src/components/Button.tsx', isExternal: false, isUnresolved: false, @@ -313,7 +317,7 @@ describe('ESLint layer-boundaries rule', () => { listeners.CallExpression?.(callNode as unknown as Parameters['CallExpression']>>[0]) expect(reportedErrors).toHaveLength(1) - expect(reportedErrors[0].messageId).toBe('violation') + expect(reportedErrors[0]!.messageId).toBe('violation') }) it('should handle dynamic imports', () => { @@ -333,8 +337,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../components/Button', resolvedPath: 'C:/project/src/components/Button.tsx', isExternal: false, isUnresolved: false, @@ -352,7 +357,7 @@ describe('ESLint layer-boundaries rule', () => { listeners.ImportExpression?.(importExprNode as unknown as Parameters['ImportExpression']>>[0]) expect(reportedErrors).toHaveLength(1) - expect(reportedErrors[0].messageId).toBe('violation') + expect(reportedErrors[0]!.messageId).toBe('violation') }) it('should handle bidirectional flow rules', () => { @@ -376,8 +381,9 @@ describe('ESLint layer-boundaries rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../components/Button', resolvedPath: 'C:/project/src/components/Button.tsx', isExternal: false, isUnresolved: false, diff --git a/tests/unit/eslint/unlayered-imports.test.ts b/tests/unit/eslint/unlayered-imports.test.ts index 85fb82c..c11f322 100644 --- a/tests/unit/eslint/unlayered-imports.test.ts +++ b/tests/unit/eslint/unlayered-imports.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import type { Rule } from 'eslint' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' // Mock dependencies before importing the rule vi.mock('../../../src/eslint/config-cache.js', () => ({ @@ -21,7 +21,7 @@ vi.mock('../../../src/enforcer/mapper.js', () => ({ })) import { getConfig } from '../../../src/eslint/config-cache.js' -import { resolveImport, createResolverContext } from '../../../src/parser/resolver.js' +import { resolveImport } from '../../../src/parser/resolver.js' import { createLayerMapper } from '../../../src/enforcer/mapper.js' import rule from '../../../src/eslint/rules/unlayered-imports.js' @@ -33,10 +33,10 @@ describe('ESLint unlayered-imports rule', () => { loc?: { start: { line: number; column: number }; end: { line: number; column: number } } }> - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { - ui: ['src/components/**/*'], - services: ['src/services/**/*'], + ui: { path: 'src/components' }, + services: { path: 'src/services' }, }, flow: ['ui -> services'], rules: { @@ -57,11 +57,10 @@ describe('ESLint unlayered-imports rule', () => { data?: Record loc?: { start: { line: number; column: number }; end: { line: number; column: number } } } - reportedErrors.push({ - messageId: d.messageId, - data: d.data, - loc: d.loc, - }) + const error: typeof reportedErrors[number] = { messageId: d.messageId } + if (d.data) error.data = d.data + if (d.loc) error.loc = d.loc + reportedErrors.push(error) }, } as unknown as Rule.RuleContext }) @@ -90,14 +89,14 @@ describe('ESLint unlayered-imports rule', () => { }) it('should return empty object when unlayeredImports is set to ignore', () => { - const configWithIgnore: ArchgateConfig = { + const configWithIgnore: LayerguardConfig = { ...mockConfig, rules: { unlayeredImports: 'ignore' }, } vi.mocked(getConfig).mockReturnValue({ config: configWithIgnore, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -105,7 +104,7 @@ describe('ESLint unlayered-imports rule', () => { vi.mocked(createLayerMapper).mockReturnValue({ map: vi.fn().mockReturnValue({ layer: 'ui', pattern: 'src/components/**/*' }), layers: mockConfig.layers, - }) + } as unknown as ReturnType) const listeners = rule.create(mockContext) @@ -115,7 +114,7 @@ describe('ESLint unlayered-imports rule', () => { it('should return empty object when source file is not in any layer', () => { vi.mocked(getConfig).mockReturnValue({ config: mockConfig, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -123,7 +122,7 @@ describe('ESLint unlayered-imports rule', () => { vi.mocked(createLayerMapper).mockReturnValue({ map: vi.fn().mockReturnValue(null), // File not in any layer layers: mockConfig.layers, - }) + } as unknown as ReturnType) const listeners = rule.create(mockContext) @@ -133,7 +132,7 @@ describe('ESLint unlayered-imports rule', () => { it('should return listeners when source file is in a layer and rule is enabled', () => { vi.mocked(getConfig).mockReturnValue({ config: mockConfig, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -141,7 +140,7 @@ describe('ESLint unlayered-imports rule', () => { vi.mocked(createLayerMapper).mockReturnValue({ map: vi.fn().mockReturnValue({ layer: 'ui', pattern: 'src/components/**/*' }), layers: mockConfig.layers, - }) + } as unknown as ReturnType) const listeners = rule.create(mockContext) @@ -155,7 +154,7 @@ describe('ESLint unlayered-imports rule', () => { beforeEach(() => { vi.mocked(getConfig).mockReturnValue({ config: mockConfig, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -171,8 +170,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../helpers/format', resolvedPath: 'C:/project/src/helpers/format.ts', isExternal: false, isUnresolved: false, @@ -189,9 +189,9 @@ describe('ESLint unlayered-imports rule', () => { listeners.ImportDeclaration?.(importNode as unknown as Parameters['ImportDeclaration']>>[0]) expect(reportedErrors).toHaveLength(1) - expect(reportedErrors[0].messageId).toBe('unlayeredImport') - expect(reportedErrors[0].data?.importPath).toBe('../helpers/format') - expect(reportedErrors[0].data?.targetPath).toContain('helpers/format') + expect(reportedErrors[0]!.messageId).toBe('unlayeredImport') + expect(reportedErrors[0]!.data?.importPath).toBe('../helpers/format') + expect(reportedErrors[0]!.data?.targetPath).toContain('helpers/format') }) it('should not report when importing from layered file', () => { @@ -204,8 +204,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../services/user', resolvedPath: 'C:/project/src/services/user.ts', isExternal: false, isUnresolved: false, @@ -230,8 +231,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: 'react', resolvedPath: null, isExternal: true, isUnresolved: false, @@ -256,8 +258,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: './missing-file', resolvedPath: null, isExternal: false, isUnresolved: true, @@ -286,8 +289,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../helpers/format', resolvedPath: 'C:/project/src/helpers/format.ts', isExternal: false, isUnresolved: false, @@ -308,7 +312,7 @@ describe('ESLint unlayered-imports rule', () => { listeners.CallExpression?.(callNode as unknown as Parameters['CallExpression']>>[0]) expect(reportedErrors).toHaveLength(1) - expect(reportedErrors[0].messageId).toBe('unlayeredImport') + expect(reportedErrors[0]!.messageId).toBe('unlayeredImport') }) it('should handle dynamic imports', () => { @@ -321,8 +325,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../helpers/format', resolvedPath: 'C:/project/src/helpers/format.ts', isExternal: false, isUnresolved: false, @@ -340,18 +345,18 @@ describe('ESLint unlayered-imports rule', () => { listeners.ImportExpression?.(importExprNode as unknown as Parameters['ImportExpression']>>[0]) expect(reportedErrors).toHaveLength(1) - expect(reportedErrors[0].messageId).toBe('unlayeredImport') + expect(reportedErrors[0]!.messageId).toBe('unlayeredImport') }) it('should work when unlayeredImports is set to error', () => { - const configWithError: ArchgateConfig = { + const configWithError: LayerguardConfig = { ...mockConfig, rules: { unlayeredImports: 'error' }, } vi.mocked(getConfig).mockReturnValue({ config: configWithError, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -365,8 +370,9 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) vi.mocked(resolveImport).mockReturnValue({ + specifier: '../helpers/format', resolvedPath: 'C:/project/src/helpers/format.ts', isExternal: false, isUnresolved: false, @@ -391,7 +397,7 @@ describe('ESLint unlayered-imports rule', () => { layers: mockConfig.layers, } - vi.mocked(createLayerMapper).mockReturnValue(mockMapper) + vi.mocked(createLayerMapper).mockReturnValue(mockMapper as unknown as ReturnType) const listeners = rule.create(mockContext) @@ -414,7 +420,7 @@ describe('ESLint unlayered-imports rule', () => { describe('rule not enabled by default', () => { it('should return empty object when no rules config is set', () => { - const configWithoutRules: ArchgateConfig = { + const configWithoutRules: LayerguardConfig = { layers: mockConfig.layers, flow: mockConfig.flow, // No rules property @@ -422,7 +428,7 @@ describe('ESLint unlayered-imports rule', () => { vi.mocked(getConfig).mockReturnValue({ config: configWithoutRules, - configPath: 'C:/project/archgate.config.ts', + configPath: 'C:/project/layerguard.config.ts', projectRoot: 'C:/project', loadedAt: Date.now(), }) @@ -430,7 +436,7 @@ describe('ESLint unlayered-imports rule', () => { vi.mocked(createLayerMapper).mockReturnValue({ map: vi.fn().mockReturnValue({ layer: 'ui', pattern: 'src/components/**/*' }), layers: mockConfig.layers, - }) + } as unknown as ReturnType) const listeners = rule.create(mockContext) diff --git a/tests/unit/output/diagram.test.ts b/tests/unit/output/diagram.test.ts index 3684d49..4994219 100644 --- a/tests/unit/output/diagram.test.ts +++ b/tests/unit/output/diagram.test.ts @@ -1,9 +1,9 @@ import { describe, it, expect } from 'vitest' import { generateDiagram, generateFlowSummary } from '../../../src/output/diagram.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' describe('generateDiagram', () => { - const basicConfig: ArchgateConfig = { + const basicConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -15,7 +15,7 @@ describe('generateDiagram', () => { it('generates a diagram with title', () => { const output = generateDiagram(basicConfig) - expect(output).toContain('Archgate Architecture') + expect(output).toContain('Layerguard Architecture') }) it('generates boxes for each layer', () => { @@ -76,7 +76,7 @@ describe('generateDiagram', () => { }) it('shows sublayers when present', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -97,7 +97,7 @@ describe('generateDiagram', () => { }) it('hides sublayers when showSublayers is false', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -118,7 +118,7 @@ describe('generateDiagram', () => { }) it('shows sublayer flow rules when present', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -138,7 +138,7 @@ describe('generateDiagram', () => { }) it('orders layers by dependency count', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { utils: { path: 'src/utils' }, hooks: { path: 'src/hooks' }, @@ -160,7 +160,7 @@ describe('generateDiagram', () => { describe('generateFlowSummary', () => { it('generates a flow summary', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' }, hooks: { path: 'src/hooks' }, @@ -177,7 +177,7 @@ describe('generateFlowSummary', () => { }) it('includes sublayer flows', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components', @@ -198,7 +198,7 @@ describe('generateFlowSummary', () => { }) it('handles empty flow rules', () => { - const config: ArchgateConfig = { + const config: LayerguardConfig = { layers: { components: { path: 'src/components' }, }, diff --git a/tests/unit/output/github.test.ts b/tests/unit/output/github.test.ts index 7d1924d..0387405 100644 --- a/tests/unit/output/github.test.ts +++ b/tests/unit/output/github.test.ts @@ -18,6 +18,7 @@ function createMockReport(violations: Violation[] = []): ViolationReport { circular: 0, unmapped: 0, unlayered: 0, + orphan: 0, depth: 0, publicApi: 0, dependentBudget: 0, @@ -34,6 +35,7 @@ function createMockReport(violations: Violation[] = []): ViolationReport { if (v.type === 'circular') counts.circular++ if (v.type === 'unmapped') counts.unmapped++ if (v.type === 'unlayered') counts.unlayered++ + if (v.type === 'orphan') counts.orphan++ if (v.type === 'depth') counts.depth++ if (v.type === 'publicApi') counts.publicApi++ if (v.type === 'dependentBudget') counts.dependentBudget++ @@ -73,7 +75,7 @@ describe('generatePrCommentBody', () => { const report = createMockReport([]) const body = generatePrCommentBody(report) - expect(body).toContain('## Archgate Architecture Check') + expect(body).toContain('## Layerguard Architecture Check') expect(body).toContain('✅ Passed') }) @@ -147,12 +149,12 @@ describe('generatePrCommentBody', () => { expect(body).toContain('Workflow: CI Pipeline') }) - it('includes archgate footer', () => { + it('includes layerguard footer', () => { const report = createMockReport([]) const body = generatePrCommentBody(report) expect(body).toContain('Generated by') - expect(body).toContain('Archgate') + expect(body).toContain('Layerguard') }) it('shows "and X more" for many violations', () => { @@ -190,6 +192,7 @@ describe('detectPrNumber', () => { }) it('detects PR number from GITHUB_REF', () => { + delete process.env.GITHUB_EVENT_PATH process.env.GITHUB_REF = 'refs/pull/123/merge' const prNumber = detectPrNumber() @@ -198,6 +201,7 @@ describe('detectPrNumber', () => { }) it('handles non-PR GITHUB_REF', () => { + delete process.env.GITHUB_EVENT_PATH process.env.GITHUB_REF = 'refs/heads/main' const prNumber = detectPrNumber() diff --git a/tests/unit/output/html.test.ts b/tests/unit/output/html.test.ts index 0fb842a..4fc7150 100644 --- a/tests/unit/output/html.test.ts +++ b/tests/unit/output/html.test.ts @@ -19,6 +19,7 @@ function createMockReport(violations: Violation[] = []): ViolationReport { circular: 0, unmapped: 0, unlayered: 0, + orphan: 0, depth: 0, publicApi: 0, dependentBudget: 0, @@ -35,6 +36,7 @@ function createMockReport(violations: Violation[] = []): ViolationReport { if (v.type === 'circular') counts.circular++ if (v.type === 'unmapped') counts.unmapped++ if (v.type === 'unlayered') counts.unlayered++ + if (v.type === 'orphan') counts.orphan++ if (v.type === 'depth') counts.depth++ if (v.type === 'publicApi') counts.publicApi++ if (v.type === 'dependentBudget') counts.dependentBudget++ @@ -77,7 +79,7 @@ describe('generateHtmlReport', () => { expect(html).toContain('') expect(html).toContain('') - expect(html).toContain('Archgate Report') + expect(html).toContain('Layerguard Report') }) it('includes title in output', () => { @@ -149,14 +151,14 @@ describe('generateHtmlReport', () => { { timestamp: '2024-01-01T00:00:00Z', date: '2024-01-01', - counts: { flow: 5, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 5 }, + counts: { flow: 5, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, orphan: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 5 }, fileCount: 50, importCount: 200, }, { timestamp: '2024-01-02T00:00:00Z', date: '2024-01-02', - counts: { flow: 3, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 3 }, + counts: { flow: 3, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, orphan: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 3 }, fileCount: 55, importCount: 220, }, @@ -197,7 +199,7 @@ describe('generateMarkdownSummary', () => { const report = createMockReport([]) const md = generateMarkdownSummary(report) - expect(md).toContain('## Archgate Check') + expect(md).toContain('## Layerguard Check') expect(md).toContain('Passed') }) @@ -267,7 +269,7 @@ describe('generateMarkdownSummary', () => { const md = generateMarkdownSummary(report) expect(md).toContain('Generated by') - expect(md).toContain('Archgate') + expect(md).toContain('Layerguard') }) }) @@ -299,14 +301,14 @@ describe('generateTrendChartData', () => { { timestamp: '2024-01-01T00:00:00Z', date: '2024-01-01', - counts: { flow: 5, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 5 }, + counts: { flow: 5, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, orphan: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 5 }, fileCount: 50, importCount: 200, }, { timestamp: '2024-01-02T00:00:00Z', date: '2024-01-02', - counts: { flow: 3, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 3 }, + counts: { flow: 3, isolation: 0, circular: 0, unmapped: 0, unlayered: 0, orphan: 0, depth: 0, publicApi: 0, dependentBudget: 0, importCount: 0, total: 3 }, fileCount: 55, importCount: 220, }, diff --git a/tests/unit/output/terminal.test.ts b/tests/unit/output/terminal.test.ts index bbe6dbf..f553c12 100644 --- a/tests/unit/output/terminal.test.ts +++ b/tests/unit/output/terminal.test.ts @@ -124,7 +124,7 @@ describe('formatReport', () => { const output = formatReport(report) - expect(output).toContain('archgate check') + expect(output).toContain('layerguard check') expect(output).toContain('No violations found') expect(output).toContain('✓') }) @@ -146,7 +146,7 @@ describe('formatReport', () => { const output = formatReport(report) - expect(output).toContain('archgate check') + expect(output).toContain('layerguard check') expect(output).toContain('2 violations found') expect(output).toContain('1 error') expect(output).toContain('1 warning') diff --git a/tests/unit/parser/barrel.test.ts b/tests/unit/parser/barrel.test.ts index d2105b0..3a697a0 100644 --- a/tests/unit/parser/barrel.test.ts +++ b/tests/unit/parser/barrel.test.ts @@ -2,7 +2,6 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest' import * as fs from 'node:fs' import { analyzeBarrel, - traceOrigins, resolveBarrelOrigins, clearBarrelCache, isLikelyBarrelFile, diff --git a/tests/unit/parser/extractor.test.ts b/tests/unit/parser/extractor.test.ts index b1023d2..d11b23d 100644 --- a/tests/unit/parser/extractor.test.ts +++ b/tests/unit/parser/extractor.test.ts @@ -12,7 +12,7 @@ describe('extractImports', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-extractor-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-extractor-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) diff --git a/tests/unit/parser/graph.test.ts b/tests/unit/parser/graph.test.ts index fc8bd3c..014be7f 100644 --- a/tests/unit/parser/graph.test.ts +++ b/tests/unit/parser/graph.test.ts @@ -14,7 +14,7 @@ describe('buildDependencyGraph', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-graph-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-graph-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) mkdirSync(join(testDir, 'src'), { recursive: true }) }) @@ -163,7 +163,7 @@ describe('getDependencies', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-deps-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-deps-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) mkdirSync(join(testDir, 'src'), { recursive: true }) }) @@ -213,7 +213,7 @@ describe('getDependents', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-dependents-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-dependents-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) mkdirSync(join(testDir, 'src'), { recursive: true }) }) @@ -252,7 +252,7 @@ describe('getGraphStats', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-stats-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-stats-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) mkdirSync(join(testDir, 'src'), { recursive: true }) }) diff --git a/tests/unit/parser/incremental.test.ts b/tests/unit/parser/incremental.test.ts index 919f4fe..3eaf0e8 100644 --- a/tests/unit/parser/incremental.test.ts +++ b/tests/unit/parser/incremental.test.ts @@ -6,7 +6,7 @@ import * as resolver from '../../../src/parser/resolver.js' import * as cacheManager from '../../../src/cache/manager.js' import { CACHE_VERSION } from '../../../src/cache/types.js' import type { CacheData } from '../../../src/cache/types.js' -import type { ArchgateConfig } from '../../../src/config/types.js' +import type { LayerguardConfig } from '../../../src/config/types.js' vi.mock('../../../src/parser/scanner.js') vi.mock('../../../src/parser/extractor.js') @@ -14,7 +14,7 @@ vi.mock('../../../src/parser/resolver.js') vi.mock('../../../src/cache/manager.js') describe('buildDependencyGraphIncremental', () => { - const mockConfig: ArchgateConfig = { + const mockConfig: LayerguardConfig = { layers: { components: { path: 'src/components' }, utils: { path: 'src/utils' }, diff --git a/tests/unit/parser/resolver.test.ts b/tests/unit/parser/resolver.test.ts index 508310c..4689396 100644 --- a/tests/unit/parser/resolver.test.ts +++ b/tests/unit/parser/resolver.test.ts @@ -36,7 +36,7 @@ describe('resolveImport', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-resolver-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-resolver-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) mkdirSync(join(testDir, 'src'), { recursive: true }) }) @@ -150,7 +150,7 @@ describe('createResolverContext', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-context-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-context-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) @@ -229,7 +229,7 @@ describe('multi-tsconfig support', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-multi-tsconfig-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-multi-tsconfig-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) @@ -311,7 +311,7 @@ describe('project references', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-proj-refs-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-proj-refs-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) diff --git a/tests/unit/parser/scanner.test.ts b/tests/unit/parser/scanner.test.ts index 9c36b54..7f113de 100644 --- a/tests/unit/parser/scanner.test.ts +++ b/tests/unit/parser/scanner.test.ts @@ -8,7 +8,7 @@ describe('scanDirectory', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-scanner-test-${Date.now()}`) + testDir = join(tmpdir(), `layerguard-scanner-test-${Date.now()}`) mkdirSync(testDir, { recursive: true }) }) @@ -164,7 +164,7 @@ describe('getRelativePath', () => { expect(getRelativePath(root, file)).toBe('src/index.ts') }) - it('handles Windows paths', () => { + it.skipIf(process.platform !== 'win32')('handles Windows paths', () => { const root = 'C:\\project' const file = 'C:\\project\\src\\index.ts' diff --git a/tests/unit/workspace/configs.test.ts b/tests/unit/workspace/configs.test.ts index 45a4568..879916e 100644 --- a/tests/unit/workspace/configs.test.ts +++ b/tests/unit/workspace/configs.test.ts @@ -17,7 +17,7 @@ describe('workspace/configs', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-cfg-test-${Date.now()}-${Math.random().toString(36).slice(2)}`) + testDir = join(tmpdir(), `layerguard-cfg-test-${Date.now()}-${Math.random().toString(36).slice(2)}`) mkdirSync(testDir, { recursive: true }) }) @@ -26,25 +26,25 @@ describe('workspace/configs', () => { }) describe('discoverPackageConfigs', () => { - it('finds archgate configs in workspace packages', () => { + it('finds layerguard configs in workspace packages', () => { // Setup workspace writeFileSync( join(testDir, 'package.json'), JSON.stringify({ workspaces: ['packages/*'] }) ) - // Create package with archgate config + // Create package with layerguard config const pkgDir = join(testDir, 'packages', 'app') mkdirSync(pkgDir, { recursive: true }) writeFileSync(join(pkgDir, 'package.json'), JSON.stringify({ name: '@my/app' })) - writeFileSync(join(pkgDir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(pkgDir, 'layerguard.config.ts'), 'export default {}') const workspace = detectWorkspace(testDir) const discovery = discoverPackageConfigs(workspace) expect(discovery.packageConfigs).toHaveLength(1) expect(discovery.packageConfigs[0]?.package.name).toBe('@my/app') - expect(discovery.packageConfigs[0]?.configPath).toContain('archgate.config.ts') + expect(discovery.packageConfigs[0]?.configPath).toContain('layerguard.config.ts') }) it('finds root config', () => { @@ -52,7 +52,7 @@ describe('workspace/configs', () => { join(testDir, 'package.json'), JSON.stringify({ workspaces: ['packages/*'] }) ) - writeFileSync(join(testDir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(testDir, 'layerguard.config.ts'), 'export default {}') const workspace = detectWorkspace(testDir) const discovery = discoverPackageConfigs(workspace) @@ -61,7 +61,7 @@ describe('workspace/configs', () => { expect(discovery.rootConfig?.package.name).toBe('root') }) - it('handles packages without archgate config', () => { + it('handles packages without layerguard config', () => { writeFileSync( join(testDir, 'package.json'), JSON.stringify({ workspaces: ['packages/*'] }) @@ -71,7 +71,7 @@ describe('workspace/configs', () => { const pkg1Dir = join(testDir, 'packages', 'with-config') mkdirSync(pkg1Dir, { recursive: true }) writeFileSync(join(pkg1Dir, 'package.json'), JSON.stringify({ name: 'with-config' })) - writeFileSync(join(pkg1Dir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(pkg1Dir, 'layerguard.config.ts'), 'export default {}') const pkg2Dir = join(testDir, 'packages', 'no-config') mkdirSync(pkg2Dir, { recursive: true }) @@ -90,17 +90,17 @@ describe('workspace/configs', () => { JSON.stringify({ workspaces: ['packages/*'] }) ) - // Package with .archgaterc.ts + // Package with .layerguardrc.ts const pkg1Dir = join(testDir, 'packages', 'pkg1') mkdirSync(pkg1Dir, { recursive: true }) writeFileSync(join(pkg1Dir, 'package.json'), JSON.stringify({ name: 'pkg1' })) - writeFileSync(join(pkg1Dir, '.archgaterc.ts'), 'export default {}') + writeFileSync(join(pkg1Dir, '.layerguardrc.ts'), 'export default {}') - // Package with archgate.config.js + // Package with layerguard.config.js const pkg2Dir = join(testDir, 'packages', 'pkg2') mkdirSync(pkg2Dir, { recursive: true }) writeFileSync(join(pkg2Dir, 'package.json'), JSON.stringify({ name: 'pkg2' })) - writeFileSync(join(pkg2Dir, 'archgate.config.js'), 'export default {}') + writeFileSync(join(pkg2Dir, 'layerguard.config.js'), 'export default {}') const workspace = detectWorkspace(testDir) const discovery = discoverPackageConfigs(workspace) @@ -119,7 +119,7 @@ describe('workspace/configs', () => { const pkgDir = join(testDir, 'packages', 'utils') mkdirSync(pkgDir, { recursive: true }) writeFileSync(join(pkgDir, 'package.json'), JSON.stringify({ name: '@scope/utils' })) - writeFileSync(join(pkgDir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(pkgDir, 'layerguard.config.ts'), 'export default {}') const workspace = detectWorkspace(testDir) const discovery = discoverPackageConfigs(workspace) @@ -138,7 +138,7 @@ describe('workspace/configs', () => { const pkgDir = join(testDir, 'packages', 'my-app') mkdirSync(pkgDir, { recursive: true }) writeFileSync(join(pkgDir, 'package.json'), JSON.stringify({ name: 'my-app' })) - writeFileSync(join(pkgDir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(pkgDir, 'layerguard.config.ts'), 'export default {}') const workspace = detectWorkspace(testDir) const discovery = discoverPackageConfigs(workspace) @@ -157,7 +157,7 @@ describe('workspace/configs', () => { const pkgDir = join(testDir, 'apps', 'web') mkdirSync(pkgDir, { recursive: true }) writeFileSync(join(pkgDir, 'package.json'), JSON.stringify({ name: '@app/web' })) - writeFileSync(join(pkgDir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(pkgDir, 'layerguard.config.ts'), 'export default {}') const workspace = detectWorkspace(testDir) const discovery = discoverPackageConfigs(workspace) @@ -193,7 +193,7 @@ describe('workspace/configs', () => { const pkgDir = join(testDir, 'packages', name) mkdirSync(pkgDir, { recursive: true }) writeFileSync(join(pkgDir, 'package.json'), JSON.stringify({ name })) - writeFileSync(join(pkgDir, 'archgate.config.ts'), 'export default {}') + writeFileSync(join(pkgDir, 'layerguard.config.ts'), 'export default {}') } const workspace = detectWorkspace(testDir) diff --git a/tests/unit/workspace/detector.test.ts b/tests/unit/workspace/detector.test.ts index ca093c0..c8a8eaf 100644 --- a/tests/unit/workspace/detector.test.ts +++ b/tests/unit/workspace/detector.test.ts @@ -17,7 +17,7 @@ describe('workspace/detector', () => { let testDir: string beforeEach(() => { - testDir = join(tmpdir(), `archgate-test-${Date.now()}-${Math.random().toString(36).slice(2)}`) + testDir = join(tmpdir(), `layerguard-test-${Date.now()}-${Math.random().toString(36).slice(2)}`) mkdirSync(testDir, { recursive: true }) }) diff --git a/tsconfig.json b/tsconfig.json index a18225a..82db3de 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,5 +20,5 @@ "noEmit": true }, "include": ["src/**/*", "tests/**/*", "eslint.config.ts"], - "exclude": ["node_modules", "dist"] + "exclude": ["node_modules", "dist", "tests/fixtures"] } diff --git a/vscode-extension/LICENSE b/vscode-extension/LICENSE index 712df3c..65d5531 100644 --- a/vscode-extension/LICENSE +++ b/vscode-extension/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Archgate Contributors +Copyright (c) 2024 Layerguard Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vscode-extension/README.md b/vscode-extension/README.md index 3d1b944..d44e0c3 100644 --- a/vscode-extension/README.md +++ b/vscode-extension/README.md @@ -1,4 +1,4 @@ -# Archgate for VS Code +# Layerguard for VS Code Enforce architectural layer boundaries directly in your editor. Get instant feedback when code violates your architecture rules. @@ -18,44 +18,44 @@ Access from the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`): | Command | Description | |---------|-------------| -| `Archgate: Show Architecture` | Open the architecture panel | -| `Archgate: Check Project` | Run a full project check | -| `Archgate: Refresh Diagnostics` | Refresh all diagnostics | +| `Layerguard: Show Architecture` | Open the architecture panel | +| `Layerguard: Check Project` | Run a full project check | +| `Layerguard: Refresh Diagnostics` | Refresh all diagnostics | ## Requirements -- An `archgate.config.ts` file in your project root +- A `layerguard.config.ts` file in your project root - Node.js 18.0.0 or higher If you don't have a config file yet, install the CLI and run the setup wizard: ```bash -npm install --save-dev archgate -npx archgate init +npm install --save-dev layerguard +npx layerguard init ``` ## Extension Settings | Setting | Default | Description | |---------|---------|-------------| -| `archgate.enable` | `true` | Enable/disable Archgate diagnostics | -| `archgate.validateOnSave` | `true` | Validate architecture when files are saved | -| `archgate.validateOnType` | `false` | Validate while typing (may impact performance) | -| `archgate.showDecorations` | `true` | Show layer decorations in the file explorer | +| `layerguard.enable` | `true` | Enable/disable Layerguard diagnostics | +| `layerguard.validateOnSave` | `true` | Validate architecture when files are saved | +| `layerguard.validateOnType` | `false` | Validate while typing (may impact performance) | +| `layerguard.showDecorations` | `true` | Show layer decorations in the file explorer | ## How It Works -1. The extension reads your `archgate.config.ts` configuration +1. The extension reads your `layerguard.config.ts` configuration 2. As you edit files, it analyzes import statements 3. Imports that violate layer boundaries are highlighted 4. Hover over violations to see which rule was broken ## Configuration -Configure your architecture in `archgate.config.ts`: +Configure your architecture in `layerguard.config.ts`: ```typescript -import { defineConfig } from 'archgate' +import { defineConfig } from 'layerguard' export default defineConfig({ layers: { @@ -74,25 +74,25 @@ export default defineConfig({ }) ``` -See the [full documentation](https://github.com/caprado/archgate) for all configuration options. +See the [full documentation](https://github.com/caprado/layerguard) for all configuration options. ## Troubleshooting **Diagnostics not appearing?** -- Ensure `archgate.config.ts` exists in your workspace root -- Check that `archgate.enable` is set to `true` -- Run `Archgate: Refresh Diagnostics` from the Command Palette +- Ensure `layerguard.config.ts` exists in your workspace root +- Check that `layerguard.enable` is set to `true` +- Run `Layerguard: Refresh Diagnostics` from the Command Palette **Performance issues?** -- Disable `archgate.validateOnType` (enabled can cause lag on large files) +- Disable `layerguard.validateOnType` (enabled can cause lag on large files) - The extension caches results, so the first check may be slower ## Links -- [Archgate CLI & Documentation](https://github.com/caprado/archgate) -- [Report Issues](https://github.com/caprado/archgate/issues) -- [npm Package](https://www.npmjs.com/package/archgate) +- [Layerguard CLI & Documentation](https://github.com/caprado/layerguard) +- [Report Issues](https://github.com/caprado/layerguard/issues) +- [npm Package](https://www.npmjs.com/package/layerguard) ## License -[MIT](https://github.com/caprado/archgate/blob/main/LICENSE) +[MIT](https://github.com/caprado/layerguard/blob/main/LICENSE) diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 9b21c3f..0adec83 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -1,13 +1,13 @@ { - "name": "archgate-vscode", - "displayName": "Archgate", + "name": "layerguard-vscode", + "displayName": "Layerguard", "description": "Enforce architectural layer boundaries in TypeScript/JavaScript projects", "version": "0.1.0", - "publisher": "archgate", + "publisher": "layerguard", "license": "MIT", "repository": { "type": "git", - "url": "https://github.com/caprado/archgate" + "url": "https://github.com/caprado/layerguard" }, "engines": { "vscode": "^1.85.0" @@ -26,55 +26,55 @@ ], "activationEvents": [ "onStartupFinished", - "onView:archgateArchitecture" + "onView:layerguardArchitecture" ], "main": "./dist/extension.js", "contributes": { "commands": [ { - "command": "archgate.showArchitecture", + "command": "layerguard.showArchitecture", "title": "Show Architecture", - "category": "Archgate" + "category": "Layerguard" }, { - "command": "archgate.checkProject", + "command": "layerguard.checkProject", "title": "Check Project", - "category": "Archgate" + "category": "Layerguard" }, { - "command": "archgate.refreshDiagnostics", + "command": "layerguard.refreshDiagnostics", "title": "Refresh Diagnostics", - "category": "Archgate" + "category": "Layerguard" } ], "views": { "explorer": [ { - "id": "archgateArchitecture", + "id": "layerguardArchitecture", "name": "Architecture", "type": "webview" } ] }, "configuration": { - "title": "Archgate", + "title": "Layerguard", "properties": { - "archgate.enable": { + "layerguard.enable": { "type": "boolean", "default": true, - "description": "Enable Archgate diagnostics" + "description": "Enable Layerguard diagnostics" }, - "archgate.showDecorations": { + "layerguard.showDecorations": { "type": "boolean", "default": true, "description": "Show layer decorations in file explorer" }, - "archgate.validateOnSave": { + "layerguard.validateOnSave": { "type": "boolean", "default": true, "description": "Validate architecture on file save" }, - "archgate.validateOnType": { + "layerguard.validateOnType": { "type": "boolean", "default": false, "description": "Validate architecture while typing (may impact performance)" @@ -84,10 +84,10 @@ "menus": { "commandPalette": [ { - "command": "archgate.showArchitecture" + "command": "layerguard.showArchitecture" }, { - "command": "archgate.checkProject" + "command": "layerguard.checkProject" } ] } @@ -105,7 +105,7 @@ "@types/node": "^25.3.3", "@types/vscode": "^1.85.0", "@vscode/vsce": "^3.7.1", - "archgate": "file:..", + "layerguard": "file:..", "esbuild": "^0.27.3", "typescript": "^5.3.0" }, diff --git a/vscode-extension/pnpm-lock.yaml b/vscode-extension/pnpm-lock.yaml index f82c724..9e8d344 100644 --- a/vscode-extension/pnpm-lock.yaml +++ b/vscode-extension/pnpm-lock.yaml @@ -21,12 +21,12 @@ importers: '@vscode/vsce': specifier: ^3.7.1 version: 3.7.1 - archgate: - specifier: file:.. - version: file:..(typescript@5.9.3) esbuild: specifier: ^0.27.3 version: 0.27.3 + layerguard: + specifier: file:.. + version: file:..(typescript@5.9.3) typescript: specifier: ^5.3.0 version: 5.9.3 @@ -425,17 +425,6 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - archgate@file:..: - resolution: {directory: .., type: directory} - engines: {node: '>=18.0.0'} - hasBin: true - peerDependencies: - eslint: '>=10.0.2' - typescript: '>=4.7.0' - peerDependenciesMeta: - eslint: - optional: true - argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -871,6 +860,17 @@ packages: keytar@7.9.0: resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} + layerguard@file:..: + resolution: {directory: .., type: directory} + engines: {node: '>=18.0.0'} + hasBin: true + peerDependencies: + eslint: '>=10.0.2' + typescript: '>=4.7.0' + peerDependenciesMeta: + eslint: + optional: true + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -1775,12 +1775,6 @@ snapshots: dependencies: color-convert: 2.0.1 - archgate@file:..(typescript@5.9.3): - dependencies: - '@clack/prompts': 1.1.0 - jiti: 2.6.1 - typescript: 5.9.3 - argparse@2.0.1: {} astral-regex@2.0.0: {} @@ -2276,6 +2270,12 @@ snapshots: prebuild-install: 7.1.3 optional: true + layerguard@file:..(typescript@5.9.3): + dependencies: + '@clack/prompts': 1.1.0 + jiti: 2.6.1 + typescript: 5.9.3 + leven@3.1.0: {} linkify-it@5.0.0: diff --git a/vscode-extension/src/extension.ts b/vscode-extension/src/extension.ts index c0358e7..d976d5f 100644 --- a/vscode-extension/src/extension.ts +++ b/vscode-extension/src/extension.ts @@ -1,11 +1,11 @@ /** - * Archgate VS Code Extension + * Layerguard VS Code Extension * * Entry point for the extension */ import * as vscode from 'vscode' -import { getArchgateService, clearArchgateService } from './services/archgateService.js' +import { getLayerguardService, clearLayerguardService } from './services/layerguardService.js' import { DiagnosticsProvider } from './providers/diagnostics.js' import { registerHoverProvider } from './providers/hover.js' import { registerCodeActionsProvider } from './providers/codeActions.js' @@ -18,7 +18,7 @@ let architecturePanel: ArchitecturePanelProvider | undefined * Activate the extension */ export async function activate(context: vscode.ExtensionContext): Promise { - console.log('Archgate extension activating...') + console.log('Layerguard extension activating...') // Get workspace root const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath @@ -28,7 +28,7 @@ export async function activate(context: vscode.ExtensionContext): Promise } // Initialize service (don't await config load yet) - const service = getArchgateService(workspaceRoot) + const service = getLayerguardService(workspaceRoot) // Register providers IMMEDIATELY (before async config load) diagnosticsProvider = new DiagnosticsProvider(service) @@ -41,7 +41,7 @@ export async function activate(context: vscode.ExtensionContext): Promise const hasConfig = await service.loadConfiguration() // Set context for when clauses - vscode.commands.executeCommand('setContext', 'archgate.hasConfig', hasConfig) + vscode.commands.executeCommand('setContext', 'layerguard.hasConfig', hasConfig) if (hasConfig) { architecturePanel.update() @@ -49,17 +49,17 @@ export async function activate(context: vscode.ExtensionContext): Promise // Register commands context.subscriptions.push( - vscode.commands.registerCommand('archgate.showArchitecture', async () => { + vscode.commands.registerCommand('layerguard.showArchitecture', async () => { // Focus the architecture panel - await vscode.commands.executeCommand('archgateArchitecture.focus') + await vscode.commands.executeCommand('layerguardArchitecture.focus') }) ) context.subscriptions.push( - vscode.commands.registerCommand('archgate.checkProject', async () => { + vscode.commands.registerCommand('layerguard.checkProject', async () => { const result = await vscode.window.withProgress({ location: vscode.ProgressLocation.Notification, - title: 'Archgate: Checking project...', + title: 'Layerguard: Checking project...', cancellable: false, }, async () => { return await service.check() @@ -72,12 +72,12 @@ export async function activate(context: vscode.ExtensionContext): Promise // Show result if (result.passed) { vscode.window.showInformationMessage( - `Archgate: All checks passed! (${result.violations.length} warnings)` + `Layerguard: All checks passed! (${result.violations.length} warnings)` ) } else { const errorCount = result.violations.filter(v => v.severity === 'error').length vscode.window.showErrorMessage( - `Archgate: ${errorCount} errors found. Check the Problems panel for details.` + `Layerguard: ${errorCount} errors found. Check the Problems panel for details.` ) } } @@ -85,14 +85,14 @@ export async function activate(context: vscode.ExtensionContext): Promise ) context.subscriptions.push( - vscode.commands.registerCommand('archgate.refreshDiagnostics', async () => { + vscode.commands.registerCommand('layerguard.refreshDiagnostics', async () => { await diagnosticsProvider?.refreshAll() - vscode.window.showInformationMessage('Archgate: Diagnostics refreshed') + vscode.window.showInformationMessage('Layerguard: Diagnostics refreshed') }) ) context.subscriptions.push( - vscode.commands.registerCommand('archgate.suggestMove', async ( + vscode.commands.registerCommand('layerguard.suggestMove', async ( _uri: vscode.Uri, suggestedPath: string, targetLayer: string @@ -117,28 +117,28 @@ export async function activate(context: vscode.ExtensionContext): Promise // Watch for config file changes const configWatcher = vscode.workspace.createFileSystemWatcher( - '**/archgate.config.{ts,js,mjs}' + '**/layerguard.config.{ts,js,mjs}' ) configWatcher.onDidChange(async () => { await service.loadConfiguration() await diagnosticsProvider?.refreshAll() await architecturePanel?.refresh() - vscode.commands.executeCommand('setContext', 'archgate.hasConfig', service.hasConfig()) + vscode.commands.executeCommand('setContext', 'layerguard.hasConfig', service.hasConfig()) }) configWatcher.onDidCreate(async () => { await service.loadConfiguration() await diagnosticsProvider?.refreshAll() await architecturePanel?.refresh() - vscode.commands.executeCommand('setContext', 'archgate.hasConfig', service.hasConfig()) + vscode.commands.executeCommand('setContext', 'layerguard.hasConfig', service.hasConfig()) }) configWatcher.onDidDelete(async () => { - clearArchgateService() + clearLayerguardService() diagnosticsProvider?.refreshAll() await architecturePanel?.refresh() - vscode.commands.executeCommand('setContext', 'archgate.hasConfig', false) + vscode.commands.executeCommand('setContext', 'layerguard.hasConfig', false) }) context.subscriptions.push(configWatcher) @@ -148,7 +148,7 @@ export async function activate(context: vscode.ExtensionContext): Promise await diagnosticsProvider.refreshAll() } - console.log('Archgate extension activated') + console.log('Layerguard extension activated') } /** @@ -156,6 +156,6 @@ export async function activate(context: vscode.ExtensionContext): Promise */ export function deactivate(): void { diagnosticsProvider?.dispose() - clearArchgateService() - console.log('Archgate extension deactivated') + clearLayerguardService() + console.log('Layerguard extension deactivated') } diff --git a/vscode-extension/src/providers/codeActions.ts b/vscode-extension/src/providers/codeActions.ts index aaad120..b6c2def 100644 --- a/vscode-extension/src/providers/codeActions.ts +++ b/vscode-extension/src/providers/codeActions.ts @@ -6,19 +6,19 @@ import * as vscode from 'vscode' import * as path from 'path' -import type { ArchgateService } from '../services/archgateService.js' +import type { LayerguardService } from '../services/layerguardService.js' /** - * Code actions provider for archgate violations + * Code actions provider for layerguard violations */ -export class ArchgateCodeActionsProvider implements vscode.CodeActionProvider { - private service: ArchgateService +export class LayerguardCodeActionsProvider implements vscode.CodeActionProvider { + private service: LayerguardService static readonly providedCodeActionKinds = [ vscode.CodeActionKind.QuickFix, ] - constructor(service: ArchgateService) { + constructor(service: LayerguardService) { this.service = service } @@ -33,12 +33,12 @@ export class ArchgateCodeActionsProvider implements vscode.CodeActionProvider { ): vscode.CodeAction[] { const actions: vscode.CodeAction[] = [] - // Filter to archgate diagnostics - const archgateDiagnostics = context.diagnostics.filter( - d => d.source === 'archgate' + // Filter to layerguard diagnostics + const layerguardDiagnostics = context.diagnostics.filter( + d => d.source === 'layerguard' ) - for (const diagnostic of archgateDiagnostics) { + for (const diagnostic of layerguardDiagnostics) { const lineText = document.lineAt(diagnostic.range.start.line).text // Add suppress comment action @@ -83,7 +83,7 @@ export class ArchgateCodeActionsProvider implements vscode.CodeActionProvider { edit.insert( document.uri, new vscode.Position(line, 0), - `${indent}// archgate-ignore-next-line ${diagnostic.code}\n` + `${indent}// layerguard-ignore-next-line ${diagnostic.code}\n` ) action.edit = edit @@ -178,7 +178,7 @@ export class ArchgateCodeActionsProvider implements vscode.CodeActionProvider { // This is just a suggestion - actual move would need more work action.command = { - command: 'archgate.suggestMove', + command: 'layerguard.suggestMove', title: 'Suggest Move', arguments: [document.uri, suggestedPath, targetLayer] } @@ -195,9 +195,9 @@ export class ArchgateCodeActionsProvider implements vscode.CodeActionProvider { */ export function registerCodeActionsProvider( context: vscode.ExtensionContext, - service: ArchgateService -): ArchgateCodeActionsProvider { - const provider = new ArchgateCodeActionsProvider(service) + service: LayerguardService +): LayerguardCodeActionsProvider { + const provider = new LayerguardCodeActionsProvider(service) const selector: vscode.DocumentSelector = [ { language: 'typescript', scheme: 'file' }, @@ -211,7 +211,7 @@ export function registerCodeActionsProvider( selector, provider, { - providedCodeActionKinds: ArchgateCodeActionsProvider.providedCodeActionKinds + providedCodeActionKinds: LayerguardCodeActionsProvider.providedCodeActionKinds } ) ) diff --git a/vscode-extension/src/providers/diagnostics.ts b/vscode-extension/src/providers/diagnostics.ts index cd03a07..1e34fa7 100644 --- a/vscode-extension/src/providers/diagnostics.ts +++ b/vscode-extension/src/providers/diagnostics.ts @@ -6,20 +6,20 @@ import * as vscode from 'vscode' import * as path from 'path' -import type { ArchgateService } from '../services/archgateService.js' -import type { Violation } from 'archgate/enforcer' +import type { LayerguardService } from '../services/layerguardService.js' +import type { Violation } from 'layerguard/enforcer' /** - * Diagnostics provider for archgate violations + * Diagnostics provider for layerguard violations */ export class DiagnosticsProvider { private diagnosticCollection: vscode.DiagnosticCollection - private service: ArchgateService + private service: LayerguardService private disposables: vscode.Disposable[] = [] - constructor(service: ArchgateService) { + constructor(service: LayerguardService) { this.service = service - this.diagnosticCollection = vscode.languages.createDiagnosticCollection('archgate') + this.diagnosticCollection = vscode.languages.createDiagnosticCollection('layerguard') } /** @@ -29,7 +29,7 @@ export class DiagnosticsProvider { // Subscribe to document changes this.disposables.push( vscode.workspace.onDidSaveTextDocument(doc => { - const config = vscode.workspace.getConfiguration('archgate') + const config = vscode.workspace.getConfiguration('layerguard') if (config.get('validateOnSave', true)) { this.updateDiagnosticsForDocument(doc) } @@ -38,7 +38,7 @@ export class DiagnosticsProvider { this.disposables.push( vscode.workspace.onDidChangeTextDocument(event => { - const config = vscode.workspace.getConfiguration('archgate') + const config = vscode.workspace.getConfiguration('layerguard') if (config.get('validateOnType', false)) { this.updateDiagnosticsForDocument(event.document) } @@ -71,18 +71,18 @@ export class DiagnosticsProvider { * Update diagnostics for all open documents */ async refreshAll(): Promise { - console.log('Archgate: refreshAll() called') + console.log('Layerguard: refreshAll() called') // Clear all diagnostics this.diagnosticCollection.clear() // Run full check const result = await this.service.check() if (!result) { - console.log('Archgate: refreshAll() - no check result') + console.log('Layerguard: refreshAll() - no check result') return } - console.log('Archgate: refreshAll() - found', result.violations.length, 'violations') + console.log('Layerguard: refreshAll() - found', result.violations.length, 'violations') const workspaceRoot = this.service.getWorkspaceRoot() // Group violations by file @@ -111,7 +111,7 @@ export class DiagnosticsProvider { return } - const config = vscode.workspace.getConfiguration('archgate') + const config = vscode.workspace.getConfiguration('layerguard') if (!config.get('enable', true)) { this.diagnosticCollection.delete(document.uri) return @@ -119,9 +119,9 @@ export class DiagnosticsProvider { // Get violations for this file const filePath = document.uri.fsPath - console.log('Archgate: Checking file:', filePath) + console.log('Layerguard: Checking file:', filePath) const violations = await this.service.getViolationsForFile(filePath) - console.log('Archgate: Found violations:', violations.length) + console.log('Layerguard: Found violations:', violations.length) // Convert to diagnostics const diagnostics = violations.map(v => this.violationToDiagnostic(v, document)) @@ -153,7 +153,7 @@ export class DiagnosticsProvider { : vscode.DiagnosticSeverity.Warning const diagnostic = new vscode.Diagnostic(range, violation.message, severity) - diagnostic.source = 'archgate' + diagnostic.source = 'layerguard' diagnostic.code = violation.type // Add related information for target file @@ -173,7 +173,7 @@ export class DiagnosticsProvider { } /** - * Check if a document is relevant for archgate + * Check if a document is relevant for layerguard */ private isRelevantDocument(document: vscode.TextDocument): boolean { const languageIds = ['typescript', 'typescriptreact', 'javascript', 'javascriptreact'] diff --git a/vscode-extension/src/providers/hover.ts b/vscode-extension/src/providers/hover.ts index abe0542..3ea3fbb 100644 --- a/vscode-extension/src/providers/hover.ts +++ b/vscode-extension/src/providers/hover.ts @@ -6,16 +6,16 @@ import * as vscode from 'vscode' import * as path from 'path' -import type { ArchgateService } from '../services/archgateService.js' -import type { ParsedFlowRule } from 'archgate/config' +import type { LayerguardService } from '../services/layerguardService.js' +import type { ParsedFlowRule } from 'layerguard/config' /** * Hover provider for import statements */ export class LayerHoverProvider implements vscode.HoverProvider { - private service: ArchgateService + private service: LayerguardService - constructor(service: ArchgateService) { + constructor(service: LayerguardService) { this.service = service } @@ -59,7 +59,7 @@ export class LayerHoverProvider implements vscode.HoverProvider { const markdown = new vscode.MarkdownString() markdown.isTrusted = true - markdown.appendMarkdown('### Archgate Layer Info\n\n') + markdown.appendMarkdown('### Layerguard Layer Info\n\n') // Source layer if (sourceLayer) { @@ -183,7 +183,7 @@ export class LayerHoverProvider implements vscode.HoverProvider { */ export function registerHoverProvider( context: vscode.ExtensionContext, - service: ArchgateService + service: LayerguardService ): LayerHoverProvider { const provider = new LayerHoverProvider(service) diff --git a/vscode-extension/src/services/archgateService.ts b/vscode-extension/src/services/layerguardService.ts similarity index 74% rename from vscode-extension/src/services/archgateService.ts rename to vscode-extension/src/services/layerguardService.ts index de497ad..ff429f4 100644 --- a/vscode-extension/src/services/archgateService.ts +++ b/vscode-extension/src/services/layerguardService.ts @@ -1,8 +1,8 @@ /** - * Archgate Service + * Layerguard Service * - * Wraps archgate functionality for use in VS Code extension. - * Uses hybrid loading: prefers workspace-installed archgate, falls back to bundled. + * Wraps layerguard functionality for use in VS Code extension. + * Uses hybrid loading: prefers workspace-installed layerguard, falls back to bundled. */ import * as vscode from 'vscode' @@ -10,50 +10,50 @@ import * as path from 'path' import { pathToFileURL } from 'url' // Type imports (these are safe - just type definitions) -import type { ArchgateConfig, LayerConfig, ParsedFlowRule } from 'archgate/config' -import type { DependencyGraph } from 'archgate/parser' -import type { Violation, LayerMapper, ViolationSeverity } from 'archgate/enforcer' - -// Archgate module interfaces -interface ArchgateModules { - loadConfig: (cwd: string) => Promise<{ config: ArchgateConfig; configPath: string }> - validateConfig: (config: ArchgateConfig, cwd: string) => { valid: boolean; errors: Array<{ message: string }> } +import type { LayerguardConfig, LayerConfig, ParsedFlowRule } from 'layerguard/config' +import type { DependencyGraph } from 'layerguard/parser' +import type { Violation, LayerMapper, ViolationSeverity } from 'layerguard/enforcer' + +// Layerguard module interfaces +interface LayerguardModules { + loadConfig: (cwd: string) => Promise<{ config: LayerguardConfig; configPath: string }> + validateConfig: (config: LayerguardConfig, cwd: string) => { valid: boolean; errors: Array<{ message: string }> } parseFlowRules: (rules: string[]) => ParsedFlowRule[] buildDependencyGraphIncremental: (options: { projectRoot: string - config: ArchgateConfig + config: LayerguardConfig includeTypeOnlyImports?: boolean useCache?: boolean ignore?: string[] }) => { graph: DependencyGraph; cacheHit: boolean; filesParsed: number } - createFlowChecker: (config: ArchgateConfig) => { + createFlowChecker: (config: LayerguardConfig) => { checkGraph: (graph: DependencyGraph, options: Record) => Violation[] } detectCircularDependencies: (graph: DependencyGraph, severity?: ViolationSeverity) => { violations: Violation[] } - createLayerMapper: (config: ArchgateConfig) => LayerMapper + createLayerMapper: (config: LayerguardConfig) => LayerMapper getPlugin: (framework: string) => { defaultIgnorePatterns?: string[] } | undefined } -let cachedModules: ArchgateModules | undefined +let cachedModules: LayerguardModules | undefined let cachedWorkspaceRoot: string | undefined /** - * Load archgate modules - prefers workspace version, falls back to bundled + * Load layerguard modules - prefers workspace version, falls back to bundled */ -async function loadArchgateModules(workspaceRoot: string): Promise { +async function loadLayerguardModules(workspaceRoot: string): Promise { // Return cached modules if same workspace if (cachedModules && cachedWorkspaceRoot === workspaceRoot) { - console.log('Archgate: Using cached modules') + console.log('Layerguard: Using cached modules') return cachedModules } - // Try workspace-installed archgate first + // Try workspace-installed layerguard first try { - const workspaceArchgatePath = path.join(workspaceRoot, 'node_modules', 'archgate') - console.log('Archgate: Trying workspace path:', workspaceArchgatePath) + const workspaceLayerguardPath = path.join(workspaceRoot, 'node_modules', 'layerguard') + console.log('Layerguard: Trying workspace path:', workspaceLayerguardPath) // Convert to file:// URL for Windows compatibility - const baseUrl = pathToFileURL(workspaceArchgatePath).href + const baseUrl = pathToFileURL(workspaceLayerguardPath).href // Dynamic imports for workspace version const configModule = await import(`${baseUrl}/dist/config/index.js`) @@ -61,7 +61,7 @@ async function loadArchgateModules(workspaceRoot: string): Promise { try { // Load modules (workspace or bundled) - this.modules = await loadArchgateModules(this.workspaceRoot) + this.modules = await loadLayerguardModules(this.workspaceRoot) const result = await this.modules.loadConfig(this.workspaceRoot) this.config = result.config @@ -143,18 +143,18 @@ export class ArchgateService { const validation = this.modules.validateConfig(this.config, this.workspaceRoot) if (!validation.valid) { vscode.window.showErrorMessage( - `Invalid archgate config: ${validation.errors.map((e: { message: string }) => e.message).join(', ')}` + `Invalid layerguard config: ${validation.errors.map((e: { message: string }) => e.message).join(', ')}` ) return false } this.mapper = this.modules.createLayerMapper(this.config) this.parsedFlows = this.modules.parseFlowRules(this.config.flow) - console.log('Archgate: Config loaded successfully from', this.configPath) + console.log('Layerguard: Config loaded successfully from', this.configPath) return true } catch (error) { const message = error instanceof Error ? error.message : String(error) - console.error('Archgate: Failed to load config:', message) + console.error('Layerguard: Failed to load config:', message) console.error(error) this.config = undefined this.configPath = undefined @@ -182,7 +182,7 @@ export class ArchgateService { /** * Get the loaded configuration */ - getConfig(): ArchgateConfig | undefined { + getConfig(): LayerguardConfig | undefined { return this.config } @@ -224,7 +224,7 @@ export class ArchgateService { * Run a full check */ async check(): Promise { - console.log('Archgate: check() called, hasConfig:', !!this.config, 'hasModules:', !!this.modules) + console.log('Layerguard: check() called, hasConfig:', !!this.config, 'hasModules:', !!this.modules) if (!this.config || !this.modules) { return undefined } @@ -238,7 +238,7 @@ export class ArchgateService { // Build dependency graph const buildOptions: { projectRoot: string - config: ArchgateConfig + config: LayerguardConfig includeTypeOnlyImports?: boolean useCache?: boolean ignore?: string[] @@ -278,9 +278,9 @@ export class ArchgateService { const allViolations = [...flowViolations, ...circularViolations] const hasErrors = allViolations.some(v => v.severity === 'error') - console.log('Archgate: check() found', allViolations.length, 'violations') + console.log('Layerguard: check() found', allViolations.length, 'violations') if (allViolations.length > 0) { - console.log('Archgate: violation files:', allViolations.map(v => v.sourceFile)) + console.log('Layerguard: violation files:', allViolations.map(v => v.sourceFile)) } return { @@ -290,8 +290,8 @@ export class ArchgateService { } } catch (error) { const message = error instanceof Error ? error.message : String(error) - console.log('Archgate: check() error:', message) - vscode.window.showErrorMessage(`Archgate check failed: ${message}`) + console.log('Layerguard: check() error:', message) + vscode.window.showErrorMessage(`Layerguard check failed: ${message}`) return undefined } } @@ -302,15 +302,15 @@ export class ArchgateService { async getViolationsForFile(filePath: string): Promise { const result = await this.check() if (!result) { - console.log('Archgate: check() returned no result') + console.log('Layerguard: check() returned no result') return [] } // Convert absolute path to relative for comparison const relativePath = path.relative(this.workspaceRoot, filePath).replace(/\\/g, '/') - console.log('Archgate: Looking for violations in:', relativePath) - console.log('Archgate: Total violations:', result.violations.length) - console.log('Archgate: Violation files:', result.violations.map(v => v.sourceFile)) + console.log('Layerguard: Looking for violations in:', relativePath) + console.log('Layerguard: Total violations:', result.violations.length) + console.log('Layerguard: Violation files:', result.violations.map(v => v.sourceFile)) return result.violations.filter(v => v.sourceFile === relativePath) } @@ -420,14 +420,14 @@ export class ArchgateService { /** * Global service instance */ -let serviceInstance: ArchgateService | undefined +let serviceInstance: LayerguardService | undefined /** - * Get or create the archgate service + * Get or create the layerguard service */ -export function getArchgateService(workspaceRoot: string): ArchgateService { +export function getLayerguardService(workspaceRoot: string): LayerguardService { if (!serviceInstance || serviceInstance['workspaceRoot'] !== workspaceRoot) { - serviceInstance = new ArchgateService(workspaceRoot) + serviceInstance = new LayerguardService(workspaceRoot) } return serviceInstance } @@ -435,6 +435,6 @@ export function getArchgateService(workspaceRoot: string): ArchgateService { /** * Clear the service instance (for testing or workspace changes) */ -export function clearArchgateService(): void { +export function clearLayerguardService(): void { serviceInstance = undefined } diff --git a/vscode-extension/src/views/architecturePanel.ts b/vscode-extension/src/views/architecturePanel.ts index adb3d8e..47b9edd 100644 --- a/vscode-extension/src/views/architecturePanel.ts +++ b/vscode-extension/src/views/architecturePanel.ts @@ -5,16 +5,16 @@ */ import * as vscode from 'vscode' -import type { ArchgateService } from '../services/archgateService.js' +import type { LayerguardService } from '../services/layerguardService.js' export class ArchitecturePanelProvider implements vscode.WebviewViewProvider { - public static readonly viewType = 'archgateArchitecture' + public static readonly viewType = 'layerguardArchitecture' private _view?: vscode.WebviewView - private service: ArchgateService + private service: LayerguardService private currentFile?: string - constructor(service: ArchgateService, _extensionUri: vscode.Uri) { + constructor(service: LayerguardService, _extensionUri: vscode.Uri) { this.service = service } @@ -147,7 +147,7 @@ export class ArchitecturePanelProvider implements vscode.WebviewViewProvider { -

No archgate.config.ts found

+

No layerguard.config.ts found

` } @@ -155,7 +155,7 @@ export class ArchitecturePanelProvider implements vscode.WebviewViewProvider { export function registerArchitecturePanel( context: vscode.ExtensionContext, - service: ArchgateService + service: LayerguardService ): ArchitecturePanelProvider { const provider = new ArchitecturePanelProvider(service, context.extensionUri)