Skip to content

domain-purity ​

The domain depends on nothing but itself. It imports its own domain, the domain of the shared kernel and the domain building blocks of @alveolus/core: no framework, no ORM, no other layer.

❌ Avoid: src/ordering/domain/aggregates/order.aggregate.ts
ts
import { Injectable } from "@nestjs/common";
import { AggregateRoot, UnitOfWork } from "@alveolus/core";
import { Column, Entity } from "typeorm";

import { Mailer } from "../../driven/smtp/adapters/mailer.adapter";
✅ Prefer: src/ordering/domain/aggregates/order.aggregate.ts
ts
import { AggregateRoot, err, ok, type Result } from "@alveolus/core";

import { Money } from "../../../shared-kernel/domain/value-objects/money.value-object";
import { InvalidTotal } from "../errors/invalid-total.error";

What it checks ​

Every import of a file in domain/, in a bounded context or in the shared kernel:

ImportAllowed when
A file of the projectIt is in the domain/ of the same context or of the shared kernel.
@alveolus/coreEvery imported name is a domain building block or part of Result: AggregateRoot, Entity, ValueObject, Identifier, DomainEvent, DomainError, DomainService, Port, Clock, IdGenerator, CommandRepository, QueryRepository, View, Result, ok, err, map, mapErr, andThen, combine and their Any… types.
Any other packageIt is listed in domainDependencies; when its entry lists names, every imported name is one of them.

Importing from the root @alveolus/core is fine: the rule checks each imported name, not the path.

Why ​

The domain holds the business rules: they should change when the business does, not when a library does. A domain that imports nothing technical runs and is tested without a database, a clock or a framework, and survives a change of any of them.

Allow a package ​

Some packages belong in a domain, such as a decimal library for money. Declare them, with true to allow everything they export, or with the names you allow:

alveolus.config.ts
ts
export default defineConfig({
	boundedContexts: { ordering: "ordering" },
	domainDependencies: { "date-fns": ["addDays", "isBefore"], "decimal.js": true },
	root: "src",
});

Importing another name from a restricted package is reported: The domain imports format from date-fns: domainDependencies only allows addDays, isBefore.

The application may use them too.

What it reports ​

src/ordering/domain/aggregates/order.aggregate.ts:1
  domain-purity: The domain imports @nestjs/common: add it to domainDependencies if the domain really needs it.

src/ordering/domain/aggregates/order.aggregate.ts:2
  domain-purity: The domain imports UnitOfWork from @alveolus/core: only domain building blocks and Result are allowed.

src/ordering/domain/aggregates/order.aggregate.ts:5
  domain-purity: The domain imports src/ordering/driven/smtp/adapters/mailer.adapter.ts (ordering driven): it may only import the domain.

Turn it off ​

ts
rules: { "domain-purity": "off" }

See also ​

Released under the MIT License.