domaintrail 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.ja.md +303 -0
- package/CHANGELOG.md +304 -0
- package/README.md +65 -170
- package/dist/dt.js +4457 -2630
- package/dist/web/chunk-4bbfrcw1.css +1 -0
- package/dist/web/{chunk-g3azafq4.js → chunk-64rawkq2.js} +108 -108
- package/dist/web/index.html +1 -1
- package/package.json +14 -3
- package/schema/diagnostics.schema.json +5 -0
- package/schema/domaintrail.schema.json +32 -7
- package/dist/web/chunk-cgxb04qn.css +0 -1
package/CHANGELOG.ja.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# 変更履歴
|
|
2
|
+
|
|
3
|
+
[English](CHANGELOG.md)
|
|
4
|
+
|
|
5
|
+
domaintrail の各バージョンの変更点です。形式は [Keep a Changelog](https://keepachangelog.com/ja/) に、バージョン番号は
|
|
6
|
+
[セマンティック バージョニング](https://semver.org/lang/ja/) に従います(1.0.0 より前は、マイナーバージョンでもモデルやコードに
|
|
7
|
+
影響する変更があります)。
|
|
8
|
+
|
|
9
|
+
**domaintrail を更新したら**、更新前から更新後までの各バージョンの **アップグレード手順**を古い順に読み、その手順に
|
|
10
|
+
従ってください。このファイルはパッケージに含まれています: `node_modules/domaintrail/CHANGELOG.ja.md`(英語版は
|
|
11
|
+
`CHANGELOG.md`)。
|
|
12
|
+
|
|
13
|
+
## [0.6.0] - 2026-10-28
|
|
14
|
+
|
|
15
|
+
### 追加
|
|
16
|
+
|
|
17
|
+
- **Live View を git のリビジョンと比較**(`docs/live-view.md`): ヘッダーの 比較対象 メニュー、または変更ペインの見出しから、
|
|
18
|
+
追加・変更・削除を何と比べて表示するかを選べます — 前回の保存(既定)か、git のリビジョン(ブランチ、タグ、最近のコミット、
|
|
19
|
+
または入力した任意のリビジョン)です。`dt view --base <ref>` で最初から指定して起動できます。図はノードのフィールドに、
|
|
20
|
+
インスペクターは 構造・状態遷移・振る舞い タブの行に印を付けます(追加、変更、削除は取り消し線、変更されたものは変更前の値も
|
|
21
|
+
表示)。
|
|
22
|
+
- **Getting started** を英語と日本語で追加しました(`docs/getting-started.md`、`docs/getting-started.ja.md`)。README は
|
|
23
|
+
それを中心に再構成しました。
|
|
24
|
+
- 変更履歴をパッケージに含めました(`node_modules/domaintrail/CHANGELOG.md`、`CHANGELOG.ja.md`)。`dt guide` は、更新後に
|
|
25
|
+
そのアップグレード手順に従うようエージェントに伝えます。
|
|
26
|
+
|
|
27
|
+
## [0.5.0] - 2026-10-24
|
|
28
|
+
|
|
29
|
+
### 追加
|
|
30
|
+
|
|
31
|
+
- **ポリシー**(`dt guide reactions`、ADR 0022): `policy P when Event -> Aggregate.command` — イベントが起きたら、
|
|
32
|
+
ポリシーを宣言したコンテキスト自身のコマンドがいずれ実行される、という反応を書けます。M023 がイベント・集約・コマンドを
|
|
33
|
+
検査し、同じ反応の重複を警告します。ポリシーごとに、イベントからコマンドの入力(`<Command><Aggregate>Input`)を作る
|
|
34
|
+
ハンドラの型が生成されます。`generate.ts.policies: "required"`(既定は `"optional"`、`generate.ts.contexts` で
|
|
35
|
+
コンテキストごとにも指定可)にすると `<Context>PolicyHandlers` が生成され、契約テストがそれを受け取り、どのイベントも
|
|
36
|
+
コマンドが受け付ける入力になることを検査します。コンテキストマップはポリシーをイベントによる依存として数えます。
|
|
37
|
+
- **検証済み型**(`dt guide verified`、ADR 0023): `verified X of T for C? errors E` — 集約の外で行った検査(他の誰も
|
|
38
|
+
使っていないメールアドレスなど)の証拠です。作れるのは利用者が書く非同期ファクトリ `Make<Name>` だけで、コマンドは
|
|
39
|
+
それを引数として受け取ります。M024 は検証済み型をコマンドの引数に限ります。
|
|
40
|
+
- **ペイロードの名前**(ADR 0021): イベントやエラーのフィールドが、名前の違う値(引数、そのフィールド、コマンド前後の
|
|
41
|
+
集約のフィールド)から値を取っていそうなときに M022 が警告します。
|
|
42
|
+
- **Zed 拡張**(`editors/zed`)と **tree-sitter 文法**(`tree-sitter-domaintrail`): Zed でのハイライト、アウトライン、
|
|
43
|
+
`dt lsp`。tree-sitter を使う他のエディタ向けの文法(`dt guide editors`)。
|
|
44
|
+
- **キャストを防ぐ lint**(`dt guide lint`): どのドメイン型も `as` を使わずに作る方法と、oxlint または
|
|
45
|
+
typescript-eslint で `no-unsafe-type-assertion` を有効にする方法。oxlint / ESLint の設定がこのルールに触れていないとき、
|
|
46
|
+
`dt generate ts` がヒントを表示します(`--format json` では `hints`)。`"lintHint": false` で止められます。ID、
|
|
47
|
+
ドメインプリミティブ、検証済み型の JSDoc に、それぞれの作り方を書きました。
|
|
48
|
+
- 生成されるランタイムに `parseDecimal(text)`: `Decimal` を作る唯一の場所です。
|
|
49
|
+
- `dt guide policies`: 変わりうる方針(ポリシー)に依存するルールの書き方。
|
|
50
|
+
- `examples/shop` を完全なプロジェクトにしました: すべての集約の実装、アプリケーション層(ユースケース、リポジトリ、
|
|
51
|
+
イベントストア、ポリシー、検証済み型のファクトリ)、テスト、デモ。README で説明しています。
|
|
52
|
+
- 言語サーバー: コマンドの名前を変更(リネーム)できます。
|
|
53
|
+
|
|
54
|
+
### 変更
|
|
55
|
+
|
|
56
|
+
- ワークスペースのファイルを集めるすべてのコマンド(`check`、`generate`、`view`、`fmt`、`show`、`lsp`)は、
|
|
57
|
+
`.gitignore`(ルート、そのサブディレクトリ、リポジトリの最上位までの親ディレクトリのもの)と `.git/info/exclude` が
|
|
58
|
+
無視するファイルを読み飛ばします。`"respectGitignore": false` で無効にできます。コマンドラインで指定したファイルは
|
|
59
|
+
読み飛ばしません。
|
|
60
|
+
- 言語サーバーが設定ファイルを見つけられないとき、設定を持つディレクトリの下で最初に開いた `.dt` ファイルによって、
|
|
61
|
+
その設定がワークスペースになります。
|
|
62
|
+
|
|
63
|
+
### 修正
|
|
64
|
+
|
|
65
|
+
- `Int` や `Decimal` を基にするドメインプリミティブを、`count()` や `length()` が計算する数と比較できるようにしました。
|
|
66
|
+
|
|
67
|
+
### アップグレード手順
|
|
68
|
+
|
|
69
|
+
1. モデルの `.dt` ファイルが `.gitignore` で無視されるディレクトリにあると、ワークスペースに含まれなくなります。
|
|
70
|
+
ファイルを移すか、`domaintrail.jsonc` に `"respectGitignore": false` を書いてください。`dt check` を実行し、
|
|
71
|
+
ファイル数が以前と同じか確かめます。
|
|
72
|
+
2. M011: `parseDecimal` はランタイムの名前になりました。その名前の要素がモデルにあれば名前を変えてください。
|
|
73
|
+
3. `dt generate ts` を実行します。lint のヒントが出たら `dt guide lint` に従い(または `"lintHint": false`)、
|
|
74
|
+
コード中のドメイン型へのキャストを `make<Name>` / `parseDecimal` に置き換えます。
|
|
75
|
+
4. 新しい警告が出ることがあります: M022(イベントやエラーのフィールドを値の出どころに合わせて名前を変えるか、
|
|
76
|
+
出どころの名前をフィールドに合わせる)。警告では `dt check` は失敗しません。
|
|
77
|
+
|
|
78
|
+
## [0.4.0] - 2026-10-24
|
|
79
|
+
|
|
80
|
+
### 追加
|
|
81
|
+
|
|
82
|
+
- コマンドの **`requires`**(`dt guide requires`、ADR 0017): `requires name { expr } else Error` — 式が成り立つときだけ
|
|
83
|
+
コマンドを受け付け、成り立たなければそのエラーを返します(M019)。
|
|
84
|
+
- コマンドの **`changes`**(`dt guide changes`、ADR 0019): コマンドが変更してよいフィールド(M021)。
|
|
85
|
+
- **多重度と `when` を持つ `emits`**(`dt guide events`、ADR 0018): `X?`、`X[0..*]`、`X[1..*]`、`X[n..m]`、
|
|
86
|
+
一部の結果でだけ発生するイベントには `X when Draft ->` / `X when -> Completed`。
|
|
87
|
+
- 式の **`unique` と `contains`**、および式を持たず言葉だけで書く不変条件(M018、ADR 0016)。
|
|
88
|
+
- **決定(decision)と `decide`**(`dt guide decide`): 各コマンドは `<Command><Aggregate>Decision` として実装します —
|
|
89
|
+
遷移元の状態ごとに、結果の `set` と `events` を返し、ランタイムの `decide(<Aggregate>Shape, decision)` が集約を
|
|
90
|
+
作ります。足りないイベント、余分なイベント、変更してはいけないフィールドを、コンパイラが名前を挙げて報告します。
|
|
91
|
+
- **生成される検査とコンストラクタ**(ADR 0020): 不変条件と要件の式から `check<Name>` /
|
|
92
|
+
`check<Command><Aggregate>Requires`、すべての ID とドメインプリミティブに `make<Name>`。
|
|
93
|
+
- **生成される契約テスト**(`dt guide tests`): `generate.ts.tests`(`runner`: `bun`、`vitest`、`jest`、`node`。
|
|
94
|
+
`out`)を指定すると、`dt generate ts` がコンテキストごとに fast-check のスイートを書き出し、コンストラクタ、要件、
|
|
95
|
+
各コマンド後の不変条件、イベント、純粋性を検査します。プロジェクトに `fast-check` が必要です。
|
|
96
|
+
- **`dt fmt`**: `.dt` ファイルを、コメントを保ったまま一つの正規のレイアウトに整形します(CI 向けに `--check`)。
|
|
97
|
+
LSP の整形にも使われます。
|
|
98
|
+
- **`dt show <name>`**: 要素・状態・コマンド・コンテキストを一つ、解決した形で、使っている側とともに表示します
|
|
99
|
+
(`--format json`)。
|
|
100
|
+
- **`dt lsp`**: `dt check` の診断、定義へ移動、参照、ホバー、アウトライン、補完、リネームを提供する言語サーバー。
|
|
101
|
+
- 診断の**ヒント**(「もしかして …」や、何を変えればよいか)と、`check` と `generate ts` の `--format json`
|
|
102
|
+
(スキーマは `schema/diagnostics.schema.json`)。
|
|
103
|
+
- 生成されるすべての宣言に、DSL の位置を指す `@see <file>:<line>`。
|
|
104
|
+
- どのコマンドも扱うコード向けのランタイムヘルパー `outcome(value)`(`{ to, aggregate, events }`)と
|
|
105
|
+
`eventList(events)`。
|
|
106
|
+
- M020(警告): 集約の ID 型の引数を持たない `create command`。
|
|
107
|
+
|
|
108
|
+
### 変更
|
|
109
|
+
|
|
110
|
+
- **`emits X` は、コマンドが成功したときにちょうど 1 つの `X`** を意味します(以前は「発生させうる」)。エラーのときは
|
|
111
|
+
何も発生させません。
|
|
112
|
+
- **コマンドの結果は結果(遷移先)ごとのキーを持つ形**になりました: タプル `[aggregate, events[]]` の代わりに
|
|
113
|
+
`{ Confirmed: { aggregate, events: { OrderConfirmed } } }`。イベントは名前をキーとし、順序を持ちません。イベントの
|
|
114
|
+
ないコマンドは `NoEvents` です。
|
|
115
|
+
- コマンドは純粋関数です: ID と時刻は引数として受け取ります(ファクトリは自分の ID を受け取ります)。
|
|
116
|
+
- `ok` は契約からだけ型を推論するので、リテラル中の余分なイベントが報告されます。
|
|
117
|
+
- `changes` のないコマンドは、共通フィールドを変更しません。
|
|
118
|
+
- 生成されるモジュールが値(`<Aggregate>Shape`)をエクスポートします: `import type` ではなく値として import します。
|
|
119
|
+
- `dt guide` はクイックリファレンスとトピック一覧を表示します。`dt guide <topic>` で 1 節、`dt guide <rule>` で 1 ルール、
|
|
120
|
+
`dt guide --all` でガイド全体。
|
|
121
|
+
- `[0..1]` は `?` と、`[1..1]` は多重度なしと同じ意味になりました。
|
|
122
|
+
- Live View は各イベントの多重度と `when`、`requires` と `changes`、問題ペインのヒントを表示します。
|
|
123
|
+
|
|
124
|
+
### 削除
|
|
125
|
+
|
|
126
|
+
- `byState` と `<Command><Aggregate>ByState` 型(0.3.0): すべてのコマンドを `decide` で実装します。
|
|
127
|
+
|
|
128
|
+
### アップグレード手順
|
|
129
|
+
|
|
130
|
+
まずモデルを変え、次に生成し、最後にコードを直します。規則の詳細は `dt guide events`、`dt guide changes`、
|
|
131
|
+
`dt guide decide` にあります。
|
|
132
|
+
|
|
133
|
+
1. **イベント。** `emits X` は、成功するたびにちょうど 1 つの `X` になりました。`emits` の各項目について、そのイベントが
|
|
134
|
+
いつ発生するかを決めて、そのとおりに書きます:
|
|
135
|
+
|
|
136
|
+
```dt
|
|
137
|
+
// 変更前(0.3.0): 「発生させうる」
|
|
138
|
+
command changeNote(note: String?)
|
|
139
|
+
Draft -> Draft, Confirmed -> Confirmed
|
|
140
|
+
emits NoteChanged
|
|
141
|
+
command cancel(reason: CancelReason)
|
|
142
|
+
Draft | Confirmed -> Cancelled
|
|
143
|
+
emits OrderCancelled, RefundRequested
|
|
144
|
+
// 変更後(0.4.0)
|
|
145
|
+
command changeNote(note: String?)
|
|
146
|
+
Draft -> Draft, Confirmed -> Confirmed
|
|
147
|
+
changes note
|
|
148
|
+
emits NoteChanged? // 高々 1 つ。いくつでもなら X[0..*]
|
|
149
|
+
command cancel(reason: CancelReason)
|
|
150
|
+
Draft | Confirmed -> Cancelled
|
|
151
|
+
emits OrderCancelled,
|
|
152
|
+
RefundRequested when Confirmed -> // Confirmed からのときだけ
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
2. **ファクトリは ID を、コマンドは時刻を受け取ります。** 各 `create command` に集約の ID 型の引数を加え(加えるまで
|
|
156
|
+
M020 が警告します)、実装が時計を読んでいたところには `Timestamp` の引数を加えます:
|
|
157
|
+
|
|
158
|
+
```dt
|
|
159
|
+
create command place(customer: CustomerId) -> Draft // 変更前
|
|
160
|
+
create command place(id: OrderId, customer: CustomerId) -> Draft // 変更後
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
ID は呼び出し側が作って(`make<Name>(crypto.randomUUID())`)渡します。
|
|
164
|
+
3. **`changes`。** 遷移元と遷移先の状態に共通するフィールド(状態のない集約ではすべてのフィールド)を変更するコマンドに、
|
|
165
|
+
`changes f1, f2` を加えます。書かないと、生成される決定の型がそのフィールドの設定を許しません。
|
|
166
|
+
4. **必要なら `requires`。** 何かを変える前にエラーを返す検査は `requires name { expr } else Error` にできます。生成される
|
|
167
|
+
`check<Command><Aggregate>Requires` と契約テストがそれを検査します。
|
|
168
|
+
5. **予約された名前(M011)。** `decide`、`Decide`、`Shape`、`NoChanges`、`outcome`、`eventList`、`NoEvents`、
|
|
169
|
+
`Outcome`、`EventOf`、`sameOptional`、`sameList`、`distinct` はランタイムの名前に、`<Command><Aggregate>Decision`、
|
|
170
|
+
`<Aggregate>Shape` は生成される名前になりました: 衝突する要素の名前を変えます。`dt check` が 0 で終わるまで直します。
|
|
171
|
+
6. **生成し直し、すべてのコマンドを `decide` で書き直します。** 結果の `set`(`changes` のフィールドと遷移先の状態で
|
|
172
|
+
新しく持つフィールド。ファクトリはすべてのフィールドを設定し、省略可能なものは `undefined`)と `events` を、遷移先の
|
|
173
|
+
状態をキーにして返します(状態のない集約では集約名がキー)。遷移元が一つでも、遷移元の状態ごとにハンドラを書きます。
|
|
174
|
+
ファクトリは一つの関数です:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
// 変更前(0.3.0)
|
|
178
|
+
import { byState, ok, type Sales } from '../generated/domain/index.js';
|
|
179
|
+
export const orderCommands: Sales.OrderCommands = {
|
|
180
|
+
place: (customer) => {
|
|
181
|
+
const order: Sales.DraftOrder = { state: 'Draft', id: crypto.randomUUID() as Sales.OrderId, items: [], customer };
|
|
182
|
+
return ok([order, [{ type: 'OrderPlaced', orderId: order.id }]] as const);
|
|
183
|
+
},
|
|
184
|
+
confirm: (order, at) =>
|
|
185
|
+
ok([{ ...order, state: 'Confirmed', confirmedAt: at }, [{ type: 'OrderConfirmed', orderId: order.id, confirmedAt: at }]] as const),
|
|
186
|
+
changeNote: byState<Sales.ChangeNoteOrderByState>({
|
|
187
|
+
Draft: (order, note) => ok([{ ...order, note }, []] as const),
|
|
188
|
+
Confirmed: (order, note) => ok([{ ...order, note }, []] as const),
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// 変更後(0.4.0)
|
|
193
|
+
import { Sales, decide, ok } from '../generated/domain/index.js';
|
|
194
|
+
export const orderCommands: Sales.OrderCommands = {
|
|
195
|
+
place: decide<Sales.PlaceOrderDecision>(Sales.OrderShape, (id, customer) =>
|
|
196
|
+
ok({ Draft: { set: { id, items: [], customer, note: undefined }, events: { OrderPlaced: { type: 'OrderPlaced', orderId: id } } } }),
|
|
197
|
+
),
|
|
198
|
+
confirm: decide<Sales.ConfirmOrderDecision>(Sales.OrderShape, {
|
|
199
|
+
Draft: (order, at) =>
|
|
200
|
+
ok({ Confirmed: { set: { confirmedAt: at }, events: { OrderConfirmed: { type: 'OrderConfirmed', orderId: order.id, confirmedAt: at } } } }),
|
|
201
|
+
}),
|
|
202
|
+
changeNote: decide<Sales.ChangeNoteOrderDecision>(Sales.OrderShape, {
|
|
203
|
+
Draft: (order, note) => ok({ Draft: { set: { note }, events: {} } }), // `emits NoteChanged?` なら、備考が変わったときに渡す
|
|
204
|
+
Confirmed: (order, note) => ok({ Confirmed: { set: { note }, events: {} } }),
|
|
205
|
+
}),
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
7. **呼び出し側**はキー付きの結果を読みます: `result.value.Confirmed.aggregate` / `.events.OrderConfirmed`。どのコマンドも
|
|
210
|
+
扱うコードでは `outcome(result.value)` → `{ to, aggregate, events }` と `eventList(events)` を使います。
|
|
211
|
+
8. 型検査します(`tsc --noEmit`)。契約と実装が食い違うとき — いつも発生させられるとは限らないイベント、変更が必要な
|
|
212
|
+
フィールド — は、実装ではなく DSL を変えます(`X?`、`changes`)。
|
|
213
|
+
9. 必要なら契約テストを有効にし(`generate.ts.tests`、`dt guide tests`)、一度 `dt fmt` を実行します。
|
|
214
|
+
|
|
215
|
+
## [0.3.0] - 2026-10-19
|
|
216
|
+
|
|
217
|
+
### 追加
|
|
218
|
+
|
|
219
|
+
- 遷移元の状態ごとのハンドラ: 遷移先が遷移元の状態によって決まるコマンドには `<Command><Aggregate>ByState` も生成され、
|
|
220
|
+
ランタイムの `byState({...})` で実装します(ADR 0015)。
|
|
221
|
+
- 状態遷移図は遷移ごとに辺を描き、インスペクタは遷移ごとに行を表示します。
|
|
222
|
+
|
|
223
|
+
### 変更
|
|
224
|
+
|
|
225
|
+
- **コマンドは `from … to …` の代わりに遷移を並べます**(ADR 0014): `Draft -> Confirmed`、
|
|
226
|
+
`Draft | Confirmed -> Cancelled`、`Draft -> Draft, Confirmed -> Confirmed`。ファクトリは遷移元のない遷移を一つ
|
|
227
|
+
持ちます(`-> Draft`)。一つの状態は、コマンドごとに一つの遷移の遷移元になります(M006)。`from` と `to` は
|
|
228
|
+
キーワードではなくなりました。
|
|
229
|
+
- 遷移先が遷移元の状態によって決まるコマンドの生成される契約は、入力の状態についてジェネリックになり、`Draft` からは
|
|
230
|
+
`Draft`、`Confirmed` からは `Confirmed` が返ります。
|
|
231
|
+
|
|
232
|
+
### 修正
|
|
233
|
+
|
|
234
|
+
- `npm publish` が警告しないよう、パッケージの `bin` のパスの書き方を直しました。
|
|
235
|
+
|
|
236
|
+
### アップグレード手順
|
|
237
|
+
|
|
238
|
+
1. 各コマンドの `from … to …` を遷移に書き換えます:
|
|
239
|
+
|
|
240
|
+
```dt
|
|
241
|
+
// 変更前(0.2.0)
|
|
242
|
+
create command place(customer: CustomerId) to Draft
|
|
243
|
+
command confirm(at: Timestamp) from Draft to Confirmed emits OrderConfirmed
|
|
244
|
+
command changeNote(note: String?) from Draft | Confirmed to Draft | Confirmed
|
|
245
|
+
// 変更後(0.3.0)
|
|
246
|
+
create command place(customer: CustomerId) -> Draft
|
|
247
|
+
command confirm(at: Timestamp) Draft -> Confirmed emits OrderConfirmed
|
|
248
|
+
command changeNote(note: String?) Draft -> Draft, Confirmed -> Confirmed // どの遷移元がどこへ行くかを書く
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
どの遷移元からどの遷移先へも行けるなら、`from A | B to C | D` は `A | B -> C | D` になります。できるだけ正確な
|
|
252
|
+
遷移を書いてください。
|
|
253
|
+
2. `dt check`、続いて `dt generate ts` を実行します。遷移先が遷移元の状態によって決まるコマンドは契約がジェネリックに
|
|
254
|
+
なります: 型アサーションの代わりに
|
|
255
|
+
`byState<Ctx.<Command><Aggregate>ByState>({ Draft: (…) => …, Confirmed: (…) => … })` で実装します。
|
|
256
|
+
|
|
257
|
+
## [0.2.0] - 2026-10-18
|
|
258
|
+
|
|
259
|
+
### 追加
|
|
260
|
+
|
|
261
|
+
- **項目セット**(`dt guide field-sets`、ADR 0013): `fields Name { ... }` で普通のフィールドの集まりを宣言し、集約・
|
|
262
|
+
エンティティ・イベントが `with A, B` でそれを持ちます(M016)。共有コンテキストにも置けます。要素が継承する
|
|
263
|
+
インターフェースが生成されます。
|
|
264
|
+
- コンテキストごとに生成される union: `DomainEvent`(すべてのイベント)、`Aggregate`(すべての集約)、
|
|
265
|
+
`<Aggregate>Event`(集約のコマンドが発生させるイベント)。
|
|
266
|
+
- M017(警告): 集約のコマンドが発生させるイベントに、その集約の ID 型のフィールドがない。
|
|
267
|
+
- ガイドで、ドメインのフィールドと技術的なフィールドの違いと、技術的なメタデータをエンベロープで付ける方法を説明しました。
|
|
268
|
+
- Live View: カタログのフィルタ(テキスト、種類、コンテキスト)。エクスプローラ、カタログ、インスペクタ、構造図での
|
|
269
|
+
項目セットの表示。
|
|
270
|
+
|
|
271
|
+
### 変更
|
|
272
|
+
|
|
273
|
+
- Live View: カタログのカードは、バッジを見出しの上に、ラベルを名前の上に置きます。カタログのセクションへのリンクは
|
|
274
|
+
なくなりました(フィルタでセクションを探せます)。
|
|
275
|
+
|
|
276
|
+
### アップグレード手順
|
|
277
|
+
|
|
278
|
+
1. M011: `DomainEvent`、`Aggregate`、`<Aggregate>Event` は生成される名前になりました。これらと名前が衝突する
|
|
279
|
+
コンテキストの要素の名前を変え、`dt check` を実行します。
|
|
280
|
+
2. `fields` と `with` はキーワードになりましたが、フィールド名や引数名としては引き続き使えます。
|
|
281
|
+
3. 新しい M017 の警告には、集約の ID をそのイベントに加えて対応します(`orderId: OrderId`)。
|
|
282
|
+
|
|
283
|
+
## [0.1.0] - 2026-10-18
|
|
284
|
+
|
|
285
|
+
最初に公開したバージョンです。
|
|
286
|
+
|
|
287
|
+
### 追加
|
|
288
|
+
|
|
289
|
+
- DomainTrail DSL: 境界づけられたコンテキスト、状態を持つ集約、エンティティ、値オブジェクト、ID、ドメインプリミティブ、
|
|
290
|
+
列挙型、union、コマンド(`from … to …`)、イベント(`persistent`)、エラー、共有コンテキスト、ラベルと説明、
|
|
291
|
+
不変条件の式。ルール M001〜M015 と L001〜L003。
|
|
292
|
+
- `dt` CLI(`domaintrail` としてもインストールされます。Node.js 22.12 以降): `dt check`、`dt generate ts`
|
|
293
|
+
(TypeScript の型とコマンドの契約。`generate.ts.contexts` でコンテキストごとの出力先)、`dt view`、`dt guide`。
|
|
294
|
+
- `domaintrail.jsonc`(`sources`、`generate.ts`、`view`)と、その JSON Schema `schema/domaintrail.schema.json`。
|
|
295
|
+
- Live View(`dt view`): コンテキストマップ、構造図(3 段階)、カタログ、状態遷移図、ソースを表示するインスペクタ、問題と
|
|
296
|
+
変更の一覧。保存のたびに更新されます。日本語と英語、ライトとダーク。
|
|
297
|
+
|
|
298
|
+
[0.6.0]: https://github.com/hisamekms/domaintrail/compare/v0.5.0...v0.6.0
|
|
299
|
+
[0.5.0]: https://github.com/hisamekms/domaintrail/compare/v0.4.0...v0.5.0
|
|
300
|
+
[0.4.0]: https://github.com/hisamekms/domaintrail/compare/v0.3.0...v0.4.0
|
|
301
|
+
[0.3.0]: https://github.com/hisamekms/domaintrail/compare/v0.2.0...v0.3.0
|
|
302
|
+
[0.2.0]: https://github.com/hisamekms/domaintrail/compare/b9f56885cde82f404bbf6b558f43b8ecb6254dfe...v0.2.0
|
|
303
|
+
[0.1.0]: https://github.com/hisamekms/domaintrail/tree/b9f56885cde82f404bbf6b558f43b8ecb6254dfe
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
[日本語](CHANGELOG.ja.md)
|
|
4
|
+
|
|
5
|
+
What changed in each version of domaintrail. The format follows [Keep a Changelog](https://keepachangelog.com/), and
|
|
6
|
+
the versions follow [Semantic Versioning](https://semver.org/) (before 1.0.0, a minor version may break models and
|
|
7
|
+
code).
|
|
8
|
+
|
|
9
|
+
**After upgrading domaintrail**, read the **Upgrading** section of every version between the one you had and the new
|
|
10
|
+
one, oldest first, and follow its steps. This file is in the package: `node_modules/domaintrail/CHANGELOG.md`.
|
|
11
|
+
|
|
12
|
+
## [0.6.0] - 2026-10-28
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Comparing the Live View with a git revision** (`docs/live-view.md`): the 比較対象 menu in the header, or the heading
|
|
17
|
+
of the changes pane, picks what additions, changes and removals are shown against — the previous save (the default)
|
|
18
|
+
or a git revision: a branch, a tag, one of the latest commits or any revision typed in. `dt view --base <ref>` starts
|
|
19
|
+
with one. The diagrams mark the fields of their nodes, and the inspector marks the rows of its 構造, 状態遷移 and 振る舞い
|
|
20
|
+
tabs (added, changed, removed struck through, with the former value of a changed one).
|
|
21
|
+
- **Getting started** in English and Japanese (`docs/getting-started.md`, `docs/getting-started.ja.md`), with the
|
|
22
|
+
README reorganized around it.
|
|
23
|
+
- The changelogs are in the package (`node_modules/domaintrail/CHANGELOG.md`, `CHANGELOG.ja.md`), and `dt guide` tells
|
|
24
|
+
agents to follow their Upgrading steps after an upgrade.
|
|
25
|
+
|
|
26
|
+
## [0.5.0] - 2026-10-24
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Policies** (`dt guide reactions`, ADR 0022): `policy P when Event -> Aggregate.command` — when the event happens,
|
|
31
|
+
the command of the policy's own context is eventually run. M023 checks the event, the aggregate and the command, and
|
|
32
|
+
warns about the same reaction twice. Each policy generates the type of its handler, from the event to the command's
|
|
33
|
+
input (`<Command><Aggregate>Input`). With `generate.ts.policies: "required"` (default `"optional"`, also per context
|
|
34
|
+
in `generate.ts.contexts`), `<Context>PolicyHandlers` is generated and the contract tests take it and check that every
|
|
35
|
+
event resolves to an input the command accepts. The context map counts a policy as an event dependency.
|
|
36
|
+
- **Verified types** (`dt guide verified`, ADR 0023): `verified X of T for C? errors E` — the evidence of a check made
|
|
37
|
+
outside the aggregate (an email address nobody else uses). Only its async factory, `Make<Name>`, written by you, makes
|
|
38
|
+
it; commands take it as a parameter. M024 keeps verified types to command parameters.
|
|
39
|
+
- **Payload names** (ADR 0021): M022 warns when an event or error field likely takes its value from a differently
|
|
40
|
+
named source (a parameter, one of its fields, or a field of the aggregate before / after the command).
|
|
41
|
+
- **Zed extension** (`editors/zed`) and a **tree-sitter grammar** (`tree-sitter-domaintrail`): highlighting, outline and
|
|
42
|
+
`dt lsp` in Zed; the grammar for other tree-sitter editors (`dt guide editors`).
|
|
43
|
+
- **Linting against casts** (`dt guide lint`): how to make every domain type without `as`, and how to enable
|
|
44
|
+
`no-unsafe-type-assertion` with oxlint or typescript-eslint. `dt generate ts` prints a hint (`hints` in
|
|
45
|
+
`--format json`) when no oxlint or ESLint config mentions the rule; `"lintHint": false` turns it off. The JSDoc of
|
|
46
|
+
IDs, domain primitives and verified types names the way to make them.
|
|
47
|
+
- `parseDecimal(text)` in the generated runtime: the one place that makes a `Decimal`.
|
|
48
|
+
- `dt guide policies`: how to write rules that depend on a changeable policy.
|
|
49
|
+
- `examples/shop` is a complete project: every aggregate implemented, an application layer (use cases, repositories, an
|
|
50
|
+
event store, policies, a verified type's factory), tests and a demo, described in its README.
|
|
51
|
+
- Language server: commands can be renamed.
|
|
52
|
+
|
|
53
|
+
### Changed
|
|
54
|
+
|
|
55
|
+
- Every command that collects the workspace's files (`check`, `generate`, `view`, `fmt`, `show`, `lsp`) skips what the
|
|
56
|
+
`.gitignore` files (of the root, its subdirectories and its parents up to the repository's top) and
|
|
57
|
+
`.git/info/exclude` ignore. `"respectGitignore": false` turns it off; files named on the command line are never
|
|
58
|
+
skipped.
|
|
59
|
+
- When the language server finds no config file, the first `.dt` file opened below a config makes that config the
|
|
60
|
+
workspace.
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- A domain primitive over `Int` or `Decimal` can be compared with the numbers `count()` and `length()` compute.
|
|
65
|
+
|
|
66
|
+
### Upgrading
|
|
67
|
+
|
|
68
|
+
1. If `.dt` files of your model are in a directory that `.gitignore` ignores, they are no longer part of the
|
|
69
|
+
workspace. Move them, or set `"respectGitignore": false` in `domaintrail.jsonc`. Run `dt check` and compare the
|
|
70
|
+
file count with before.
|
|
71
|
+
2. M011: `parseDecimal` is now a runtime name. Rename an element of your model with that name.
|
|
72
|
+
3. Run `dt generate ts`. If it prints the lint hint, follow `dt guide lint` (or set `"lintHint": false`), and replace
|
|
73
|
+
casts to domain types in your code with `make<Name>` / `parseDecimal`.
|
|
74
|
+
4. New warnings may appear: M022 (rename the event or error field after its source, or the source after the field).
|
|
75
|
+
Warnings do not fail `dt check`.
|
|
76
|
+
|
|
77
|
+
## [0.4.0] - 2026-10-24
|
|
78
|
+
|
|
79
|
+
### Added
|
|
80
|
+
|
|
81
|
+
- **`requires`** on commands (`dt guide requires`, ADR 0017): `requires name { expr } else Error` — the command is
|
|
82
|
+
accepted only if the expression holds, otherwise it returns the error (M019).
|
|
83
|
+
- **`changes`** on commands (`dt guide changes`, ADR 0019): the fields a command may change (M021).
|
|
84
|
+
- **`emits` with multiplicities and `when`** (`dt guide events`, ADR 0018): `X?`, `X[0..*]`, `X[1..*]`, `X[n..m]`, and
|
|
85
|
+
`X when Draft ->` / `X when -> Completed` for events of some outcomes only.
|
|
86
|
+
- **`unique` and `contains`** in expressions, and invariants without an expression, stated in words only (M018; ADR
|
|
87
|
+
0016).
|
|
88
|
+
- **Decisions and `decide`** (`dt guide decide`): each command is implemented as a `<Command><Aggregate>Decision` — per
|
|
89
|
+
source state, the outcome's `set` and `events` — and `decide(<Aggregate>Shape, decision)` from the runtime makes the
|
|
90
|
+
aggregate. The compiler names a missing event, an extra event, and a field the command may not set.
|
|
91
|
+
- **Generated checks and constructors** (ADR 0020): `check<Name>` / `check<Command><Aggregate>Requires` from the
|
|
92
|
+
invariant and requirement expressions, and `make<Name>` for every ID and domain primitive.
|
|
93
|
+
- **Generated contract tests** (`dt guide tests`): with `generate.ts.tests` (`runner`: `bun`, `vitest`, `jest` or
|
|
94
|
+
`node`; `out`), `dt generate ts` writes fast-check suites per context that check the constructors, the requirements,
|
|
95
|
+
the invariants after each command, the events and purity. They need `fast-check` in your project.
|
|
96
|
+
- **`dt fmt`**: one canonical layout for `.dt` files, keeping every comment (`--check` for CI); also LSP formatting.
|
|
97
|
+
- **`dt show <name>`**: one element, state, command or context resolved, with who uses it (`--format json`).
|
|
98
|
+
- **`dt lsp`**: a language server with the diagnostics of `dt check`, definition, references, hover, outline,
|
|
99
|
+
completion and rename.
|
|
100
|
+
- **Hints** on diagnostics (did you mean …, and what to change), and `--format json` for `check` and `generate ts`
|
|
101
|
+
(schema in `schema/diagnostics.schema.json`).
|
|
102
|
+
- `@see <file>:<line>` on every generated declaration, pointing back to the DSL.
|
|
103
|
+
- Runtime helpers `outcome(value)` (`{ to, aggregate, events }`) and `eventList(events)` for code that handles any
|
|
104
|
+
command.
|
|
105
|
+
- M020 (warning): a `create command` without a parameter of the aggregate's ID type.
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- **`emits X` means exactly one `X`** when the command succeeds (it meant "may emit"), and nothing on an error.
|
|
110
|
+
- **Command results are keyed by outcome**: `{ Confirmed: { aggregate, events: { OrderConfirmed } } }` instead of the
|
|
111
|
+
tuple `[aggregate, events[]]`; events are keyed by name and have no order. A command without events has `NoEvents`.
|
|
112
|
+
- Commands are pure: IDs and times come in as parameters (factories take their ID).
|
|
113
|
+
- `ok` infers its type from the contract only, so an extra event in the literal is reported.
|
|
114
|
+
- Without `changes`, a command changes no common field.
|
|
115
|
+
- Generated modules export values (`<Aggregate>Shape`): import them as values, not with `import type`.
|
|
116
|
+
- `dt guide` prints a quick reference and the list of topics; `dt guide <topic>` one section, `dt guide <rule>` one
|
|
117
|
+
rule, `dt guide --all` the whole guide.
|
|
118
|
+
- `[0..1]` is the same as `?` and `[1..1]` the same as no multiplicity.
|
|
119
|
+
- The Live View shows the multiplicity and `when` of each event, `requires` and `changes`, and hints in the problems
|
|
120
|
+
pane.
|
|
121
|
+
|
|
122
|
+
### Removed
|
|
123
|
+
|
|
124
|
+
- `byState` and the `<Command><Aggregate>ByState` types (0.3.0): every command is implemented with `decide`.
|
|
125
|
+
|
|
126
|
+
### Upgrading
|
|
127
|
+
|
|
128
|
+
Change the model first, then generate, then the code. The full rules are in `dt guide events`, `dt guide changes` and
|
|
129
|
+
`dt guide decide`.
|
|
130
|
+
|
|
131
|
+
1. **Events.** `emits X` is now exactly one `X` on every success. For each `emits` entry, decide when the event
|
|
132
|
+
happens and write it so:
|
|
133
|
+
|
|
134
|
+
```dt
|
|
135
|
+
// before (0.3.0): "may emit"
|
|
136
|
+
command changeNote(note: String?)
|
|
137
|
+
Draft -> Draft, Confirmed -> Confirmed
|
|
138
|
+
emits NoteChanged
|
|
139
|
+
command cancel(reason: CancelReason)
|
|
140
|
+
Draft | Confirmed -> Cancelled
|
|
141
|
+
emits OrderCancelled, RefundRequested
|
|
142
|
+
// after (0.4.0)
|
|
143
|
+
command changeNote(note: String?)
|
|
144
|
+
Draft -> Draft, Confirmed -> Confirmed
|
|
145
|
+
changes note
|
|
146
|
+
emits NoteChanged? // at most one; X[0..*] for any number
|
|
147
|
+
command cancel(reason: CancelReason)
|
|
148
|
+
Draft | Confirmed -> Cancelled
|
|
149
|
+
emits OrderCancelled,
|
|
150
|
+
RefundRequested when Confirmed -> // only from Confirmed
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
2. **Factories take their ID, commands take the time.** Add a parameter of the aggregate's ID type to each
|
|
154
|
+
`create command` (M020 warns until you do), and a `Timestamp` parameter where the implementation read the clock:
|
|
155
|
+
|
|
156
|
+
```dt
|
|
157
|
+
create command place(customer: CustomerId) -> Draft // before
|
|
158
|
+
create command place(id: OrderId, customer: CustomerId) -> Draft // after
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Callers make the ID (`make<Name>(crypto.randomUUID())`) and pass it in.
|
|
162
|
+
3. **`changes`.** Add `changes f1, f2` to every command that changes a field common to its source and target states
|
|
163
|
+
(or any field of an aggregate without states). Without it, the generated decision does not let the command set the
|
|
164
|
+
field.
|
|
165
|
+
4. **Optionally `requires`.** A check that returns an error before anything changes can become
|
|
166
|
+
`requires name { expr } else Error`; the generated `check<Command><Aggregate>Requires` and the contract tests then
|
|
167
|
+
check it.
|
|
168
|
+
5. **Reserved names (M011).** `decide`, `Decide`, `Shape`, `NoChanges`, `outcome`, `eventList`, `NoEvents`, `Outcome`,
|
|
169
|
+
`EventOf`, `sameOptional`, `sameList` and `distinct` are runtime names, and `<Command><Aggregate>Decision`,
|
|
170
|
+
`<Aggregate>Shape` are generated: rename elements whose names clash. Run `dt check` until it exits 0.
|
|
171
|
+
6. **Regenerate and rewrite every command with `decide`.** Return the outcome's `set` (the fields in `changes` and the
|
|
172
|
+
target state's new fields; a factory sets every field, optional ones as `undefined`) and its `events`, keyed by the
|
|
173
|
+
target state (by the aggregate's name without states). One handler per source state, also with one source; a
|
|
174
|
+
factory is a single function:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
// before (0.3.0)
|
|
178
|
+
import { byState, ok, type Sales } from '../generated/domain/index.js';
|
|
179
|
+
export const orderCommands: Sales.OrderCommands = {
|
|
180
|
+
place: (customer) => {
|
|
181
|
+
const order: Sales.DraftOrder = { state: 'Draft', id: crypto.randomUUID() as Sales.OrderId, items: [], customer };
|
|
182
|
+
return ok([order, [{ type: 'OrderPlaced', orderId: order.id }]] as const);
|
|
183
|
+
},
|
|
184
|
+
confirm: (order, at) =>
|
|
185
|
+
ok([{ ...order, state: 'Confirmed', confirmedAt: at }, [{ type: 'OrderConfirmed', orderId: order.id, confirmedAt: at }]] as const),
|
|
186
|
+
changeNote: byState<Sales.ChangeNoteOrderByState>({
|
|
187
|
+
Draft: (order, note) => ok([{ ...order, note }, []] as const),
|
|
188
|
+
Confirmed: (order, note) => ok([{ ...order, note }, []] as const),
|
|
189
|
+
}),
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// after (0.4.0)
|
|
193
|
+
import { Sales, decide, ok } from '../generated/domain/index.js';
|
|
194
|
+
export const orderCommands: Sales.OrderCommands = {
|
|
195
|
+
place: decide<Sales.PlaceOrderDecision>(Sales.OrderShape, (id, customer) =>
|
|
196
|
+
ok({ Draft: { set: { id, items: [], customer, note: undefined }, events: { OrderPlaced: { type: 'OrderPlaced', orderId: id } } } }),
|
|
197
|
+
),
|
|
198
|
+
confirm: decide<Sales.ConfirmOrderDecision>(Sales.OrderShape, {
|
|
199
|
+
Draft: (order, at) =>
|
|
200
|
+
ok({ Confirmed: { set: { confirmedAt: at }, events: { OrderConfirmed: { type: 'OrderConfirmed', orderId: order.id, confirmedAt: at } } } }),
|
|
201
|
+
}),
|
|
202
|
+
changeNote: decide<Sales.ChangeNoteOrderDecision>(Sales.OrderShape, {
|
|
203
|
+
Draft: (order, note) => ok({ Draft: { set: { note }, events: {} } }), // with `emits NoteChanged?`, give it when the note changes
|
|
204
|
+
Confirmed: (order, note) => ok({ Confirmed: { set: { note }, events: {} } }),
|
|
205
|
+
}),
|
|
206
|
+
};
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
7. **Callers** read the keyed result: `result.value.Confirmed.aggregate` / `.events.OrderConfirmed`, or, in code that
|
|
210
|
+
handles any command, `outcome(result.value)` → `{ to, aggregate, events }` and `eventList(events)`.
|
|
211
|
+
8. Type-check (`tsc --noEmit`). When the contract and the implementation disagree — an event that cannot always be
|
|
212
|
+
emitted, a field that must change — change the DSL (`X?`, `changes`), not the implementation.
|
|
213
|
+
9. Optionally enable the contract tests (`generate.ts.tests`, `dt guide tests`) and run `dt fmt` once.
|
|
214
|
+
|
|
215
|
+
## [0.3.0] - 2026-10-19
|
|
216
|
+
|
|
217
|
+
### Added
|
|
218
|
+
|
|
219
|
+
- Handlers per source state: a command whose targets depend on its source state also gets
|
|
220
|
+
`<Command><Aggregate>ByState`, implemented with `byState({...})` from the runtime (ADR 0015).
|
|
221
|
+
- The State View draws one edge per transition, and the inspector shows a row per transition.
|
|
222
|
+
|
|
223
|
+
### Changed
|
|
224
|
+
|
|
225
|
+
- **Commands list their transitions** instead of `from … to …` (ADR 0014): `Draft -> Confirmed`,
|
|
226
|
+
`Draft | Confirmed -> Cancelled`, `Draft -> Draft, Confirmed -> Confirmed`; a factory has one transition without
|
|
227
|
+
sources, `-> Draft`. A state is the source of one transition per command (M006). `from` and `to` are no longer
|
|
228
|
+
keywords.
|
|
229
|
+
- The generated contract of a command whose targets depend on its source state is generic over the input state, so a
|
|
230
|
+
`Draft` gives a `Draft` and a `Confirmed` a `Confirmed`.
|
|
231
|
+
|
|
232
|
+
### Fixed
|
|
233
|
+
|
|
234
|
+
- The `bin` paths of the package are written so that `npm publish` does not warn about them.
|
|
235
|
+
|
|
236
|
+
### Upgrading
|
|
237
|
+
|
|
238
|
+
1. Rewrite each command's `from … to …` as transitions:
|
|
239
|
+
|
|
240
|
+
```dt
|
|
241
|
+
// before (0.2.0)
|
|
242
|
+
create command place(customer: CustomerId) to Draft
|
|
243
|
+
command confirm(at: Timestamp) from Draft to Confirmed emits OrderConfirmed
|
|
244
|
+
command changeNote(note: String?) from Draft | Confirmed to Draft | Confirmed
|
|
245
|
+
// after (0.3.0)
|
|
246
|
+
create command place(customer: CustomerId) -> Draft
|
|
247
|
+
command confirm(at: Timestamp) Draft -> Confirmed emits OrderConfirmed
|
|
248
|
+
command changeNote(note: String?) Draft -> Draft, Confirmed -> Confirmed // say which source goes where
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`from A | B to C | D` becomes `A | B -> C | D` when every source may end in every target; prefer the precise
|
|
252
|
+
transitions.
|
|
253
|
+
2. Run `dt check`, then `dt generate ts`. A command whose targets depend on its source state has a generic contract:
|
|
254
|
+
implement it with `byState<Ctx.<Command><Aggregate>ByState>({ Draft: (…) => …, Confirmed: (…) => … })` instead of
|
|
255
|
+
a type assertion.
|
|
256
|
+
|
|
257
|
+
## [0.2.0] - 2026-10-18
|
|
258
|
+
|
|
259
|
+
### Added
|
|
260
|
+
|
|
261
|
+
- **Field sets** (`dt guide field-sets`, ADR 0013): `fields Name { ... }` declares plain fields that aggregates,
|
|
262
|
+
entities and events take on with `with A, B` (M016). Shared contexts may hold them. They generate an interface that
|
|
263
|
+
the elements extend.
|
|
264
|
+
- Generated unions per context: `DomainEvent` (every event), `Aggregate` (every aggregate) and `<Aggregate>Event` (the
|
|
265
|
+
events an aggregate's commands emit).
|
|
266
|
+
- M017 (warning): an event emitted by an aggregate's command has no field of that aggregate's ID type.
|
|
267
|
+
- The guide explains domain vs technical fields, and attaching technical metadata with envelopes.
|
|
268
|
+
- Live View: a filter bar in the catalog (text, kinds, contexts); field sets in the explorer, catalog, inspector and
|
|
269
|
+
structure diagram.
|
|
270
|
+
|
|
271
|
+
### Changed
|
|
272
|
+
|
|
273
|
+
- Live View: catalog cards put the badges above the heading and the label over the name; the catalog's section links
|
|
274
|
+
are gone (the filter finds a section).
|
|
275
|
+
|
|
276
|
+
### Upgrading
|
|
277
|
+
|
|
278
|
+
1. M011: `DomainEvent`, `Aggregate` and `<Aggregate>Event` are generated names now. Rename an element of a context
|
|
279
|
+
whose name clashes with them, then run `dt check`.
|
|
280
|
+
2. `fields` and `with` are keywords; they are still allowed as field and parameter names.
|
|
281
|
+
3. Address the new M017 warnings by adding the aggregate's ID to its events (`orderId: OrderId`).
|
|
282
|
+
|
|
283
|
+
## [0.1.0] - 2026-10-18
|
|
284
|
+
|
|
285
|
+
The first published version.
|
|
286
|
+
|
|
287
|
+
### Added
|
|
288
|
+
|
|
289
|
+
- The DomainTrail DSL: bounded contexts, aggregates with states, entities, value objects, IDs, domain primitives,
|
|
290
|
+
enums, unions, commands (`from … to …`), events (`persistent`), errors, shared contexts, labels and descriptions,
|
|
291
|
+
and invariant expressions; rules M001–M015 and L001–L003.
|
|
292
|
+
- The `dt` CLI (also installed as `domaintrail`), on Node.js 22.12 or later: `dt check`, `dt generate ts` (TypeScript
|
|
293
|
+
types and command contracts, one output directory per context with `generate.ts.contexts`), `dt view` and
|
|
294
|
+
`dt guide`.
|
|
295
|
+
- `domaintrail.jsonc` (`sources`, `generate.ts`, `view`) with its JSON Schema in `schema/domaintrail.schema.json`.
|
|
296
|
+
- The Live View (`dt view`): the context map, the structure diagram (three levels), the catalog, the state diagram,
|
|
297
|
+
the inspector with the source, problems and changes, updated on every save; in Japanese or English, light or dark.
|
|
298
|
+
|
|
299
|
+
[0.6.0]: https://github.com/hisamekms/domaintrail/compare/v0.5.0...v0.6.0
|
|
300
|
+
[0.5.0]: https://github.com/hisamekms/domaintrail/compare/v0.4.0...v0.5.0
|
|
301
|
+
[0.4.0]: https://github.com/hisamekms/domaintrail/compare/v0.3.0...v0.4.0
|
|
302
|
+
[0.3.0]: https://github.com/hisamekms/domaintrail/compare/v0.2.0...v0.3.0
|
|
303
|
+
[0.2.0]: https://github.com/hisamekms/domaintrail/compare/b9f56885cde82f404bbf6b558f43b8ecb6254dfe...v0.2.0
|
|
304
|
+
[0.1.0]: https://github.com/hisamekms/domaintrail/tree/b9f56885cde82f404bbf6b558f43b8ecb6254dfe
|