diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index 45ea1e88..e18416c8 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -109,6 +109,39 @@ These options have sensible defaults and are typically only customized for speci +#### `excludeFromChecks` {#excludefromchecks} + +- **Type**: `(string | RegExp)[]` +- **Default**: `[]` +- **Description**: Patterns to exclude from ALL Sheriff rule enforcement. Files matching these patterns are still processed and traversed for dependency analysis, but no rule violations are reported. Supports glob patterns and regular expressions. + +**Key Distinction: `ignoreFileExtensions` vs `excludeFromChecks`** + +The `ignoreFileExtensions` option makes Sheriff skip parsing and traversing certain file types, such as `.scss`, because the TypeScript parser cannot read them. This means dependencies inside those files are completely hidden from Sheriff. + +In contrast, `excludeFromChecks` disables rule enforcement for specific paths while still parsing and traversing them. Excluded files themselves are not checked, but any files they import remain visible to Sheriff. This ensures that non-excluded code imported through excluded paths is still validated. + +**Examples:** + +```typescript +export const config: SheriffConfig = { + excludeFromChecks: [ + 'src/client/**', // Skip all rule checks for generated client + 'src/generated/**', // Skip all rule checks for generated files + 'src/**/*.gen.ts', // Skip all rule checks for .gen.ts files + /src\/.*\.gen\.ts$/, // Regex pattern for .gen.ts files + 'src/legacy/**' // Skip all rule checks for legacy code + ], + // ... other config options +}; +``` + +**Use Cases:** + +- **Legacy code migration**: Existing codebases that haven't been refactored to follow strict module boundaries yet need time to gradually adopt Sheriff's rules +- **Third-party generated code**: Users import from generated SDKs or client libraries that have internal dependencies (e.g., OpenAPI clients) +- **Temporary exclusions**: During refactoring phases where certain areas need to be temporarily excluded from rule enforcement + ### Legacy Options #### `excludeRoot` {#excluderoot} diff --git a/docs/docs/release-notes/0.20.md b/docs/docs/release-notes/0.20.md index 72231d98..8848d964 100644 --- a/docs/docs/release-notes/0.20.md +++ b/docs/docs/release-notes/0.20.md @@ -54,3 +54,47 @@ This feature is particularly useful when: No migration is required. Existing configurations will continue to work with the new default ignored extensions. If you want to customize the ignored extensions, simply add the `ignoreFileExtensions` option to your configuration. For more details, see the [Configuration Reference](../configuration.md#ignorefileextensions). + +## New Feature: Exclude Files from Rule Checks + +Sheriff now supports excluding specific files or patterns from all rule enforcement through the new `excludeFromChecks` configuration option. + +### What it does + +The `excludeFromChecks` option allows you to exclude specific file paths or patterns from Sheriff's rule enforcement while still maintaining dependency analysis. This is particularly useful for legacy code, generated files, or areas of your codebase that need time to gradually adopt Sheriff's rules. + +### Key Distinction: `ignoreFileExtensions` vs `excludeFromChecks` + +- **`ignoreFileExtensions`**: Makes Sheriff skip parsing and traversing certain file types (e.g., `.scss` files that TypeScript can't read) +- **`excludeFromChecks`**: Disables rule enforcement for specific paths while still parsing and traversing them for dependency analysis + +### Configuration Options + +You can use a combination of glob patterns and regular expressions: + +```typescript +export const config: SheriffConfig = { + excludeFromChecks: [ + 'src/client/**', // Skip all rule checks for generated client + 'src/generated/**', // Skip all rule checks for generated files + 'src/**/*.gen.ts', // Skip all rule checks for .gen.ts files + /src\/.*\.gen\.ts$/, // Regex pattern for .gen.ts files + 'src/legacy/**' // Skip all rule checks for legacy code + ], + // ... other configuration +}; +``` + +### Use Cases + +This feature is particularly useful when: + +- **Legacy code migration**: Existing codebases that haven't been refactored to follow strict module boundaries yet +- **Third-party generated code**: Importing from generated SDKs or client libraries with internal dependencies +- **Temporary exclusions**: During refactoring phases where certain areas need to be temporarily excluded + +### Migration + +No migration is required. Existing configurations will continue to work. The `excludeFromChecks` option defaults to an empty array, meaning no files are excluded by default. + +For more details, see the [Configuration Reference](../configuration.md#excludefromchecks). diff --git a/packages/core/src/lib/checks/check-for-dependency-rule-violation.ts b/packages/core/src/lib/checks/check-for-dependency-rule-violation.ts index d68f3b22..7292a35b 100644 --- a/packages/core/src/lib/checks/check-for-dependency-rule-violation.ts +++ b/packages/core/src/lib/checks/check-for-dependency-rule-violation.ts @@ -2,6 +2,7 @@ import { FsPath, toFsPath } from '../file-info/fs-path'; import { ProjectInfo } from '../main/init'; import { calcTagsForModule } from '../tags/calc-tags-for-module'; import { isDependencyAllowed } from './is-dependency-allowed'; +import { isExcludedFromChecks } from '../util/is-excluded-from-checks'; export type DependencyRuleViolation = { rawImport: string; @@ -21,6 +22,11 @@ export function checkForDependencyRuleViolation( return []; } + // Skip checks for excluded files + if (isExcludedFromChecks(fsPath, config.excludeFromChecks)) { + return []; + } + const assignedFileInfo = getFileInfo(fsPath); const importedModulePathsWithRawImport = assignedFileInfo.imports // skip imports of same module diff --git a/packages/core/src/lib/checks/has-encapsulation-violations.ts b/packages/core/src/lib/checks/has-encapsulation-violations.ts index 9b7ffe54..6884d744 100644 --- a/packages/core/src/lib/checks/has-encapsulation-violations.ts +++ b/packages/core/src/lib/checks/has-encapsulation-violations.ts @@ -3,6 +3,7 @@ import { Configuration } from '../config/configuration'; import { ProjectInfo } from '../main/init'; import { FileInfo } from '../modules/file.info'; import getFs from '../fs/getFs'; +import { isExcludedFromChecks } from '../util/is-excluded-from-checks'; /** * verifies if an existing file has imports which break @@ -17,6 +18,12 @@ export function hasEncapsulationViolations( { rootDir, config, getFileInfo }: ProjectInfo, ): Record { const encapsulationViolations: Record = {}; + + // Skip checks for excluded files + if (isExcludedFromChecks(fsPath, config.excludeFromChecks)) { + return encapsulationViolations; + } + const assignedFileInfo = getFileInfo(fsPath); for (const importedFileInfo of assignedFileInfo.imports) { diff --git a/packages/core/src/lib/config/configuration.ts b/packages/core/src/lib/config/configuration.ts index adb94069..f137471b 100644 --- a/packages/core/src/lib/config/configuration.ts +++ b/packages/core/src/lib/config/configuration.ts @@ -18,4 +18,6 @@ export type Configuration = Required< entryPoints?: Record; // ignoreFileExtensions is always present (either user-specified or default) ignoreFileExtensions: string[]; + // excludeFromChecks is always present (either user-specified or default) + excludeFromChecks: (string | RegExp)[]; }; diff --git a/packages/core/src/lib/config/default-config.ts b/packages/core/src/lib/config/default-config.ts index 7db8434a..581fbfd2 100644 --- a/packages/core/src/lib/config/default-config.ts +++ b/packages/core/src/lib/config/default-config.ts @@ -15,4 +15,5 @@ export const defaultConfig: Configuration = { barrelFileName: 'index.ts', entryPoints: undefined, ignoreFileExtensions: defaultIgnoreFileExtensions, + excludeFromChecks: [], }; diff --git a/packages/core/src/lib/config/parse-config.ts b/packages/core/src/lib/config/parse-config.ts index 339d06c9..3f149dbe 100644 --- a/packages/core/src/lib/config/parse-config.ts +++ b/packages/core/src/lib/config/parse-config.ts @@ -67,9 +67,14 @@ export const parseConfig = (configFile: FsPath): Configuration => { mergedConfig.ignoreFileExtensions, ); + const excludeFromChecks = getExcludeFromChecks( + mergedConfig.excludeFromChecks, + ); + return { ...mergedConfig, ignoreFileExtensions, + excludeFromChecks, }; }; @@ -82,3 +87,9 @@ function getIgnoreFileExtensions( : ignoreFileExtensions; return Array.from(new Set(extensions.map((ext) => ext.toLowerCase()))); } + +function getExcludeFromChecks( + excludeFromChecks: (string | RegExp)[] | undefined, +): (string | RegExp)[] { + return excludeFromChecks ?? []; +} diff --git a/packages/core/src/lib/config/tests/parse-config.spec.ts b/packages/core/src/lib/config/tests/parse-config.spec.ts index 5374b96f..56c70826 100644 --- a/packages/core/src/lib/config/tests/parse-config.spec.ts +++ b/packages/core/src/lib/config/tests/parse-config.spec.ts @@ -367,4 +367,81 @@ export const config: SheriffConfig = { ); }); }); + + describe('excludeFromChecks', () => { + it('should use empty array when excludeFromChecks is not provided', () => { + getFs().writeFile( + 'sheriff.config.ts', + ` +import { SheriffConfig } from '@softarc/sheriff-core'; + +export const config: SheriffConfig = { + depRules: { root: 'noTag', noTag: 'noTag' } +}; + `, + ); + const config = parseConfig( + toFsPath(getFs().cwd() + '/sheriff.config.ts'), + ); + expect(config.excludeFromChecks).toEqual([]); + }); + + it('should parse string patterns correctly', () => { + getFs().writeFile( + 'sheriff.config.ts', + ` +import { SheriffConfig } from '@softarc/sheriff-core'; + +export const config: SheriffConfig = { + excludeFromChecks: ['src/client/**', 'src/generated/**'], + depRules: { root: 'noTag', noTag: 'noTag' } +}; + `, + ); + const config = parseConfig( + toFsPath(getFs().cwd() + '/sheriff.config.ts'), + ); + expect(config.excludeFromChecks).toEqual(['src/client/**', 'src/generated/**']); + }); + + it('should parse regex patterns correctly', () => { + getFs().writeFile( + 'sheriff.config.ts', + ` +import { SheriffConfig } from '@softarc/sheriff-core'; + +export const config: SheriffConfig = { + excludeFromChecks: [/src\/.*\.gen\.ts$/, /.*\.spec\.ts$/], + depRules: { root: 'noTag', noTag: 'noTag' } +}; + `, + ); + const config = parseConfig( + toFsPath(getFs().cwd() + '/sheriff.config.ts'), + ); + expect(config.excludeFromChecks).toEqual([/src\/.*\.gen\.ts$/, /.*\.spec\.ts$/]); + }); + + it('should parse mixed patterns correctly', () => { + getFs().writeFile( + 'sheriff.config.ts', + ` +import { SheriffConfig } from '@softarc/sheriff-core'; + +export const config: SheriffConfig = { + excludeFromChecks: ['src/client/**', /src\/.*\.gen\.ts$/, 'src/legacy/**'], + depRules: { root: 'noTag', noTag: 'noTag' } +}; + `, + ); + const config = parseConfig( + toFsPath(getFs().cwd() + '/sheriff.config.ts'), + ); + expect(config.excludeFromChecks).toEqual([ + 'src/client/**', + /src\/.*\.gen\.ts$/, + 'src/legacy/**' + ]); + }); + }); }); diff --git a/packages/core/src/lib/config/user-sheriff-config.ts b/packages/core/src/lib/config/user-sheriff-config.ts index 4bc596c7..728d29e9 100644 --- a/packages/core/src/lib/config/user-sheriff-config.ts +++ b/packages/core/src/lib/config/user-sheriff-config.ts @@ -280,4 +280,23 @@ export interface UserSheriffConfig { * ``` */ ignoreFileExtensions?: string[] | ((defaults: string[]) => string[]); + + /** + * Patterns to exclude from ALL Sheriff rule enforcement. + * Files matching these patterns are still processed and traversed + * for dependency analysis, but no rule violations are reported. + * Supports glob patterns and regular expressions. + * + * @example + * ```typescript + * excludeFromChecks: [ + * 'src/client/**', // Skip all rule checks for generated client + * 'src/generated/**', // Skip all rule checks for generated files + * 'src/**/*.gen.ts', // Skip all rule checks for .gen.ts files + * /src\/.*\.gen\.ts$/, // Regex pattern for .gen.ts files + * 'src/legacy/**' // Skip all rule checks for legacy code + * ] + * ``` + */ + excludeFromChecks?: (string | RegExp)[]; } diff --git a/packages/core/src/lib/util/is-excluded-from-checks.spec.ts b/packages/core/src/lib/util/is-excluded-from-checks.spec.ts new file mode 100644 index 00000000..1d365775 --- /dev/null +++ b/packages/core/src/lib/util/is-excluded-from-checks.spec.ts @@ -0,0 +1,129 @@ +import { describe, it, expect } from 'vitest'; +import { toFsPath } from '../file-info/fs-path'; +import { isExcludedFromChecks } from './is-excluded-from-checks'; + +describe('isExcludedFromChecks', () => { + describe('with string patterns', () => { + it('should return false when no patterns are provided', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, [])).toBe(false); + }); + + it('should match exact path patterns', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/app/component.ts'])).toBe(true); + }); + + it('should match path ending patterns', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, ['component.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['app/component.ts'])).toBe(true); + }); + + it('should handle glob patterns with single asterisk', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/app/*.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/*/component.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/*/*.ts'])).toBe(true); + }); + + it('should handle glob patterns with double asterisk', () => { + const filePath = toFsPath('src/app/feature/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/**/*.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/app/**'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['**/component.ts'])).toBe(true); + }); + + it('should handle complex glob patterns', () => { + const filePath = toFsPath('src/app/feature/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/app/feat*/**/*.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/**/feat*/**/*.ts'])).toBe(true); + }); + + it('should not match unrelated patterns', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/lib/**'])).toBe(false); + expect(isExcludedFromChecks(filePath, ['**/*.spec.ts'])).toBe(false); + expect(isExcludedFromChecks(filePath, ['dist/**'])).toBe(false); + }); + }); + + describe('with regex patterns', () => { + it('should match regex patterns', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, [/\.ts$/])).toBe(true); + expect(isExcludedFromChecks(filePath, [/src\/.*\.ts$/])).toBe(true); + expect(isExcludedFromChecks(filePath, [/.*component.*/])).toBe(true); + }); + + it('should handle complex regex patterns', () => { + const filePath = toFsPath('src/app/feature/component.ts'); + expect(isExcludedFromChecks(filePath, [/src\/.*\/.*\/.*\.ts$/])).toBe(true); + expect(isExcludedFromChecks(filePath, [/.*feature.*/])).toBe(true); + }); + + it('should not match unrelated regex patterns', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, [/\.spec\.ts$/])).toBe(false); + expect(isExcludedFromChecks(filePath, [/dist\//])).toBe(false); + }); + }); + + describe('with mixed patterns', () => { + it('should match any pattern in the array', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, [ + 'src/lib/**', + 'src/app/**', + /\.spec\.ts$/ + ])).toBe(true); + }); + + it('should handle empty patterns array', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, [])).toBe(false); + }); + }); + + describe('edge cases', () => { + it('should handle root paths', () => { + const filePath = toFsPath('component.ts'); + expect(isExcludedFromChecks(filePath, ['*.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['**/*.ts'])).toBe(true); + }); + + it('should handle paths with special characters', () => { + const filePath = toFsPath('src/app/feature-name/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/**/feature-*/**'])).toBe(true); + expect(isExcludedFromChecks(filePath, [/feature-.*/])).toBe(true); + }); + + it('should handle Windows-style paths', () => { + const filePath = toFsPath('src\\app\\component.ts'); + expect(isExcludedFromChecks(filePath, ['src/app/**'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/**/*.ts'])).toBe(true); + }); + }); + + describe('glob pattern conversion', () => { + it('should convert single asterisk correctly', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/*/component.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/app/*.ts'])).toBe(true); + }); + + it('should convert double asterisk correctly', () => { + const filePath = toFsPath('src/app/feature/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/**/*.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['**/feature/**'])).toBe(true); + }); + + it('should escape regex special characters in glob patterns', () => { + const filePath = toFsPath('src/app/component.ts'); + expect(isExcludedFromChecks(filePath, ['src/app/component.ts'])).toBe(true); + expect(isExcludedFromChecks(filePath, ['src/app/component\\.ts'])).toBe(false); + }); + }); +}); + + diff --git a/packages/core/src/lib/util/is-excluded-from-checks.ts b/packages/core/src/lib/util/is-excluded-from-checks.ts new file mode 100644 index 00000000..4ac923ea --- /dev/null +++ b/packages/core/src/lib/util/is-excluded-from-checks.ts @@ -0,0 +1,74 @@ +import { FsPath } from '../file-info/fs-path'; +import { wildcardToRegex } from './wildcard-to-regex'; + +/** + * Checks if a file path should be excluded from Sheriff rule checks. + * + * @param filePath - The file path to check + * @param excludePatterns - Array of glob patterns or regular expressions to match against + * @returns true if the file should be excluded from checks + */ +export function isExcludedFromChecks( + filePath: FsPath, + excludePatterns: (string | RegExp)[], +): boolean { + if (excludePatterns.length === 0) { + return false; + } + + // Convert FsPath to string for matching + const pathString = filePath.toString(); + + for (const pattern of excludePatterns) { + if (typeof pattern === 'string') { + // Handle glob patterns + if (pattern.includes('*') || pattern.includes('**')) { + const regex = globToRegex(pattern); + if (regex.test(pathString)) { + return true; + } + } else { + // Exact path match + if (pathString === pattern || pathString.endsWith(pattern)) { + return true; + } + } + } else if (pattern instanceof RegExp) { + // Regular expression match + if (pattern.test(pathString)) { + return true; + } + } + } + + return false; +} + +/** + * Converts a glob pattern to a regular expression. + * Supports basic glob patterns including ** for recursive matching. + * + * @param globPattern - The glob pattern to convert + * @returns A regular expression that matches the glob pattern + */ +function globToRegex(globPattern: string): RegExp { + // Handle ** for recursive matching + let pattern = globPattern + .replace(/\*\*/g, '.*') // ** becomes .* + .replace(/\*/g, '[^/]*'); // * becomes [^/]* (matches anything except /) + + // Escape other regex special characters + pattern = pattern.replace(/([.+?^=!:${}()|[\]\\])/g, '\\$1'); + + // Ensure the pattern matches the entire path + if (!pattern.startsWith('^')) { + pattern = '^' + pattern; + } + if (!pattern.endsWith('$')) { + pattern = pattern + '$'; + } + + return new RegExp(pattern); +} + + diff --git a/test-projects/angular-iv/integration-test.sh b/test-projects/angular-iv/integration-test.sh index 3cfb14b5..d19bf858 100755 --- a/test-projects/angular-iv/integration-test.sh +++ b/test-projects/angular-iv/integration-test.sh @@ -85,4 +85,12 @@ cp tests/sheriff.config-ignore-nothing.ts sheriff.config.ts npx ng lint --lint-file-patterns '**/different-file-extension-imports.ts' --force --format json --output-file tests/actual/ignore-file-extensions-lint.json ../remove-paths.mjs tests/actual/ignore-file-extensions-lint.json diff tests/actual/ignore-file-extensions-lint.json tests/expected/ignore-file-extensions-lint.json +cp sheriff.config.ts.original sheriff.config.ts + +## Exclude From Checks Check +echo 'checking for exclude from checks' +cp tests/sheriff.config-exclude-from-checks.ts sheriff.config.ts +npx ng lint --force --format json --output-file tests/actual/exclude-from-checks-lint.json +../remove-paths.mjs tests/actual/exclude-from-checks-lint.json +diff tests/actual/exclude-from-checks-lint.json tests/expected/exclude-from-checks-lint.json cp sheriff.config.ts.original sheriff.config.ts \ No newline at end of file diff --git a/test-projects/angular-iv/src/app/customers/api/excluded-file.ts b/test-projects/angular-iv/src/app/customers/api/excluded-file.ts new file mode 100644 index 00000000..1ffcbb02 --- /dev/null +++ b/test-projects/angular-iv/src/app/customers/api/excluded-file.ts @@ -0,0 +1,9 @@ +// This file should be excluded from all Sheriff checks +// It intentionally violates dependency rules to test exclusion + +// This import violates the dependency rules but should be ignored +import { CustomerService } from '../../shared/services/customer.service'; + +export class ExcludedCustomerComponent { + constructor(private customerService: CustomerService) {} +} diff --git a/test-projects/angular-iv/src/app/customers/feature/non-excluded-file.ts b/test-projects/angular-iv/src/app/customers/feature/non-excluded-file.ts new file mode 100644 index 00000000..ad26b346 --- /dev/null +++ b/test-projects/angular-iv/src/app/customers/feature/non-excluded-file.ts @@ -0,0 +1,11 @@ +// This file should NOT be excluded from Sheriff checks +// It should still be checked for dependency rule violations + +// This import should trigger a violation since it's not excluded +import { CustomerService } from '../../shared/services/customer.service'; + +export class NonExcludedCustomerComponent { + constructor(private customerService: CustomerService) {} +} + + diff --git a/test-projects/angular-iv/src/app/shared/generated/generated-file.gen.ts b/test-projects/angular-iv/src/app/shared/generated/generated-file.gen.ts new file mode 100644 index 00000000..c0e778f8 --- /dev/null +++ b/test-projects/angular-iv/src/app/shared/generated/generated-file.gen.ts @@ -0,0 +1,11 @@ +// This is a generated file that should be excluded from Sheriff checks +// It intentionally violates dependency rules to test regex exclusion + +// This import violates the dependency rules but should be ignored +import { CustomerService } from '../services/customer.service'; + +export class GeneratedCustomerService { + constructor(private customerService: CustomerService) {} +} + + diff --git a/test-projects/angular-iv/tests/exclude-from-checks-test.ts b/test-projects/angular-iv/tests/exclude-from-checks-test.ts new file mode 100644 index 00000000..e2ad2fcd --- /dev/null +++ b/test-projects/angular-iv/tests/exclude-from-checks-test.ts @@ -0,0 +1,16 @@ +import { getProjectData } from '@softarc/sheriff-core'; + +// Test the excludeFromChecks functionality +export function testExcludeFromChecks() { + const projectData = getProjectData('src/app/app.component.ts', { + projectName: 'angular-iv', + includeExternalLibraries: false, + }); + + // Files that should be excluded should not have dependency violations + // Files that are not excluded should still be checked normally + + return projectData; +} + + diff --git a/test-projects/angular-iv/tests/expected/exclude-from-checks-lint.json b/test-projects/angular-iv/tests/expected/exclude-from-checks-lint.json new file mode 100644 index 00000000..47486a52 --- /dev/null +++ b/test-projects/angular-iv/tests/expected/exclude-from-checks-lint.json @@ -0,0 +1,28 @@ +{ + "src/app/customers/api/excluded-file.ts": { + "module": "src/app/customers/api", + "moduleType": "barrel-less", + "tags": ["domain:customers", "type:api"], + "imports": [], + "unresolvedImports": [], + "projectName": "" + }, + "src/app/customers/feature/non-excluded-file.ts": { + "module": "src/app/customers/feature", + "moduleType": "barrel-less", + "tags": ["domain:customers", "type:feature"], + "imports": ["src/app/shared/services/customer.service"], + "unresolvedImports": [], + "projectName": "" + }, + "src/app/shared/generated/generated-file.gen.ts": { + "module": "src/app/shared/generated", + "moduleType": "barrel-less", + "tags": ["shared", "shared:generated"], + "imports": [], + "unresolvedImports": [], + "projectName": "" + } +} + + diff --git a/test-projects/angular-iv/tests/sheriff.config-exclude-from-checks.ts b/test-projects/angular-iv/tests/sheriff.config-exclude-from-checks.ts new file mode 100644 index 00000000..d090b990 --- /dev/null +++ b/test-projects/angular-iv/tests/sheriff.config-exclude-from-checks.ts @@ -0,0 +1,46 @@ +import { noDependencies, sameTag, SheriffConfig } from '@softarc/sheriff-core'; + +export const config: SheriffConfig = { + tagging: { + 'src/app': { + 'shared/': ['shared', 'shared:'], + bookings: ['domain:bookings', 'type:feature'], + 'customers/api': ['type:api', 'domain:customers:api'], + '/': ['domain:', 'type:'], + }, + }, + depRules: { + root: ['type:feature', 'shared:*'], + 'domain:*': [sameTag, 'shared'], + 'domain:bookings': 'domain:customers:api', + 'domain:customers:api': 'domain:customers', + 'type:api': 'type:*', + 'type:feature': [ + 'type:*', + 'shared:config', + 'shared:form', + 'shared:master-data', + 'shared:ngrx-utils', + 'shared:util', + ], + 'type:data': [ + 'type:model', + 'shared:http', + 'shared:ngrx-utils', + 'shared:ui-messaging', + ], + 'type:ui': ['type:model', 'shared:form', 'shared:ui'], + 'type:model': noDependencies, + shared: 'shared:*', + 'shared:http': ['shared:config', 'shared:ui-messaging'], + 'shared:ngrx-utils': ['shared:util'], + }, + excludeFromChecks: [ + 'src/app/customers/api/**', // Exclude all files in customers/api directory + 'src/app/shared/generated/**', // Exclude generated files + /src\/app\/.*\.gen\.ts$/, // Exclude .gen.ts files with regex + 'src/app/legacy/**' // Exclude legacy code + ], +}; + +