-
Notifications
You must be signed in to change notification settings - Fork 22
Description
EDIT
After writing all of this, I guess I realized the mistake in my mental model.
What I described would be possible if I change the dependecy rules to 'type:feature': ['type:feature', 'type:ui', 'type:data', 'type:util'],
This would allow smart components (feature prefix) to access each other...
But this would break the hierarchy (feature > ui > ...) you and Manfred often describe.
Now I'm a bit stuck, on how to solve this, because in practice I can think of usecases where smart components use other smart components in the UI.
This is propbably more a question than an issue, as I'm not sure if my mental model, what exactly a module
is, fits what Sheriff wants to achive and if it is possible to integrate it that way for an existing project.
Problem
I get a ESLint warning that is not correct in my opinion:
With the configuration described below, sheriff list
lists all the modules that should be relevant (see bleow) and sheriff verify
finds some violations, were the above is not correct IMHO, because sheriff export shows both have the same tags assigned and therefore should be able to access each other?
More Details:
IDE:
IntelliJ 2025.1.2
Sheriff & ESLint:
"@softarc/eslint-plugin-sheriff": "^0.18.1",
"@softarc/sheriff-core": "^0.18.1",
"angular-eslint": "~19.0.0",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-prettier": "^5.2.0",
Assumptions:
- For Sheriff a module is whatever is identified in the module property of the sheriff.config.ts
- this can be a folder (and I guess all files directly located in the folder)
- this can be a file
- If
autoTagging
is set to false, we can only enforce dependency rules for modules that are explicitly listed/identified through the modules configuraton in sheriff.config.ts - If the sheriff dependency graph shows the same tags for two entries, those should be able to access each other
Goal:
The general structure I want to achive consists out of different domains, that should not be allowed to import from each other (besides if they offer APIs, but I did not set this up in hte dependency rules yet)
The domain itself is not a module, but the underlying folders are.
There is always at least one "public" feature that can be imported from root.
There can be internal elements as well (inside /internal
folder). To enforce the correct dependency constrains, I also try to detect elements inside /internal
folder with the module configuration.
├───domains
│ ├───sales-orders
│ │ ├───feature-a
│ │ └───internal
│ │ ├───feature-b
│ │ ├───ui-a
│ │ └───...
│ ├───shared
│ │ └───internal
│ └───vehicle-configurator
│ ├───feature-c
│ └───internal
├───legacy code // should be excluded what is achived by setting `autoTagging` to false and only define modules for `/domains` and the `barrelFileName` is set to something different than `index.ts` to prevent that existing legacy barrels are detected
sheriff verify:
|-- projects\shell\src\app\domains\sales-orders\feature-a\feature-a.component.ts
| |-- Dependency Rule Violations
| | |-- from tag domain:sales-orders to tags domain:vehicle-configurator, type:feature // correct
| | |-- from tag type:feature to tags domain:sales-orders, type:feature // IMHO incorrect - features should be able to use other features of the same module, or not?
|-- projects\shell\src\app\domains\vehicle-configurator\feature-c\feature-c.component.ts
| |-- Dependency Rule Violations
| | |-- from tag domain:vehicle-configurator to tags domain:sales-orders, type:feature // correct
sheriff list:
. (root)
├── projects\shell\src\app\domains\sales-orders\feature-a (domain:sales-orders, type:feature)
├── projects\shell\src\app\domains\sales-orders\internal\feature-b (domain:sales-orders, type:feature)
├── projects\shell\src\app\domains\sales-orders\internal\ui-test (domain:sales-orders, type:ui)
└── projects\shell\src\app\domains\vehicle-configurator\feature-c (domain:vehicle-configurator, type:feature)
sheriff.config.ts
export const config: SheriffConfig = {
autoTagging: false,
enableBarrelLess: true,
// `barrelFileName` can be removed when the old code is refactored and no `index.ts` files exist anymore
barrelFileName: 'public-api.ts',
// apply tags to your modules
modules: {
'projects/shell/src/app/domains/<domain>/feature-<name>': ['domain:<domain>', 'type:feature'],
'projects/shell/src/app/domains/<domain>/internal/feature-<name>': ['domain:<domain>', 'type:feature'],
'projects/shell/src/app/domains/<domain>/ui-<name>': ['domain:<domain>', 'type:ui'],
'projects/shell/src/app/domains/<domain>/internal/ui-<name>': ['domain:<domain>', 'type:ui'],
'projects/shell/src/app/domains/<domain>/data-<name>': ['domain:<domain>', 'type:data'],
'projects/shell/src/app/domains/<domain>/internal/data-<name>': ['domain:<domain>', 'type:data'],
'projects/shell/src/app/domains/<domain>/util-<name>': ['domain:<domain>', 'type:util'],
'projects/shell/src/app/domains/<domain>/internal/util-<name>': ['domain:<domain>', 'type:util']
},
depRules: {
// module rules definitions
root: '*',
noTag: 'noTag',
// each domain can depend on itself and shared
'domain:*': [sameTag, 'domain:shared'],
// type rule definitions
'type:feature': ['type:ui', 'type:data', 'type:util'],
'type:ui': ['type:data', 'type:util'],
'type:data': ['type:util'],
'type:util': []
}
};
sheriff export::
{
"projects\\shell\\src\\main.ts": {
"module": ".",
"moduleType": "barrel-less",
"tags": [
"root"
],
"imports": [
"projects\\shell\\src\\bootstrap.ts"
],
"externalLibraries": []
},
"projects\\shell\\src\\bootstrap.ts": {
"module": ".",
"moduleType": "barrel-less",
"tags": [
"root"
],
"imports": [
"projects\\shell\\src\\app\\app.module.ts"
],
"externalLibraries": [
"@angular/platform-browser-dynamic"
]
},
"projects\\shell\\src\\app\\app.module.ts": {
"module": ".",
"moduleType": "barrel-less",
"tags": [
"root"
],
"imports": [
... // removed some stuff here
"projects\\shell\\src\\app\\domains\\sales-orders\\feature-a\\feature-a.component.ts"
],
"externalLibraries": [
... // removed some stuff here
]
},
// removed some entries about legacy code that can not be shared, but should also not be part of the Sheriff modules
"projects\\shell\\src\\app\\domains\\sales-orders\\feature-a\\feature-a.component.ts": {
"module": "projects\\shell\\src\\app\\domains\\sales-orders\\feature-a",
"moduleType": "barrel-less",
"tags": [ // same tags as feature-b.component.ts
"domain:sales-orders",
"type:feature"
],
"imports": [
"projects\\shell\\src\\app\\domains\\vehicle-configurator\\feature-c\\feature-c.component.ts",
"projects\\shell\\src\\app\\domains\\sales-orders\\internal\\feature-b\\feature-b.component.ts"
],
"externalLibraries": [
"@angular/core"
]
},
"projects\\shell\\src\\app\\domains\\vehicle-configurator\\feature-c\\feature-c.component.ts": {
"module": "projects\\shell\\src\\app\\domains\\vehicle-configurator\\feature-c",
"moduleType": "barrel-less",
"tags": [
"domain:vehicle-configurator",
"type:feature"
],
"imports": [
"projects\\shell\\src\\app\\domains\\sales-orders\\internal\\feature-b\\feature-b.component.ts"
],
"externalLibraries": [
"@angular/core"
]
},
"projects\\shell\\src\\app\\domains\\sales-orders\\internal\\feature-b\\feature-b.component.ts": {
"module": "projects\\shell\\src\\app\\domains\\sales-orders\\internal\\feature-b",
"moduleType": "barrel-less",
"tags": [ // same tags as feature-a.component.ts
"domain:sales-orders",
"type:feature"
],
"imports": [],
"externalLibraries": [
"@angular/core"
]
}
}