Kinds
Markdown for agentsSome codebases say what a file is in its name or its folder: order.entity.ts,
order.repository.ts, views/cart-page.tsx. A kind turns that name into a table row. You
write one pattern, and archangel gives each file its kind. You do not declare a part for each kind.
The kinds pattern
Section titled “The kinds pattern”A table’s kinds option is a path pattern with the capture {kind}. The value of the capture is
the file’s kind.
| Pattern | File | Kind |
|---|---|---|
**/*.{kind}.ts |
src/orders/order.entity.ts |
entity |
src/features/*/{kind}/** |
src/features/cart/views/page.tsx |
views |
**/{kind}/**/*.{kind}.ts |
src/entity/order.entity.ts |
entity |
{kind}can be in a pattern two times. Then the two places must give the same name.- A declaration file counts
.d.tsas one extension. Soenv.d.tshas no kindd. - A file that the pattern does not match has no kind.
A table of kinds
Section titled “A table of kinds”This table uses the end of each file name as its kind. It also has one row, shared, that is a
part. One table can mix kinds, parts and groups:
import { defineConfig } from '@enhance-eng/archangel';
export default defineConfig({ parts: { shared: 'src/shared/**', }, rules: ({ mayImport }) => [ mayImport('orders', { service: ['repository', 'entity', 'shared'], repository: ['entity', 'shared'], entity: ['shared'], shared: [], }, { kinds: 'src/**/*.{kind}.ts', files: 'src/**', because: 'A service uses repositories. A repository stores entities. An entity knows only itself.', }), ],});archangel explain shows the kind of a file. The file is in no part, but it has the kind service
in the table orders:
$ npx archangel explain src/orders/place-order.service.tssrc/orders/place-order.service.ts part: no part; no file pattern matches it: "shared" src/shared/**: the path does not start with "src/shared/" kind: service in orders groups: none rules that apply: orders.service orders.service: service may import only repository, entity, shared, and itself (judges its imports) imports: line 1 './order.entity' -> src/orders/order.entity.ts line 2 './order.repository' -> src/orders/order.repository.ts line 3 './order.helpers' -> src/orders/order.helpers.ts breaks orders.service imported by: noneA new kind is not a silent gap
Section titled “A new kind is not a silent gap”The repository has a file that the table does not know: order.helpers.ts. Its kind is
helpers, and the table has no row for it. Two rules find it:
$ npx archangel checkerror[every-file-has-a-kind]: src/orders/order.helpers.ts has the kind helpers, and the table "orders" has no row for it: no row for helpers. To fix this, add a row, rename the file, or leave it out of the table's files with `not`--> src/orders/order.helpers.ts = help: add a row, rename the file, or leave it out of the table's files with `not` = note: rule: orders.every-file-has-a-kind = note: because: A service uses repositories. A repository stores entities. An entity knows only itself.
error[may-import]: service may not import helpers, through "./order.helpers": no row for helpers, and service may import only repository, entity, shared, and itself --> src/orders/place-order.service.ts:3:28 |3 | import { orderTotal } from './order.helpers'; | ^^^^^^^^^^^^^^^^^ service may import only repository, entity, shared, and itself | = help: remove the import, or move the code to a file whose row permits the import = note: rule: orders.service = note: because: A service uses repositories. A repository stores entities. An entity knows only itself.
checked 6 files and 7 imports: 2 problemsFor what a code means, run `archangel docs every-file-has-a-kind` or `archangel docs may-import`.orders.every-file-has-a-kindrefuses the file itself. This rule checks only the files in the table’sfiles, heresrc/**. Withoutfiles, this rule checks nothing.orders.servicerefuses the import of the file, because the rowservicedoes not listhelpers, and the table has no row for it.
To fix it, decide where helpers belong in your architecture. Add a row, and name it in the rows that may import it:
import { defineConfig } from '@enhance-eng/archangel';
export default defineConfig({ parts: { shared: 'src/shared/**', }, rules: ({ mayImport }) => [ mayImport('orders', { service: ['repository', 'entity', 'helpers', 'shared'], repository: ['entity', 'shared'], entity: ['shared'], helpers: ['entity', 'shared'], shared: [], }, { kinds: 'src/**/*.{kind}.ts', files: 'src/**', because: 'A service uses repositories. A repository stores entities. An entity knows only itself.', }), ],});$ npx archangel checkchecked 6 files and 7 imports: no problemsYou can also rename the file so that it has a kind with a row, or leave it out of the table’s
files with not.
Kinds or parts
Section titled “Kinds or parts”| Use | When |
|---|---|
| A kind | One pattern gives the names, for many folders or file endings. You add a kind when you add the first file with that ending, and the table tells you if it has no row. |
| A part | The area has a name of its own, and rules other than this table use it. A rule’s files can name a part. |
A kind has a meaning only in its table. A rule’s files cannot name a kind. To select the same
files in a rule, write the pattern, for example files: 'src/**/*.entity.ts'.