Skip to content

Validation Rules

The library uses a hybrid validation strategy: some rules are checked immediately, others are deferred to build time.

Validation Strategy

ValidationWhenRationale
Domain existsImmediateCatch typos early
Name format (no whitespace)ImmediateCatch invalid names immediately
Required fields presentImmediateSchema compliance
Custom type registeredImmediateFail fast on unknown types
Custom type required fieldsImmediateType-specific validation
Link targets existDeferred (build)Allow forward references
Component references valid domainDeferred (build)Full graph needed

Immediate Validation

These checks happen when you call the method:

Domain Must Exist

typescript
const builder = new RiviereBuilder({
  domains: {
    orders: { description: '...', systemType: 'domain' }
  },
  sources: [{ repository: 'your-repo/orders' }]
})

builder.addUseCase({
  domain: 'shipping',
  module: 'checkout',
  name: 'place-order',
  sourceLocation: {
    repository: 'your-repo/orders',
    filePath: 'src/use-cases/place-order.ts',
    lineNumber: 10
  }
})

Error:

text
Unknown domain: "shipping". Available domains: orders

Name Cannot Contain Whitespace

typescript
builder.addUseCase({
  domain: 'orders',
  module: 'checkout',
  name: 'place order',
  sourceLocation: {
    repository: 'your-repo/orders',
    filePath: 'src/use-cases/place-order.ts',
    lineNumber: 10
  }
})

Error:

text
Invalid name: "place order". Names cannot contain whitespace. Use kebab-case instead.

Custom Type Must Be Registered

typescript
builder.addCustom({
  domain: 'messaging',
  module: 'queues',
  customType: 'Queue',
  name: 'my-queue',
  queueName: 'my-queue',
  sourceLocation: {
    repository: 'your-repo/messaging',
    filePath: 'src/queues/my-queue.ts',
    lineNumber: 1
  }
})

Error:

text
Unknown custom type: "Queue". Define it first with defineCustomType() or in builder config.

Custom Type Required Fields

typescript
builder.defineCustomType('Queue', {
  requiredFields: ['queueName']
})

builder.addCustom({
  domain: 'messaging',
  module: 'queues',
  customType: 'Queue',
  name: 'my-queue',
  sourceLocation: {
    repository: 'your-repo/messaging',
    filePath: 'src/queues/my-queue.ts',
    lineNumber: 1
  }
})

Error:

text
Custom type "Queue" requires field "queueName"

Deferred Validation (Build Time)

These checks happen when you call build():

typescript
builder.link(api, useCase, 'sync')

const graph = builder.build()

Error:

text
Validation failed:
Link target not found: orders:checkout:usecase:missing

Component Domains Must Be Valid

Components reference domains from config. At build time, this is verified:

typescript
const graph = builder.build()

Error:

text
Validation failed:
Component "orders:checkout:usecase:placeorder" references unknown domain: orders

Build-Time Validation

The build() method runs full validation before returning the graph:

typescript
const graph = builder.build()

If validation fails, an error is thrown with all issues:

text
Validation failed:
Link source not found: api-missing
Link target not found: usecase-missing
Component "bad:module:usecase:test" references unknown domain: bad

Manual Validation

You can validate without building:

typescript
const result = builder.validate()
// { valid: boolean, errors: string[] }

if (!result.valid) {
  console.log(result.errors)
}

Duplicate Handling

Adding a component with the same ID overwrites the previous one silently. Adding a link with the same ID is silently ignored (idempotent).

Summary

CheckTimingMethod
Domain existsImmediateAll add* methods
Name formatImmediateaddUI, addUseCase, addEvent, addEventHandler, addCustom
Custom type existsImmediateaddCustom
Custom required fieldsImmediateaddCustom
Link targets existBuildbuild()
All domains validBuildbuild()