Skip to content

Incorrect linter warning for same module #211

@J-O-W-O

Description

@J-O-W-O

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:

Image

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"
    ]
  }
}

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions