From 4dda1fac13621bd9ad5a1813ae63f4c925ec1525 Mon Sep 17 00:00:00 2001 From: Rainer Hahnekamp Date: Tue, 29 Oct 2024 23:14:18 +0100 Subject: [PATCH] feat: allow regex for `encapsulationPattern` --- .../checks/has-encapsulation-violations.ts | 10 ++++-- .../tests/encapsulation-barrel-less.spec.ts | 33 +++++++++++++++++-- .../src/lib/config/user-sheriff-config.ts | 32 ++++++++++++++---- packages/core/src/lib/test/project-creator.ts | 28 ++++++++++++++-- 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/packages/core/src/lib/checks/has-encapsulation-violations.ts b/packages/core/src/lib/checks/has-encapsulation-violations.ts index 8ef950f..9b7ffe5 100644 --- a/packages/core/src/lib/checks/has-encapsulation-violations.ts +++ b/packages/core/src/lib/checks/has-encapsulation-violations.ts @@ -45,7 +45,7 @@ export function hasEncapsulationViolations( function accessesExposedFileForBarrelLessModules( fileInfo: FileInfo, enableBarrelLess: boolean, - encapsulationPatternForBarrelLess: string, + encapsulationPattern: string | RegExp, ) { const fs = getFs(); if (!enableBarrelLess) { @@ -57,7 +57,13 @@ function accessesExposedFileForBarrelLessModules( } const relativePath = fs.relativeTo(fileInfo.moduleInfo.path, fileInfo.path); - return !relativePath.startsWith(encapsulationPatternForBarrelLess); + + if (typeof encapsulationPattern === 'string') { + return !relativePath.startsWith(encapsulationPattern); + } else { + const matches = relativePath.match(encapsulationPattern); + return !matches + } } function accessesBarrelFileForBarrelModules(fileInfo: FileInfo) { diff --git a/packages/core/src/lib/checks/tests/encapsulation-barrel-less.spec.ts b/packages/core/src/lib/checks/tests/encapsulation-barrel-less.spec.ts index def62f7..fcb5565 100644 --- a/packages/core/src/lib/checks/tests/encapsulation-barrel-less.spec.ts +++ b/packages/core/src/lib/checks/tests/encapsulation-barrel-less.spec.ts @@ -232,6 +232,35 @@ describe('barrel-less', () => { it.skip('should support nested wildcards', () => {}); - it.skip('should apply regex to path', () => {}); + it('should apply regex to path', () => { + assertProject({ encapsulationPattern: /(^|\/)_/ }) + .withCustomerRoute({ + feature: { + 'customer.component.ts': [], + 'customers.component.ts': [ + '../data/_main.ts', + '../data/sub/_file.ts', + '../data/_sub/file.ts', + '../data/main.ts', + '../data/main_file.ts', + '../data/internal/file.ts', + ], + }, + data: { + '_main.ts': [], + sub: { '_file.ts': [] }, + _sub: { 'file.ts': [] }, + 'main.ts': [], + 'main_file.ts': [], + 'internal/file.ts': [], + }, + }) + .hasEncapsulationViolations({ + 'feature/customers.component.ts': [ + '../data/_main.ts', + '../data/sub/_file.ts', + '../data/_sub/file.ts', + ], + }); + }); }); - diff --git a/packages/core/src/lib/config/user-sheriff-config.ts b/packages/core/src/lib/config/user-sheriff-config.ts index 3958e9a..d24e8c6 100644 --- a/packages/core/src/lib/config/user-sheriff-config.ts +++ b/packages/core/src/lib/config/user-sheriff-config.ts @@ -191,16 +191,36 @@ export interface UserSheriffConfig { * or a regex to define the location/pattern for * encapsulation in barrel-less modules. * - * Example with a simple string: + * Examples: * - * + * --- + * A **string** `encapsulationPattern: 'private'` encapsulates * - * + * - `private/main.ts` + * - `private/sub/sub.ts` * - * This is a more powerful alternative to - * {@link encapsulatedFolderNameForBarrelLess}. + * But would expose + * - `main.ts` + * - `internal/hidden.ts` + * + * --- + * + * A **regular expression** `encapsulationPattern: /(^|\/)_/` encapsulates + * any file or directory starting with an underscore: + * + * - _main.ts + * - internal/_hidden + * - _sub/main.ts + * + * But would expose + * + * - main.ts + * - internal/hidden + * - sub/main_file.ts + * + * --- */ - encapsulationPattern?: string + encapsulationPattern?: string | RegExp /** * @deprecated no warning is shown. diff --git a/packages/core/src/lib/test/project-creator.ts b/packages/core/src/lib/test/project-creator.ts index 3851cfb..6d00ccb 100644 --- a/packages/core/src/lib/test/project-creator.ts +++ b/packages/core/src/lib/test/project-creator.ts @@ -47,9 +47,20 @@ class ProjectCreator { } else if (typeof value === 'string') { this.fs.writeFile(`${currentDir}/${child}`, value); } else if (isSheriffConfigContent(value)) { - const serializedConfig = JSON.stringify( - serializeDepRules({ ...defaultConfig, ...value.content }), - ).replace(/"α([^ω]+)ω"/g, '$1'); + let serializedConfig = JSON.stringify( + serializeEncapsulationPattern( + serializeDepRules({ ...defaultConfig, ...value.content }), + ), + ); + + if (value.content.encapsulationPattern instanceof RegExp) { + serializedConfig = serializedConfig.replace( + /"Δ.*Δ"/, + value.content.encapsulationPattern.toString(), + ); + } + + serializedConfig = serializedConfig.replace(/"α([^ω]+)ω"/g, '$1'); this.fs.writeFile( `${currentDir}/${child}`, `export const config = ${serializedConfig};`, @@ -75,3 +86,14 @@ function serializeDepRules(config: Configuration): Configuration { ), }; } + +function serializeEncapsulationPattern(config: Configuration): Configuration { + if (typeof config.encapsulationPattern === 'string') { + return config; + } else { + return { + ...config, + encapsulationPattern: `Δ${config.encapsulationPattern.toString()}Δ`, + }; + } +}