Reference: Tables: The mayImport table, its rows, cells and options, and the rules that it makes.
# Tables
> The mayImport table, its rows, cells and options, and the rules that it makes.
A table says what each set of files may import. It is the main form of an architecture test. For the ideas behind it, read [Tables, rows and cells](/archangel/concepts/tables-rows-and-cells/).
```ts
mayImport(name, rows, options)
```
| Argument | Type | What it is |
| --------- | ------ | -------------------------------------------------------------- |
| `name` | string | The name of the table. It has no `:` and no `/`. |
| `rows` | object | One row for each set of files. The value is the list of cells. |
| `options` | object | Optional, except `kinds` for a table of kinds. |
This table has rows of parts:
```ts
mayImport('backend', {
routes: ['services'],
services: ['domain', 'db'],
db: ['domain', 'driver'],
domain: [],
}, {
because: 'A route calls a service. Only db talks to the database.',
})
```
## Rows
A row name means, in this order:
1. the declared part or group with that name;
2. in a table with `kinds`, the kind with that name.
A row cannot name an externals set. Archangel refuses a row name that means nothing, and shows the nearest declared name.
Each row is a rule with the name `.`, for example `backend.routes`. Use this name in `off`, in an exception comment and in the baseline.
## Cells
A cell is one name in the list of a row. A cell can be:
* the name of a row of the same table;
* the name of a part, a group or an externals set;
* a path pattern, such as `'src/config.ts'` or `'src/generated/**'`.
Archangel refuses a cell that is none of these.
## What a row permits
A row permits only:
1. the cells in its list;
2. its own name, in the same instance. A row of a part with a capture permits imports inside its own instance, and refuses imports into other instances of that part. Use `mayNotImportItself` to remove this;
3. the cells in `everyRowMayImport`.
The row refuses each other import into the repository. An import of a file that has no row gives the message “no row for …”.
**A table judges a package only when a cell names it.** A table judges an import of an outside package only when a cell, or `everyRowMayImport`, names an externals set with that package. So a row with an empty list can still import each package that no cell names. To refuse a package, put it in an externals set and name the set in the cells of the rows that may use it.
## Options
| Option | Type | Default | What it does |
| ---------------------------------------------- | ------------------------------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `kinds` | path pattern with `{kind}` | none | The pattern that gives each file its kind. With it, a row name can be a kind. Read [Kinds](/archangel/concepts/kinds/). |
| `files` | set of files | each file with a row | The importers that the table judges. With `files`, each file in the set must have a row. |
| `within` | set of files | the repository | The area of the table. The rows judge only imports whose target is in the area. |
| `everyRowMayImport` | list of cells | `[]` | Cells that each row has, for example a file that all code may use. |
| `mayNotImportItself` | list of row names | `[]` | Rows that may not import their own name, in the same instance or in a different instance. |
| `because` | string | none | The reason, which each problem shows. |
| `link` | string | none | A link, which each problem shows. |
| `examples` | object | none | Examples for the whole table. A row needs no written example. |
| `imports` | `'all'`, `'runtime'`, `'static'`, `'types'` | `'all'` | The kinds of import that each row counts. |
| `names`, `specifier`, `instance`, `dependency` | | none | The same as for an import condition. Each row gets the option. Read [Import options](/archangel/reference/import-options/). |
A row that `everyRowMayImport` names cannot be in `mayNotImportItself`.
### `kinds`
```ts
mayImport('model', {
entity: ['value-object'],
event: ['entity', 'value-object'],
'value-object': [],
}, {
files: 'domain',
kinds: 'src/domain/*.{kind}.ts',
})
```
| Pattern | File | Kind |
| -------------------------- | ---------------------------------- | -------- |
| `**/*.{kind}.ts` | `src/order/order.entity.ts` | `entity` |
| `src/features/*/{kind}/**` | `src/features/cart/views/page.tsx` | `views` |
| `**/{kind}/**/*.{kind}.ts` | `src/entity/user.entity.ts` | `entity` |
`{kind}` can be two times in a pattern. Then the two places must give the same name. A declaration file counts `.d.ts` as one extension, so `env.d.ts` has no kind `d`.
A row name that is a declared part or group means that part or group, also when the kind pattern gives the same name.
The `files` option does not change the kind of a file. It only chooses the importers that the table judges. A file outside `files` still has its kind when a file in `files` imports it.
### `files`
Without `files`, the table judges each file that has a row. A file that has no row is not checked, and `archangel rules` lists it under the files that no rule judges.
With `files`, each file in the set must have a row. A file without a row is a problem of the rule `.every-file-has-a-kind`, with the code [`every-file-has-a-kind`](/archangel/reference/diagnostics/every-file-has-a-kind/). To let a file out, use `not` in `files`, or put `.every-file-has-a-kind` in `off`.
### `within`
```ts
mayImport('domain-model', {
entity: ['value-object'],
'value-object': [],
}, {
kinds: 'src/domain/*.{kind}.ts',
within: 'domain',
})
```
With `within`, the table ignores each import whose target is outside the area. Here, a domain file can import a package or a file in `shared`, and the table does not judge it.
## The rules that a table makes
A table with the rows `routes` and `services` makes these rules:
| Rule | It refuses |
| ------------------------------- | -------------------------------------------------------------- |
| `.routes` | an import of a file in `routes` that its row does not permit |
| `.services` | an import of a file in `services` that its row does not permit |
| `.every-file-has-a-kind` | a file in the table’s `files` that has no row |
`archangel rules` shows each one as a sentence:
Terminal
```ansi
$ npx archangel rules
backend 4 rows archangel.config.ts:14
because: A route calls a service. Only db talks to the database. The domain depends on nothing.
backend.routes: routes may import only services, and itself
2 files · 2 imports judged · 1 problem · 0 exceptions
backend.services: services may import only domain, db, and itself
1 file · 2 imports judged · 0 problems · 0 exceptions
backend.db: db may import only domain, driver, and itself
1 file · 2 imports judged · 0 problems · 0 exceptions
backend.domain: domain may import only itself
3 files · 3 imports judged · 0 problems · 0 exceptions
backend.every-file-has-a-kind: a file in no row is not checked here; add `files` to check it
7 files · 0 problems
model 3 rows archangel.config.ts:23
because: An entity does not know its events. A service publishes them.
model.entity: entity may import only value-object, and itself
1 file · 2 imports judged · 1 problem · 0 exceptions
model.event: event may import only entity, value-object, and itself
1 file · 1 import judged · 0 problems · 0 exceptions
model.value-object: value-object may import only itself
1 file · 0 imports judged · 0 problems · 0 exceptions
model.every-file-has-a-kind: every file of model has a row
3 files · 0 problems
no-cycles archangel.config.ts:33
because: Files that import each other cannot change one at a time.
files in src/** may not import each other in a cycle
7 files · 0 problems
Not judged by any rule: 0 files, 0 imports between repository files.
Outside packages that no rule names: none.
```
## Errors in a table
| Code | When |
| -------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
| [`table-empty`](/archangel/reference/diagnostics/table-empty/) | The table has no row, or its rows find no file, so it checks nothing. |
| [`table-row-overlap`](/archangel/reference/diagnostics/table-row-overlap/) | Two rows find one file. |
| [`rule-unknown-element`](/archangel/reference/diagnostics/rule-unknown-element/) | A row or a cell names nothing. |
| [`config-invalid`](/archangel/reference/diagnostics/config-invalid/) | A name has a `:` or a `/`, or an option has a wrong value. |
One row that finds no file is not an error, because you can write a row before its first file exists. `archangel check` and `archangel rules` list that row. A table in a preset that checks nothing gives one line in the summary, not an error.
## A table in JSON
In a JSON config, a table is an object with `"kind": "mayImport"`, a `name` and its `rows`:
archangel.config.json
```json
{
"$schema": "./node_modules/@enhance-eng/archangel/archangel.schema.json",
"parts": {
"feature": "src/features/{feature}/**",
"shared": "src/shared/**"
},
"rules": [
{
"kind": "mayImport",
"name": "app",
"rows": { "feature": ["shared"], "shared": [] },
"because": "Shared code never depends on a feature."
}
]
}
```
The options have the same names. For a table of kinds, add `"kinds": "src/features/*/{kind}/**"`.