javierbrea / eslint-plugin-boundaries

Eslint plugin checking architecture boundaries between elements
MIT License
473 stars 9 forks source link

Disallow imports from the same boundary element in monorepo #294

Closed ledamint closed 11 months ago

ledamint commented 1 year ago

Describe the bug monorepo entities-package1 entities/packages/package1 entities-package2 entities/packages/package2 features-package1 features/packages/package1

I want to restrict import entities packages from all other packages in entities. For example

// entities/packages/package1/src/index.js
import {something} from 'entities-package2' // want to see error

In config I allowed imports from libs and shared without entities - {from: 'entities', allow: ['libs', 'shared']} but I don't get the error.

For example if I try to import from features folder I get the error.

// entities/packages/package1/src/index.js
import {something} from 'features-package1' // error works properly

To Reproduce Set up monorepo and add one eslint config (attached below) to root of repository.

Expected behavior Want to restrict imports from the same boundary element in monorepo.

Operating system

Additional context eslint config

module.exports = {
  env: {
    node: true,
    jest: true,
  },
  settings: {
    'import/resolver': {typescript: {alwaysTryTypes: true}},
    'boundaries/elements': [
      {
        type: 'app',
        pattern: 'app/**/*',
        mode: 'folder',
      },
      {
        type: 'processes',
        pattern: 'processes/**/*',
        mode: 'folder',
      },
      {
        type: 'pages',
        pattern: 'pages/**/*',
        mode: 'folder',
      },
      {
        type: 'widgets',
        pattern: 'widgets/**/*',
        mode: 'folder',
      },
      {
        type: 'features',
        pattern: 'features/**/*',
        mode: 'folder',
      },
      {
        type: 'entities',
        pattern: 'entities/**/*',
        mode: 'folder',
      },
      {
        type: 'libs',
        pattern: 'libs/**/*',
        mode: 'folder',
      },
      {
        type: 'shared',
        pattern: 'shared/**/*',
        mode: 'folder',
      },
    ],
    'boundaries/ignore': ['**/*.test.*'],
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react-hooks/recommended',
    'prettier',
  ],
  parser: '@typescript-eslint/parser',
  plugins: [
    '@typescript-eslint',
    'eslint-plugin-react',
    'import',
    'boundaries',
  ],
  rules: {
    'boundaries/element-types': [
      'warn',
      {
        default: 'disallow',
        rules: [
          {
            from: 'app',
            allow: [
              'processes',
              'pages',
              'widgets',
              'features',
              'entities',
              'libs',
              'shared',
            ],
          },
          {
            from: 'processes',
            allow: [
              'pages',
              'widgets',
              'features',
              'entities',
              'libs',
              'shared',
            ],
          },
          {
            from: 'pages',
            allow: ['widgets', 'features', 'entities', 'libs', 'shared'],
          },
          {from: 'widgets', allow: ['features', 'entities', 'libs', 'shared']},
          {from: 'features', allow: ['entities', 'libs', 'shared']},
          {from: 'entities', allow: ['libs', 'shared']},
          {from: 'libs', allow: ['libs', 'shared']},
          {from: 'shared', allow: ['shared', 'libs']},
        ],
      },
    ],
  },
  ignorePatterns: [
    '*.g.ts',
    '*.d.ts',
    '*.config.js',
    '**/dist/**/*.js',
    '**/build/**/*.js',
    '**/node_modules/*',
  ],
};
javierbrea commented 1 year ago

Hi @ledamint , could you please provide a repository with a reproducible example? I'm sorry but I don't have enough context to see what can be wrong in the config. I suppose you are in a monorepo, and you have aliases for imports... is the eslint config being able to interpret aliases? Is the plugin config detecting properly each type of file as the type you pretend to assign to it?

ledamint commented 1 year ago

@javierbrea Thanks for response. I created an example https://github.com/ledamint/monorepo-example-boundaries/tree/main

File https://github.com/ledamint/monorepo-example-boundaries/blob/main/entities/packages/example1/src/index.ts

import all2 from '@monorepo-example/example2'
import all3 from '@monorepo-example/example3'

example2 is located inside entities example3 is located inside features

I allow all packages inside entities to import only libs and shared {from: 'entities', allow: ['libs', 'shared']},

So for this file I cant import from entities and features and want to get 2 errors with these imports. But I get only 1 error - with example3 (features) and not getting an error with example2 (entities).

Screenshot 2023-06-19 at 16 52 45

javierbrea commented 1 year ago

@ledamint , the problem seems to be in the pattern that you are using to detect each entity. It produces to detect all code in the entities folder as the same entity, because of the double asterisk. Just replace it by a single asterisk corresponding to the folder of the entity name, or you can even be more specific and capture the name of the matching folder as package "name" in order to improve the logs:

{
      type: 'features',
      pattern: 'features/packages/*',
      mode: 'folder',
      capture: ["name"]
    },
    {
      type: 'entities',
      pattern: 'entities/packages/*',
      mode: 'folder',
      capture: ["name"]
    }

I have tested this configuration in your example repository, and it works. You can also see here how logs improve:

image

ledamint commented 11 months ago

Thanks, that helps