Guides: Migrate from eslint-plugin-boundaries: Turn boundaries elements into parts, element-types into a table, and entry-point into the entry shorthand. # Migrate from eslint-plugin-boundaries > Turn boundaries elements into parts, element-types into a table, and entry-point into the entry shorthand. This guide moves an eslint-plugin-boundaries setup to archangel. The two tools have the same idea: give names to areas of the code, then say which area may import which. In archangel, the names are **parts**, and the main rule is a **table**. ## The config before eslint.config.js ```js import boundaries from 'eslint-plugin-boundaries'; export default [ { plugins: { boundaries }, settings: { 'boundaries/elements': [ { type: 'app', pattern: 'src/app/**', mode: 'full' }, { type: 'feature', pattern: 'src/features/*', capture: ['featureName'] }, { type: 'shared', pattern: 'src/shared/**', mode: 'full' }, ], }, rules: { 'boundaries/element-types': ['error', { default: 'disallow', rules: [ { from: 'app', allow: ['feature', 'shared'] }, { from: 'feature', allow: ['shared', ['feature', { featureName: '${from.featureName}' }]] }, { from: 'shared', allow: ['shared'] }, ], }], 'boundaries/entry-point': ['error', { default: 'disallow', rules: [{ target: ['feature'], allow: 'index.ts' }], }], }, }, ]; ``` ## Map each setting | eslint-plugin-boundaries | archangel | | ----------------------------------------------------------- | --------------------------------------------------------------------------------------- | | An element in `boundaries/elements` | A part in `parts`. | | `pattern` with `mode: 'full'` | A path pattern that ends in `/**`, from the config folder. | | `pattern: 'src/features/*'` with `capture: ['featureName']` | `'src/features/{featureName}/**'`. The capture goes in the pattern. | | `boundaries/element-types` with `default: 'disallow'` | A table. Each `from` is a row, and its `allow` list is the row’s list. | | `allow` of the same element with `${from.featureName}` | Nothing. A row may import its own part in the same instance by default. | | `allow` of another instance of the same element | Add the part to its own row, for example `feature: ['shared', 'feature']`. | | `boundaries/entry-point` | `entry('feature', 'index.ts')`. | | `boundaries/no-private` | `entry`, or `isolate` for instances that may not import each other at all. | | `boundaries/external` | A cell that names an externals set, or a rule with `mayNotImport: { packages: [...] }`. | | `boundaries/no-unknown-files` | A rule with `mustNotExist` on the files that are in no part. | ## The config after archangel.config.ts ```ts import { defineConfig } from '@enhance-eng/archangel'; export default defineConfig({ parts: { app: 'src/app/**', feature: 'src/features/{featureName}/**', shared: 'src/shared/**', }, rules: ({ entry, mayImport }) => [ mayImport('element-types', { app: ['feature', 'shared'], feature: ['shared'], shared: [], }), entry('feature', 'index.ts', { name: 'entry-point', examples: { rejected: ['src/app/main.ts imports src/features/login/form.ts'], }, }), ], }); ``` * Each element type is a part. The capture `{featureName}` makes each folder in `src/features` one instance. * The table `element-types` keeps the name of the old rule. Its rows are named `element-types.app`, `element-types.feature` and `element-types.shared`. * The `entry` shorthand takes the name `entry-point`, with a rejected example. ## Run it 1. Prove the rules: Terminal ```ansi $ npx archangel test pass entry-point rejected #1 src/app/main.ts, src/features/login/form.ts 1 examples, none failed; 0 rules without a rejected example 3 table rows need no written example; `archangel rules` shows what each covers ``` 2. Check the repository: Terminal ```ansi $ npx archangel check error[entry]: "../features/cart/cart-total" reaches inside "cart" of "feature" past its entry files --> src/app/main.ts:1:27 | 1 | import { cartTotal } from '../features/cart/cart-total'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ import it through "../features/cart" | = note: rule: entry-point error[may-import]: feature may not import another instance of feature, through "../cart": feature may import only shared, and itself in the same instance --> src/features/checkout/index.ts:1:27 | 1 | import { cartTotal } from '../cart'; | ^^^^^^^^^ feature may import only shared, and itself in the same instance | = help: remove the import, or move the code to a file whose row permits the import = note: rule: element-types.feature checked 6 files and 6 imports: 2 problems For what a code means, run `archangel docs entry` or `archangel docs may-import`. ``` `app/main.ts` reaches past the entry file of `cart`, and `checkout` imports another feature. Compare these problems with what ESLint reports before you remove the plugin. 3. Read what each row judged: Terminal ```ansi $ npx archangel rules element-types 3 rows archangel.config.ts:10 element-types.app: app may import only feature, shared, and itself 1 file · 2 imports judged · 0 problems · 0 exceptions element-types.feature: feature may import only shared, and itself in the same instance 3 files · 3 imports judged · 1 problem · 0 exceptions element-types.shared: shared may import only itself 1 file · 0 imports judged · 0 problems · 0 exceptions element-types.every-file-has-a-kind: a file in no row is not checked here; add `files` to check it 5 files · 0 problems entry-point archangel.config.ts:16 files in feature may be imported from outside their instance only through its entry files index.ts 3 files · 4 imports judged · 1 problem · 0 exceptions Not judged by any rule: 0 files, 0 imports between repository files. Outside packages that no rule names: none. ``` ## Results that change * **One run checks all files.** ESLint runs the plugin on each file, and the plugin resolves the imports of that file. `archangel check` reads the repository one time, and it can also check cycles and chains of imports. * **Each file is in one part at most.** boundaries takes the first element that matches a file. In archangel, a file that two parts find is the error [`part-overlap`](/archangel/reference/diagnostics/part-overlap/). Make the patterns disjoint, or make one of them a group. * **An element that finds no file is an error.** In archangel, this is [`element-empty`](/archangel/reference/diagnostics/element-empty/). It usually shows a pattern with a typing error. * **A table refuses imports into the repository only.** A table judges a package only when a cell names an externals set that holds it. See [Tables, rows and cells](/archangel/concepts/tables-rows-and-cells/). Keep ESLint for the rest Remove eslint-plugin-boundaries when archangel gives the same results. Keep ESLint for code style and for rules that need types.