### Quick Start Installation and Linting Source: https://github.com/evo-community/evolution-design/blob/main/README.md Follow these steps to build the project, navigate to the examples directory, install dependencies, and run the architecture linter. ```bash npm run build cd examples/todo npm i npm run lint:architect ``` -------------------------------- ### JavaScript (ESM) Configuration File Example Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md Example of a configuration file using JavaScript with ES Module syntax. Use import to bring in functions from '@evod/core'. ```javascript import { defineConfig, abstraction } from "@evod/core"; export default defineConfig({ root: abstraction({ name: "root", children: { app: abstraction("app"), }, }), baseUrl: "./src", }); ``` -------------------------------- ### Complete Configuration Example Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/configuration.md Use this example to set up a comprehensive `evo.config.ts` file, defining the project's root abstraction, base URL, files to validate, and files to ignore. ```typescript import { defineConfig, abstraction, rule } from "@evod/core"; export default defineConfig({ root: abstraction({ name: "root", children: { app: abstraction("app"), features: abstraction("features"), shared: abstraction("shared"), }, }), baseUrl: "./src", files: ["**/*.ts", "**/*.tsx"], ignores: ["**/*.test.ts", "**/*.stories.tsx"], }); ``` -------------------------------- ### JavaScript (CommonJS) Configuration File Example Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md Example of a configuration file using JavaScript with CommonJS module syntax. Use require to import necessary functions from '@evod/core'. ```javascript const { defineConfig, abstraction } = require("@evod/core"); module.exports = defineConfig({ root: abstraction({ name: "root", children: { app: abstraction("app"), }, }), baseUrl: "./src", }); ``` -------------------------------- ### Example Usage of defineConfig Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md An example demonstrating how to use `defineConfig` with nested abstractions and various configuration properties. ```typescript import { defineConfig, abstraction } from "@evod/core"; export default defineConfig({ root: abstraction({ name: "root", children: { app: abstraction("app"), features: abstraction("features"), }, }), baseUrl: "./src", files: ["**/*.ts", "**/*.tsx"], ignores: ["**/*.test.ts"], }); ``` -------------------------------- ### TypeScript Configuration File Example Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md Example of a configuration file using TypeScript, recommended for its type safety and features. Ensure to import defineConfig, abstraction, and rule from '@evod/core'. ```typescript import { defineConfig, abstraction, rule } from "@evod/core"; export default defineConfig({ root: abstraction({ name: "root", children: { app: abstraction("app"), }, }), baseUrl: "./src", }); ``` -------------------------------- ### Example: Load Configuration Once Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md This example shows how to use `watchConfig` with `onlyOne: true` to load the configuration once and subscribe to its result. It logs the loaded config path and root abstraction name. ```typescript import { watchConfig } from "@evod/core"; import process from "node:process"; // Load once watchConfig({ cwd: process.cwd(), onlyOne: true }).subscribe({ next: ({ config, configPath }) => { console.log(`Loaded config from ${configPath}`); console.log(`Root abstraction: ${config.root.name}`); }, error: (err) => { console.error(`Config error: ${err.message}`); }, }); ``` -------------------------------- ### Example: Watch for Configuration Changes Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md This example demonstrates how to use `watchConfig` without the `onlyOne` option to continuously watch for configuration changes and log the reloaded configuration. ```typescript // Watch for changes watchConfig({ cwd: process.cwd() }).subscribe(({ config }) => { console.log("Config reloaded", config); }); ``` -------------------------------- ### Example Usage of parseDependenciesMap Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/dependencies.md Demonstrates how to use `parseDependenciesMap` to get a dependency map and then query for importers of a specific file or dependencies of a specific file. ```typescript import { watchFs, parseDependenciesMap, getFlattenFiles, } from "@evod/core"; watchFs("./src", { onlyReady: true }).subscribe(async ({ vfs }) => { const deps = await parseDependenciesMap(vfs); // Find all files that import from "app/index.ts" const importers = deps.dependencyFor["/absolute/path/to/app/index.ts"]; if (importers) { for (const importer of importers) { console.log(`${importer} imports from app/index.ts`); } } // Find all imports from "shared" const myDeps = deps.dependencies["/absolute/path/to/component.ts"]; if (myDeps) { for (const dep of myDeps) { console.log(`component.ts imports from ${dep}`); } } }); ``` -------------------------------- ### Create evo.config.ts Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md Example of a basic evo.config.ts file structure using defineConfig and abstraction. ```typescript import { defineConfig, abstraction } from "@evod/core"; export default defineConfig({ root: abstraction("root"), baseUrl: "./src", }); ``` -------------------------------- ### Complete FSD Project Configuration Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/configuration.md A comprehensive `evo.config.ts` example demonstrating Feature-Sliced Design (FSD) structure with multiple layers and rules. ```typescript import { defineConfig, abstraction, rule, type Abstraction } from "@evod/core"; import { dependenciesDirection, noUnabstractionFiles, publicAbstraction, requiredChildren, restrictCrossImports, } from "@evod/core/rules"; export default defineConfig({ root: createRoot(), baseUrl: "./src", }); function createRoot(): Abstraction { return abstraction({ name: "fsdApp", children: { app: abstraction("app", { rules: [noUnabstractionFiles()], }), features: createFeaturesLayer(), shared: abstraction("shared", { rules: [noUnabstractionFiles()], }), }, rules: [ dependenciesDirection(["app", "features", "shared"]), noUnabstractionFiles(), ], }); } function createFeaturesLayer(): Abstraction { return abstraction({ name: "features", children: { "*": createFeature(), }, rules: [restrictCrossImports(), noUnabstractionFiles()], }); } function createFeature(): Abstraction { return abstraction({ name: "feature", children: { "index.ts": abstraction("entry"), model: abstraction("model"), ui: abstraction("ui"), "*": abstraction("other"), }, rules: [ requiredChildren(["entry", "model", "ui"]), noUnabstractionFiles(), dependenciesDirection(["entry", "ui", "model", "other"]), publicAbstraction("entry"), ], }); } ``` -------------------------------- ### DependenciesMap Example Structure Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/dependencies.md Illustrates the expected structure of the `dependencies` and `dependencyFor` records within a `DependenciesMap` object. ```typescript // Example structure: { dependencies: { "/project/src/app/index.ts": new Set([ "/project/src/shared/utils.ts", "/project/src/shared/types.ts" ]), "/project/src/shared/utils.ts": new Set([]) }, dependencyFor: { "/project/src/shared/utils.ts": new Set([ "/project/src/app/index.ts", "/project/src/features/todos/index.ts" ]), "/project/src/shared/types.ts": new Set([ "/project/src/app/index.ts" ]) } } ``` -------------------------------- ### Handle ConfigurationNotFoundError Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md Catch ConfigurationNotFoundError when no evo.config.* file is found in the search path. This example uses `firstValueFrom` to get the initial configuration. ```typescript try { const result = await firstValueFrom( watchConfig({ cwd: process.cwd(), onlyOne: true }) ); } catch (err) { if (err instanceof ConfigurationNotFoundError) { console.error(`Config not found in ${process.cwd()}`); } } ``` -------------------------------- ### Example Usage of noUnabstractionFiles Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/built-in-rules.md Illustrates how to use the noUnabstractionFiles rule within an abstraction definition. This setup will report errors for files like README.md or config.ts if they are not part of any defined child abstraction. ```typescript import { abstraction, noUnabstractionFiles } from "@evod/core"; const root = abstraction({ name: "root", children: { app: abstraction("app"), features: abstraction("features"), }, rules: [noUnabstractionFiles()], }); // Reports errors for: // - src/README.md (file not in app or features) // - src/config.ts (file not in app or features) ``` -------------------------------- ### Example Usage of parseAbstractionInstance Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction-instance.md Demonstrates how to use `parseAbstractionInstance` to create a parsing function and then use it with a VfsNode obtained from `watchFs`. Results are memoized per node. ```typescript import { abstraction, parseAbstractionInstance, watchFs, } from "@evod/core"; const rootAbstraction = abstraction({ name: "root", children: { "app/*": abstraction("module"), }, }); const parseNode = parseAbstractionInstance(rootAbstraction); // Later, when you have a VfsNode from watchFs: watchFs("./src").subscribe(({ vfs }) => { const instance = parseNode(vfs); console.log(instance.path, instance.children.length); }); ``` -------------------------------- ### CLI Exit Code 1 Example Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md Demonstrates scenarios where the linter exits with code 1, such as configuration errors or validation errors. This is useful for scripting and CI/CD pipelines. ```bash $ edlint lint # Configuration not found $ echo $? 1 $ edlint lint --fail-on-warning # Warnings found $ echo $? 1 ``` -------------------------------- ### Example Usage of getAbstractionInstanceLabel Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction-instance.md Shows how `getAbstractionInstanceLabel` generates different labels based on whether the folder name matches the abstraction name. ```typescript import { getAbstractionInstanceLabel } from "@evod/core"; // If folder is "features" and abstraction name is "feature" const label = getAbstractionInstanceLabel(instance); // Returns: "features (feature)" // If folder is "feature" and abstraction name is "feature" const label = getAbstractionInstanceLabel(instance); // Returns: "feature" ``` -------------------------------- ### Monorepo Configuration Pattern Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/configuration.md Example configuration for a monorepo structure. It defines a root abstraction named 'monorepo' with nested abstractions for packages and their source directories. ```typescript export default defineConfig({ root: abstraction({ name: "monorepo", children: { "packages/*": abstraction({ name: "package", children: { src: abstraction("src"), }, }), }, }), baseUrl: "./", }); ``` -------------------------------- ### Monorepo Configuration with Evo Design Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Configure a monorepo structure with defined package dependencies and rules. This setup is useful for managing multiple related packages within a single repository. ```typescript import { defineConfig, abstraction } from "@evod/core"; import { noUnabstractionFiles, dependenciesDirection } from "@evod/core/rules"; export default defineConfig({ root: abstraction({ name: "monorepo", children: { "packages/core": createPackage("core"), "packages/ui": createPackage("ui"), "packages/cli": createPackage("cli"), }, rules: [ // cli depends on ui depends on core dependenciesDirection(["packages/cli", "packages/ui", "packages/core"]), ], }), baseUrl: "./", }); function createPackage(name) { return abstraction({ name: `package-${name}`, children: { src: abstraction("src", { children: { index: abstraction("index"), utils: abstraction("utils"), "*": abstraction("internal"), }, }), }, rules: [noUnabstractionFiles()], }); } ``` -------------------------------- ### Configure Plugin Architecture Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Define a plugin architecture using abstractions in evo.config.ts. This setup allows for decoupled modules loaded at runtime, with specific rules for inter-plugin dependencies. ```typescript import { defineConfig, abstraction } from "@evod/core"; import { noUnabstractionFiles } from "@evod/core/rules"; export default defineConfig({ root: abstraction({ name: "plugins", children: { core: abstraction("core"), "plugins/*": abstraction({ name: "plugin", children: { "index.ts": abstraction("entry"), "*": abstraction("internal"), }, rules: [noUnabstractionFiles()], }), }, rules: [ // Each plugin can import from core, but plugins cannot import from each other // (enforced through restrictCrossImports if applied to plugin layer) noUnabstractionFiles(), ], }), baseUrl: "./src", }); ``` -------------------------------- ### Validate Configuration Early Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md Implement early validation of configuration files to catch `ConfigurationInvalidError` exceptions. This prevents the linter from starting with an invalid configuration. ```typescript import { watchConfig, ConfigurationInvalidError } from "@evod/core"; async function loadConfig() { try { const result = await firstValueFrom( watchConfig({ cwd: process.cwd(), onlyOne: true }) ); return result.config; } catch (err) { if (err instanceof ConfigurationInvalidError) { console.error("Config is invalid:", err.message); process.exit(1); } throw err; } } ``` -------------------------------- ### GitHub Actions Integration for Linting Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Integrate edlint into your GitHub Actions workflow to automatically lint your code on every push or pull request. This example shows a basic linting step. ```yaml - name: Run architecture linter run: npx edlint lint ``` -------------------------------- ### Example Usage of requiredChildren Rule Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/built-in-rules.md Demonstrates how to use the `requiredChildren` rule within an abstraction definition to ensure its child components exist. This rule provides auto-fixes for missing files or folders. ```typescript import { abstraction, requiredChildren } from "@evod/core"; const feature = abstraction({ name: "feature", children: { model: abstraction("model"), ui: abstraction("ui"), "index.ts": abstraction("entry"), }, rules: [requiredChildren()], }); // This feature instance will report errors if: // - The "model" folder doesn't exist // - The "ui" folder doesn't exist // - The "index.ts" file doesn't exist ``` -------------------------------- ### Example Usage of publicAbstraction Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/built-in-rules.md Demonstrates the publicAbstraction rule to ensure imports are made through an entry point (e.g., index.ts). This prevents direct imports from internal modules like 'model' and enforces imports via the abstraction's public API. ```typescript import { abstraction, publicAbstraction } from "@evod/core"; const feature = abstraction({ name: "feature", children: { "index.ts": abstraction("entry"), model: abstraction("model"), ui: abstraction("ui"), }, rules: [publicAbstraction("entry")], }); // This prevents: // import { useModel } from "../feature/model" // // And requires: // import { useModel } from "../feature" // via index.ts ``` -------------------------------- ### Initialize New Project with edlint Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Use this command to initialize a new project with edlint. This functionality is currently a placeholder and not yet implemented. ```bash edlint init ``` -------------------------------- ### Create Starlight Project Source: https://github.com/evo-community/evolution-design/blob/main/apps/docs/README.md Use this command to create a new Astro project with the Starlight template. ```bash npm create astro@latest -- --template starlight ``` -------------------------------- ### Evo Lint CLI Options Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Use the `edlint lint` command with options to watch for changes, apply automatic fixes, or fail the build on warnings. ```bash edlint lint [OPTIONS] --watch Monitor for changes --fix Apply automatic fixes --fail-on-warning Fail if warnings found ``` -------------------------------- ### Check Configuration Validity with edlint Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md This bash script demonstrates how to create a minimal `evo.config.ts` file and then use `npx edlint lint` to validate its loading and configuration. ```bash # Create a minimal test config cat > evo.config.ts << 'EOF' import { defineConfig, abstraction } from "@evod/core"; export default defineConfig({ root: abstraction("root"), baseUrl: "./src", }); EOF # Validate it loads npx edlint lint ``` -------------------------------- ### Detect Circular Dependencies Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/dependencies.md An example function that utilizes `parseDependenciesMap` to detect circular dependencies within a project's file structure. ```typescript import { parseDependenciesMap } from "@evod/core"; async function findCycles(vfs) { const deps = await parseDependenciesMap(vfs); const visited = new Set(); const stack = new Set(); function hasCycle(file) { if (stack.has(file)) return true; if (visited.has(file)) return false; visited.add(file); stack.add(file); const fileDeps = deps.dependencies[file] || new Set(); for (const dep of fileDeps) { if (hasCycle(dep)) return true; } stack.delete(file); return false; } const allFiles = Object.keys(deps.dependencies); const cyclic = allFiles.filter(hasCycle); return cyclic; } ``` -------------------------------- ### abstraction() - Overload 1: String + Options Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction.md Creates an Abstraction instance using a name string and optional configuration object. ```APIDOC ## abstraction(name: string, optionalConfig?: Omit) ### Description Creates an `Abstraction` instance that defines a named architectural layer or component with child patterns, associated rules, and optional fractal reuse. ### Parameters #### Path Parameters - **name** (string) - Required - Name of the abstraction - **optionalConfig** (Omit) - Optional - Additional configuration ### Return Type Returns an `Abstraction` object representing the architectural definition. ``` -------------------------------- ### abstraction() - Overload 2: Configuration Object Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction.md Creates an Abstraction instance using a full configuration object. ```APIDOC ## abstraction(config: AbstractionOptions) ### Description Creates an `Abstraction` instance that defines a named architectural layer or component with child patterns, associated rules, and optional fractal reuse. ### Parameters #### Path Parameters - **config** (AbstractionOptions) - Required - Full abstraction configuration object ### Return Type Returns an `Abstraction` object representing the architectural definition. ``` -------------------------------- ### Development Workflow: Basic Linting Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Run edlint once to check the current state of your codebase for architectural violations. This is useful for an initial assessment. ```bash # Run once to check current state edlint lint ``` -------------------------------- ### rule() - Overload 2: Configuration Object Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/rule.md Creates a rule with full configuration, including custom severity, description URL, and a check function. ```APIDOC ## rule(options: RuleOptions) ### Description Creates a rule with full configuration, allowing customization of name, severity, description URL, and the check function. ### Parameters #### Path Parameters - **options** (RuleOptions) - Required - Rule configuration object ### Return Type Returns a `Rule` object. ### Example ```typescript import { rule } from "@evod/core"; const noEmptyFolders = rule({ name: "no-empty-folders", severity: "warn", check: ({ instance, root }) => { const diagnostics = []; if (instance.childNodes.length === 0 && instance.children.length === 0) { diagnostics.push({ message: "Abstraction is empty", location: { path: instance.path }, }); } return { diagnostics }; }, }); const noCyclicDeps = rule({ name: "no-cyclic-dependencies", severity: "error", descriptionUrl: "https://docs.example.com/rules/cyclic", check: async ({ instance, dependenciesMap, root }) => { const diagnostics = []; // Check for cycles in dependenciesMap return { diagnostics }; }, }); ``` ``` -------------------------------- ### Project Structure Overview Source: https://github.com/evo-community/evolution-design/blob/main/apps/docs/README.md This is the typical directory structure for an Astro + Starlight project. Starlight content resides in `src/content/docs/`. ```bash . ├── public/ ├── src/ │ ├── assets/ │ ├── content/ │ │ ├── docs/ │ │ └── config.ts │ └── env.d.ts ├── astro.config.mjs ├── package.json └── tsconfig.json ``` -------------------------------- ### GitHub Actions for Linting and Auto-fixing Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Configure GitHub Actions to automatically lint and fix code violations. This setup includes committing and pushing fixes if linting fails. ```yaml - name: Lint and fix run: npx edlint lint --fix - name: Commit fixes if: failure() run: | git add -A git commit -m "chore: fix architecture violations" git push ``` -------------------------------- ### Export File System Utilities from @evod/core Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Exports utilities for interacting with the virtual file system, such as watching for changes and retrieving file nodes. Useful for tools that need to analyze or manipulate project files. ```typescript export { watchFs, getFlattenFiles, getNodesRecord, type VfsNode }; ``` -------------------------------- ### Type-Safe Configuration with defineConfig Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/configuration.md Utilize `defineConfig` and `EvolutionConfig` for full TypeScript inference and validation of configuration options. Import necessary types from `@evod/core`. ```typescript import { defineConfig, type EvolutionConfig } from "@evod/core"; const config: EvolutionConfig = { root: abstraction("root"), // ✓ TypeScript validates all options here }; export default defineConfig(config); ``` -------------------------------- ### Programmatically Watch Configuration Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/configuration.md Use `watchConfig` to subscribe to configuration changes. This is useful for dynamic loading or when the CLI is not used. Ensure `@evod/core` is imported. ```typescript import { watchConfig, type ConfigResult } from "@evod/core"; watchConfig({ cwd: process.cwd(), onlyOne: true, }).subscribe({ next: ({ config, configPath }: ConfigResult) => { console.log(`Loaded from ${configPath}`); console.log(`Root: ${config.root.name}`); }, error: (err) => { console.error(`Config error: ${err.message}`); }, }); ``` -------------------------------- ### Validate Fix Operations Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md Implement robust error handling for auto-fix operations. This example uses `Promise.allSettled` to manage multiple fix attempts and logs warnings for any failures, returning the original diagnostics for unfixable issues. ```typescript const applyFixes = async (diagnostics) => { const results = await Promise.allSettled( diagnostics.map(async (d) => { if (!d.fixes) return null; try { return await applyAutofixes([d]); } catch (err) { console.warn(`Failed to fix ${d.location.path}: ${err.message}`); return [d]; // Keep original diagnostic } }) ); return results .filter((r) => r.status === "fulfilled") .flatMap((r) => r.value || []) .flat(); }; ``` -------------------------------- ### Run Evolution Design Lint CLI Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Use this command to perform initial validation of your project's architecture. For development, use the --watch flag to automatically re-run on file changes. The --fix flag attempts to auto-correct issues. ```bash # Initial validation npm run lint:architect # Watch mode during development npm run lint:architect -- --watch # Auto-fix where possible npm run lint:architect -- --fix # Fail on warnings too npm run lint:architect -- --fail-on-warning ``` -------------------------------- ### Run Evolution Design Linter Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Command to run the Evolution Design linter for validating project architecture. ```bash edlint lint # ✓ No problems found! ``` -------------------------------- ### GitHub Actions for Linting Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md A GitHub Actions workflow step to run edlint for code linting. ```yaml - run: npx edlint lint ``` -------------------------------- ### Development Commands Source: https://github.com/evo-community/evolution-design/blob/main/apps/docs/README.md These npm commands are used to manage the development and build process of your Starlight site. ```bash npm install ``` ```bash npm run dev ``` ```bash npm run build ``` ```bash npm run preview ``` ```bash npm run astro ... ``` ```bash npm run astro -- --help ``` -------------------------------- ### Define Architecture with defineConfig Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Configure the project's root abstraction and rules using defineConfig. Ensure correct imports from @evod/core. ```typescript import { defineConfig, abstraction } from "@evod/core"; import { dependenciesDirection, noUnabstractionFiles } from "@evod/core/rules"; export default defineConfig({ root: abstraction({ name: "app", children: { app: abstraction("app"), features: abstraction("features"), shared: abstraction("shared"), }, rules: [ dependenciesDirection(["app", "features", "shared"]), noUnabstractionFiles(), ], }), baseUrl: "./src", }); ``` -------------------------------- ### Package.json Scripts for Linting Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Configure package.json scripts to run edlint for linting, watching for changes, and fixing issues. ```json { "scripts": { "lint:arch": "edlint lint", "lint:arch:watch": "edlint lint --watch", "lint:arch:fix": "edlint lint --fix" } } ``` -------------------------------- ### Run edlint CLI Commands Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Execute linting operations using the edlint CLI. Use the --watch flag for continuous monitoring during development and --fix to automatically correct violations. ```bash # Check once edlint lint # Watch during development edlint lint --watch # Auto-fix violations edlint lint --fix ``` -------------------------------- ### watchFs() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/vfs.md Observes a directory tree for file system changes and emits VFS events as a reactive stream. It automatically ignores `node_modules` and git-ignored paths. ```APIDOC ## watchFs() ### Description Observes a directory tree for file system changes and emits VFS events as a reactive stream. Automatically ignores `node_modules` and git-ignored paths. ### Method Signature ```typescript function watchFs( path: Path, { onlyReady }?: { onlyReady?: boolean } ): Observable; ``` ### Parameters #### Path Parameters - **path** (`string`) - Required - Root directory path to watch #### Query Parameters - **onlyReady** (`boolean`) - Optional - If true, only emit initial "ready" event; if false, emit all change events. Defaults to `false`. ### Return Type An RxJS `Observable` that emits file system events. ### Example ```typescript import { watchFs } from "@evod/core"; watchFs("./src").subscribe((event) => { console.log(`Event type: ${event.type}`); console.log(`VFS root: ${event.vfs.path}`); // Get all files from the current VFS const files = getFlattenFiles(event.vfs); console.log(`Total files: ${files.length}`); }); ``` ``` -------------------------------- ### Export Configuration from @evod/core Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Exports functions for configuring Evolution Design, including defining configurations and watching for changes. Use these to set up your project's linting rules and settings. ```typescript export { defineConfig, type EvolutionConfig }; export { watchConfig, type ConfigResult }; ``` -------------------------------- ### AbstractionInstance Type Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction-instance.md Represents a parsed abstraction within the file system. ```APIDOC ## AbstractionInstance Type ```typescript interface AbstractionInstance { abstraction: Abstraction; children: AbstractionInstance[]; path: Path; childNodes: Path[]; } ``` ### Fields - **abstraction** (`Abstraction`) - The abstraction definition this instance was created from - **children** (`AbstractionInstance[]`) - Child abstraction instances nested within this instance - **path** (`Path`) - Absolute file system path to the directory or file this instance represents - **childNodes** (`Path[]`) - Paths to direct children (files and folders) that are not abstraction instances ``` -------------------------------- ### getAbstractionInstanceLabel() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction-instance.md Formats a human-readable label for an AbstractionInstance, combining the folder name and abstraction name when they differ. ```APIDOC ## getAbstractionInstanceLabel() ### Description Formats a human-readable label for an `AbstractionInstance`, combining the folder name and abstraction name when they differ. ### Function Signature ```typescript function getAbstractionInstanceLabel(instance: AbstractionInstance): string; ``` ### Parameters #### Path Parameters - **instance** (`AbstractionInstance`) - Required - The abstraction instance to label ### Return Type A string label combining the folder name and abstraction name when different, or just the name if they match. ### Example ```typescript import { getAbstractionInstanceLabel } from "@evod/core"; // If folder is "features" and abstraction name is "feature" const label = getAbstractionInstanceLabel(instance); // Returns: "features (feature)" // If folder is "feature" and abstraction name is "feature" const label = getAbstractionInstanceLabel(instance); // Returns: "feature" ``` ``` -------------------------------- ### Handle File System Errors with applyAutofixes Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md Use a try-catch block to handle potential file system errors during the autofix process. This ensures that if file operations fail, the application can log the error and continue without crashing. ```typescript import { applyAutofixes } from "edlint"; try { const remaining = await applyAutofixes(diagnostics); console.log(`Fixed ${diagnostics.length - remaining.length} issues`); } catch (err) { if (err instanceof Error) { console.error(`Auto-fix failed: ${err.message}`); } // Diagnostics remain unfixed } ``` -------------------------------- ### AbstractionOptions Type Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction.md Defines the configuration options for creating an Abstraction. ```APIDOC ## AbstractionOptions ### Fields - **name** (string) - Required - Name of the abstraction - **children** (Record) - Optional - Nested abstraction definitions - **rules** (Rule[]) - Optional - Validation rules (default: `[]`) - **fractal** (string) - Optional - Enables fractal nesting when referencing an ancestor abstraction name - **fileTemplate** (((path: Path) => string) | string) - Optional - Template string or function for generated file content - **fileTemplateUrl** (string) - Optional - Path to a template file to be read when creating files ``` -------------------------------- ### watchConfig() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/config.md Watches for configuration file changes and emits `ConfigResult` events as an RxJS Observable. It looks for files named `evo.config.ts`, `evo.config.js`, etc. ```APIDOC ## watchConfig() ### Description Watches for configuration file changes and emits `ConfigResult` events as an RxJS Observable. Looks for files named `evo.config.ts`, `evo.config.js`, `evo.config.mjs`, etc. ### Signature ```typescript function watchConfig({ cwd, onlyOne, }: { cwd: string; onlyOne?: boolean; }): Observable; ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **cwd** (`string`) - Required - Directory to search for config file (usually `process.cwd()`) * **onlyOne** (`boolean`) - Optional - If true, emit one config and complete; if false, watch for changes. Defaults to `false`. ### Return Type An RxJS `Observable` that emits configuration results. ### Throws * `ConfigurationNotFoundError` — No `evo.config.*` file found in `cwd` or parent directories * `ConfigurationInvalidError` — Config file fails validation against the schema ### Example ```typescript import { watchConfig } from "@evod/core"; import process from "node:process"; // Load once watchConfig({ cwd: process.cwd(), onlyOne: true }).subscribe({ next: ({ config, configPath }) => { console.log(`Loaded config from ${configPath}`); console.log(`Root abstraction: ${config.root.name}`); }, error: (err) => { console.error(`Config error: ${err.message}`); }, }); // Watch for changes watchConfig({ cwd: process.cwd() }).subscribe(({ config }) => { console.log("Config reloaded", config); }); ``` ``` -------------------------------- ### rule() - Overload 1: String Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/rule.md Creates a rule with default settings (severity 'error' and a no-op check function) using only a rule name. ```APIDOC ## rule(name: RuleName) ### Description Creates a rule with default settings: severity "error" and a no-op check function. ### Parameters #### Path Parameters - **name** (string) - Required - Unique name for the rule ### Return Type Returns a `Rule` object. ### Example ```typescript import { rule } from "@evod/core"; const myRule = rule("my-validation"); ``` ``` -------------------------------- ### Create Async Rule Checking Dependencies Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/rule.md Define an asynchronous rule that can inspect dependencies. Provide a name, severity, an optional description URL, and an async check function that returns diagnostics. ```typescript import { rule } from "@evod/core"; const noCyclicDeps = rule({ name: "no-cyclic-dependencies", severity: "error", descriptionUrl: "https://docs.example.com/rules/cyclic", check: async ({ instance, dependenciesMap, root }) => { const diagnostics = []; // Check for cycles in dependenciesMap return { diagnostics }; }, }); ``` -------------------------------- ### GitLab CI Integration for Linting Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Set up GitLab CI to run edlint as part of your pipeline. This script executes the lint command and will fail the pipeline if violations are found. ```yaml lint: script: - npx edlint lint ``` -------------------------------- ### Import Core Rules Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/types.md Import specific rule functions from the @evod/core/rules module. These are pre-defined rules that can be used in your configuration. ```typescript import { // Functions requiredChildren, noUnabstractionFiles, publicAbstraction, restrictCrossImports, dependenciesDirection, off, warn, } from "@evod/core/rules"; ``` -------------------------------- ### Pre-commit Hook for Architecture Validation Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Implement a pre-commit hook to automatically run edlint before each commit. This ensures that code adheres to architectural standards before being committed. ```bash #!/bin/sh npx edlint lint if [ $? -ne 0 ]; then echo "Architecture validation failed" exit 1 fi ``` -------------------------------- ### Create Simple Abstraction by Name Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/abstraction.md Use this when you need to define a basic architectural layer or component without complex configurations. It requires only the name of the abstraction. ```typescript import { abstraction } from "@evod/core"; const appLayer = abstraction("app"); ``` -------------------------------- ### getFlattenFiles() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/vfs.md Recursively flattens a VFS tree to collect all files. Results are memoized for performance. ```APIDOC ## getFlattenFiles() ### Description Recursively flattens a VFS tree to collect all files. Results are memoized for performance. ### Method Signature ```typescript function getFlattenFiles(node: VfsNode): VfsFile[]; ``` ### Parameters #### Path Parameters - **node** (`VfsNode`) - Required - Root node to flatten (file or folder) ### Return Type Array of all `VfsFile` objects found in the tree, in depth-first order. ### Example ```typescript import { watchFs, getFlattenFiles } from "@evod/core"; watchFs("./src", { onlyReady: true }).subscribe(({ vfs }) => { const files = getFlattenFiles(vfs); const tsFiles = files.filter((f) => f.path.endsWith(".ts")); console.log(`Found ${tsFiles.length} TypeScript files`); }); ``` ``` -------------------------------- ### Create Rule with Check Function Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/rule.md Configure a rule with a specific severity and a synchronous check function. The check function receives the instance and root context and should return diagnostics. ```typescript import { rule } from "@evod/core"; const noEmptyFolders = rule({ name: "no-empty-folders", severity: "warn", check: ({ instance, root }) => { const diagnostics = []; if (instance.childNodes.length === 0 && instance.children.length === 0) { diagnostics.push({ message: "Abstraction is empty", location: { path: instance.path }, }); } return { diagnostics }; }, }); ``` -------------------------------- ### formatPretty() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/lint.md Formats diagnostics into a human-readable string with colors and formatting suitable for terminal output. ```APIDOC ## formatPretty() ### Description Formats diagnostics into a human-readable string with colors and formatting suitable for terminal output. ### Signature ```typescript function formatPretty( diagnostics: AugmentedDiagnostic[], cwd: string ): string; ``` ### Parameters #### Path Parameters - **diagnostics** (AugmentedDiagnostic[]) - Required - Array of diagnostics to format - **cwd** (string) - Required - Working directory for computing relative paths ### Return Type A formatted string with ANSI color codes suitable for console output. ### Example ```typescript import { lint, formatPretty } from "edlint"; lint({ config, configPath, watch: false }).subscribe((diagnostics) => { const formatted = formatPretty(diagnostics, process.cwd()); console.log(formatted); }); ``` ``` -------------------------------- ### Define Evo Configuration Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Export a configuration object from `evo.config.ts` to define the root abstraction and optional settings like baseUrl, files, and ignores. ```typescript export default defineConfig({ root: Abstraction, // Required baseUrl?: string, // Default: "." files?: string[], // File glob patterns to validate ignores?: string[], // File glob patterns to ignore }); ``` -------------------------------- ### Manage FSD Linter with Watch and Fix Flags Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Commands for linting, watching for changes during development, and automatically fixing missing required files in an FSD architecture. ```bash # Check current state edlint lint # Watch during development edlint lint --watch # Auto-fix missing required files edlint lint --fix ``` -------------------------------- ### Run edlint lint once Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Executes the edlint linter once to validate the current project's architecture against defined rules. Use this for a single validation pass. ```bash edlint lint ``` -------------------------------- ### Microservice Configuration Pattern Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/configuration.md Configuration pattern for a microservice. It sets up a root abstraction named 'service' and defines common subdirectories like routes, middleware, models, and utils. Includes base URL and file glob patterns. ```typescript export default defineConfig({ root: abstraction({ name: "service", children: { routes: abstraction("routes"), middleware: abstraction("middleware"), models: abstraction("models"), utils: abstraction("utils"), }, }), baseUrl: "./src", files: ["**/*.ts", "!**/*.test.ts"], }); ``` -------------------------------- ### parseDependenciesMap() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/dependencies.md Analyzes all files in a VFS tree, resolves imports using tsconfig settings, and returns a bidirectional dependency map. This is the main entry point for generating dependency information. ```APIDOC ## parseDependenciesMap() ### Description Analyzes all files in a VFS tree, resolves imports using tsconfig settings, and returns a bidirectional dependency map. ### Method `async function parseDependenciesMap(vfs: VfsNode): Promise;` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **vfs** (`VfsNode`) - Required - Root VFS node representing the project file system ### Return Type Promise that resolves to a `DependenciesMap` object. ### Throws - May throw if a `tsconfig.json` cannot be parsed or if file I/O fails ### Example ```typescript import { watchFs, parseDependenciesMap, getFlattenFiles, } from "@evod/core"; watchFs("./src", { onlyReady: true }).subscribe(async ({ vfs }) => { const deps = await parseDependenciesMap(vfs); // Find all files that import from "app/index.ts" const importers = deps.dependencyFor["/absolute/path/to/app/index.ts"]; if (importers) { for (const importer of importers) { console.log(`${importer} imports from app/index.ts`); } } // Find all imports from "shared" const myDeps = deps.dependencies["/absolute/path/to/component.ts"]; if (myDeps) { for (const dep of myDeps) { console.log(`component.ts imports from ${dep}`); } } }); ``` ``` -------------------------------- ### Add lint:architect Script to package.json Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Configure your package.json to include the 'lint:architect' script, which is used to run the 'edlint lint' command. ```json { "scripts": { "lint:architect": "edlint lint" } } ``` -------------------------------- ### Gradual Migration with Severity Levels Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Implement a gradual migration strategy by using severity levels for rules. Initially, warnings are used to flag violations, which are later enforced strictly as the migration progresses. ```typescript import { defineConfig, abstraction } from "@evod/core"; import { warn, noUnabstractionFiles } from "@evod/core/rules"; export default defineConfig({ root: abstraction({ name: "app", children: { legacy: abstraction("legacy"), new: abstraction("new"), }, rules: [ // Warn on legacy violations, but don't fail warn(noUnabstractionFiles()), ], }), baseUrl: "./src", }); // Later, when migration is complete: export default defineConfig({ root: abstraction({ name: "app", children: { // legacy is removed features: abstraction("features"), }, rules: [ // Now enforce strictly noUnabstractionFiles(), ], }), baseUrl: "./src", }); ``` -------------------------------- ### Development Workflow: Watch Mode Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/cli-reference.md Use the --watch flag to have edlint continuously monitor your files during development. It will automatically re-run checks when changes are detected. ```bash # Watch during development edlint lint --watch ``` -------------------------------- ### Enable Verbose Output with watchConfig Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/errors.md Use this TypeScript snippet to enable detailed logging during configuration watching. It subscribes to configuration changes, logs loaded config details, and reports diagnostics from linting. ```typescript import { watchConfig } from "@evod/core"; import { lint, reportPretty } from "edlint"; watchConfig({ cwd: process.cwd() }).subscribe({ next: ({ config, configPath }) => { console.debug(`Loaded config from ${configPath}`); console.debug(`Root abstraction: ${config.root.name}`); console.debug(`Base URL: ${config.baseUrl}`); lint({ config, configPath, watch: false }).subscribe((diagnostics) => { console.debug(`Found ${diagnostics.length} diagnostics`); diagnostics.forEach((d) => { console.debug(` - ${d.rule.name} at ${d.location.path}`); }); reportPretty(diagnostics, process.cwd()); }); }, error: (err) => { console.error("Error:", err); if (err instanceof Error && err.stack) { console.error(err.stack); } }, }); ``` -------------------------------- ### Configure Simple Layered Architecture Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/examples.md Define a basic three-layer architecture (app, features, shared) with dependency rules using `evo.config.ts`. Ensures only specific layers can depend on others. ```typescript import { defineConfig, abstraction } from "@evod/core"; import { dependenciesDirection, noUnabstractionFiles } from "@evod/core/rules"; export default defineConfig({ root: abstraction({ name: "root", children: { app: abstraction("app"), features: abstraction("features"), shared: abstraction("shared"), }, rules: [ // Only app can depend on features and shared // features can depend on shared dependenciesDirection(["app", "features", "shared"]), // No loose files at root level noUnabstractionFiles(), ], }), baseUrl: "./src", }); ``` -------------------------------- ### reportPretty() Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/api-reference/lint.md Formats and prints diagnostics to stderr. ```APIDOC ## reportPretty() ### Description Formats and prints diagnostics to stderr. ### Signature ```typescript function reportPretty( diagnostics: AugmentedDiagnostic[], cwd: string ): void; ``` ### Parameters #### Path Parameters - **diagnostics** (AugmentedDiagnostic[]) - Required - Array of diagnostics to report - **cwd** (string) - Required - Working directory for computing relative paths ### Example ```typescript import { lint, reportPretty } from "edlint"; import process from "node:process"; lint({ config, configPath, watch: false }).subscribe((diagnostics) => { reportPretty(diagnostics, process.cwd()); process.exit(diagnostics.length > 0 ? 1 : 0); }); ``` ``` -------------------------------- ### RuleOptions Interface Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/types.md Configuration options for the `rule()` factory function. Allows setting the rule name, severity, description URL, and the check function. ```typescript interface RuleOptions { name: RuleName; severity?: Severity; descriptionUrl?: string; check?: (context: RuleContext) => RuleResult | Promise; } ``` -------------------------------- ### Export Dependencies Utilities from @evod/core Source: https://github.com/evo-community/evolution-design/blob/main/_autodocs/README.md Exports utilities for parsing and representing the dependency graph of a project. Use this to analyze import relationships between modules. ```typescript export { parseDependenciesMap, type DependenciesMap }; ```