aact 2.1.5 → 3.0.0-beta.3

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/dist/index.d.ts CHANGED
@@ -1,48 +1,231 @@
1
1
  import * as v from 'valibot';
2
- import { UMLElement } from 'plantuml-parser';
3
2
 
3
+ /**
4
+ * Self-sufficient C4 Model for aact. Covers full PlantUML / Mermaid C4 /
5
+ * Structurizr DSL API surface — round-trip без потерь данных для всех
6
+ * популярных C4-as-code инструментов.
7
+ *
8
+ * Scope (намеренно): Solution Architect — C4 Static (L1/L2/L3) + System
9
+ * Landscape + Dynamic. НЕ покрывается: Deployment view (System Architect /
10
+ * kube-score territory), ArchiMate, UML, BPMN.
11
+ *
12
+ * Performance: Record<string, T> вместо Map<string, T> — на масштабе aact
13
+ * (30-300 containers) V8 inline cache даёт ~1ns lookup, Map ~50ns. Плюс
14
+ * JSON.stringify работает нативно, console.log показывает tree.
15
+ */
16
+ /** C4 element types. Полный stdlib набор. */
17
+ type ContainerKind = "Person" | "System" | "Container" | "ContainerDb" | "ContainerQueue" | "Component" | "ComponentDb" | "ComponentQueue";
18
+ /**
19
+ * Boundary types сохраняются для round-trip без шумного diff'а в git.
20
+ * PlantUML автор писал `System_Boundary` / `Container_Boundary` /
21
+ * `Component_Boundary` / `Enterprise_Boundary` — `aact generate` обязан
22
+ * вернуть тот же ключ. Generic `Boundary(...)` мапится на "System".
23
+ */
24
+ type BoundaryKind = "System" | "Container" | "Component" | "Enterprise";
25
+ /**
26
+ * Foundation для clickable file:line violations в CLI output'е (terminal-link
27
+ * OSC8). Optional на типе — loader'ы заполняют где могут, test fixtures могут
28
+ * опустить.
29
+ */
30
+ interface SourceLocation {
31
+ readonly file: string;
32
+ readonly line: number;
33
+ readonly column?: number;
34
+ readonly endLine?: number;
35
+ }
36
+ /**
37
+ * Связь между двумя контейнерами. `to` — имя целевого контейнера (name-ref),
38
+ * не объектная ссылка — это рвёт Container↔Relation цикл, делает Model
39
+ * сериализуемой и упрощает test fixtures (`to: "containerB"` вместо ref'а).
40
+ */
4
41
  interface Relation {
5
- readonly to: Container;
42
+ /** Имя целевого контейнера. Lookup через `model.containers[rel.to]` или helper `targetOf(model, rel)`. */
43
+ readonly to: string;
44
+ /** Описание/label. PlantUML `Rel(from, to, label, ...)`, Structurizr `rel.description`. */
45
+ readonly description?: string;
46
+ /** Технология. PlantUML `Rel(..., ?techn, ...)`, Structurizr `rel.technology`. */
6
47
  readonly technology?: string;
7
- readonly tags?: string[];
8
- }
9
-
48
+ /** Tags всегда массив (пустой если нет тегов) — убирает `?.includes()` шум в правилах. */
49
+ readonly tags: readonly string[];
50
+ /** Sprite. PlantUML/Mermaid `Rel(..., ?sprite, ...)`. */
51
+ readonly sprite?: string;
52
+ /** Sequence number для Dynamic diagrams. PlantUML `$index=Index()`, Structurizr dynamic step. */
53
+ readonly order?: number;
54
+ /** $link для clickable diagrams. */
55
+ readonly link?: string;
56
+ /** Structurizr relation properties + perspectives (через `perspective.<name>` prefix). */
57
+ readonly properties?: Readonly<Record<string, string>>;
58
+ /** Foundation для terminal-link OSC8. Заполняется loader'ом где возможно. */
59
+ readonly sourceLocation?: SourceLocation;
60
+ }
61
+ /**
62
+ * C4 element: Person, System, Container или Component. `kind` — typed union,
63
+ * не stringly. `external` — orthogonal flag (не отдельный `System_Ext` kind),
64
+ * покрывает все 8 `_Ext` вариантов PlantUML/Mermaid одним полем.
65
+ */
10
66
  interface Container {
67
+ /** Уникальное имя — ключ в `model.containers`. PlantUML alias / Structurizr `structurizr.dsl.identifier`. */
11
68
  readonly name: string;
69
+ /** Human-readable label. PlantUML `Container(alias, label, ...)`. */
12
70
  readonly label: string;
13
- readonly type?: string;
14
- readonly tags?: string[];
71
+ /** Типизированный C4 kind. Compile-error на typo. */
72
+ readonly kind: ContainerKind;
73
+ /** Внешний контейнер (System_Ext, Container_Ext etc.). Orthogonal к kind. */
74
+ readonly external: boolean;
15
75
  readonly description: string;
16
- readonly relations: Relation[];
17
- }
18
-
76
+ /** C4 technology — Structurizr `cont.technology`, PlantUML `Container(alias, label, ?techn, ...)`. */
77
+ readonly technology?: string;
78
+ /** Tags всегда массив, не optional — убирает `?.includes()` в правилах. */
79
+ readonly tags: readonly string[];
80
+ /** PlantUML/Mermaid `?sprite` — отдельно от tags (раньше попадал в tags). */
81
+ readonly sprite?: string;
82
+ /** Исходящие relations. Целевые контейнеры — name-refs (`relation.to`). */
83
+ readonly relations: readonly Relation[];
84
+ /** $link для clickable diagrams. */
85
+ readonly link?: string;
86
+ /** Structurizr arbitrary properties (включая archetype name + perspectives через `perspective.<name>` prefix). */
87
+ readonly properties?: Readonly<Record<string, string>>;
88
+ readonly sourceLocation?: SourceLocation;
89
+ }
90
+ /**
91
+ * Структурная граница. `containerNames` и `boundaryNames` — name-refs, не
92
+ * object-refs (как в `Relation.to`) — делает Model сериализуемой и упрощает
93
+ * test fixtures.
94
+ */
19
95
  interface Boundary {
20
96
  readonly name: string;
21
97
  readonly label: string;
22
- readonly type?: string;
23
- boundaries: Boundary[];
24
- readonly containers: Container[];
98
+ readonly kind: BoundaryKind;
99
+ /** PlantUML Boundary `?descr`, Structurizr softwareSystem.description. */
100
+ readonly description?: string;
101
+ readonly tags: readonly string[];
102
+ /** Имена контейнеров внутри этой границы. Lookup через `model.containers[name]`. */
103
+ readonly containerNames: readonly string[];
104
+ /** Имена вложенных boundaries. Lookup через `model.boundaries[name]`. */
105
+ readonly boundaryNames: readonly string[];
106
+ readonly link?: string;
107
+ /** Structurizr softwareSystem properties (archetypes etc.). */
108
+ readonly properties?: Readonly<Record<string, string>>;
109
+ readonly sourceLocation?: SourceLocation;
110
+ }
111
+ /**
112
+ * Корневая Model. Record-based для O(1) lookup'ов на масштабе aact и native
113
+ * JSON-сериализации. Все поля readonly — после loader-фазы модель immutable.
114
+ */
115
+ interface Model {
116
+ readonly containers: Readonly<Record<string, Container>>;
117
+ readonly boundaries: Readonly<Record<string, Boundary>>;
118
+ /** Корневые boundaries — top-level в рендере. Все остальные boundary вложены через `boundaryNames`. */
119
+ readonly rootBoundaryNames: readonly string[];
25
120
  }
26
121
 
27
- interface ArchitectureModel {
28
- readonly boundaries: Boundary[];
29
- readonly allContainers: Container[];
30
- }
122
+ /**
123
+ * Issue найденный validateModel — проблема в loader output'е, которую
124
+ * раньше silent drop'ало (Structurizr component relations, PlantUML
125
+ * dangling Rel'ы, duplicate names при load collision).
126
+ *
127
+ * CLI решает severity: dangling/duplicate/cycle — fail, unknown-kind/
128
+ * self-relation — warn.
129
+ */
130
+ type ModelIssue = {
131
+ kind: "dangling-relation";
132
+ from: string;
133
+ to: string;
134
+ } | {
135
+ kind: "container-in-boundary-not-in-model";
136
+ container: string;
137
+ boundary: string;
138
+ } | {
139
+ kind: "boundary-not-in-model";
140
+ parent: string;
141
+ child: string;
142
+ } | {
143
+ kind: "boundary-cycle";
144
+ path: readonly string[];
145
+ } | {
146
+ kind: "duplicate-container-name";
147
+ name: string;
148
+ } | {
149
+ kind: "duplicate-boundary-name";
150
+ name: string;
151
+ } | {
152
+ kind: "self-relation";
153
+ container: string;
154
+ } | {
155
+ kind: "unknown-kind";
156
+ container: string;
157
+ raw: string;
158
+ };
159
+ /**
160
+ * Single-pass O(V + E) проверка инвариантов Model. Loader'ы зовут после
161
+ * построения; CLI surfaces issues пользователю с file:line context (если
162
+ * SourceLocation заполнен).
163
+ *
164
+ * Duplicate names ловятся на loader-side (Record overwrites молча) — loader
165
+ * должен явно проверять collision перед insertion и добавлять issue, либо
166
+ * validateModel может опираться на тот факт, что Record не сохранит дубликат.
167
+ * Здесь мы проверяем по уже-построенной Model — duplicates physically не
168
+ * могут быть, но мы оставляем тип в union для loader'а / future use.
169
+ */
170
+ declare const validateModel: (model: Model) => ModelIssue[];
171
+ declare const isDuplicateContainer: (containers: Readonly<Record<string, Container>>, name: string) => boolean;
31
172
 
32
- declare const EXTERNAL_SYSTEM_TYPE = "System_Ext";
33
- declare const SYSTEM_TYPE = "System";
34
- declare const CONTAINER_TYPE = "Container";
35
- declare const CONTAINER_DB_TYPE = "ContainerDb";
36
- declare const COMPONENT_TYPE = "Component";
37
- declare const BOUNDARY_TYPE = "Boundary";
38
- declare const SYSTEM_BOUNDARY_TYPE = "System_Boundary";
39
- declare const CONTAINER_BOUNDARY_TYPE = "Container_Boundary";
40
- declare const PERSON_TYPE = "Person";
173
+ /**
174
+ * Все loader'ы (PlantUML, Structurizr, Kubernetes, future Mermaid/Compose/
175
+ * LikeC4) строят Model через эту единственную точку. Гарантии:
176
+ *
177
+ * 1. Duplicate name detection — перед insertion'ом в Record. Issue вместо
178
+ * silent overwrite (что Record делает по умолчанию).
179
+ * 2. Final validateModel pass — dangling refs, boundary cycles, unknown
180
+ * kinds. Issues аккумулируются с pre-build duplicates.
181
+ * 3. Immutable Model — Object.freeze на containers/boundaries/root names.
182
+ * 4. Stable insertion order — sorted by name для deterministic output
183
+ * (JSON snapshot тестов, diff-friendly serialization).
184
+ *
185
+ * Tests могут конструировать Model вручную через literal, но через
186
+ * buildModel гарантия проверок одинакова с loader'ами.
187
+ */
188
+ interface ModelBuildInput {
189
+ readonly containers: readonly Container[];
190
+ readonly boundaries: readonly Boundary[];
191
+ readonly rootBoundaryNames: readonly string[];
192
+ /** Issues найденные loader'ом до сборки (parse errors etc.) — добавляются к ModelIssue'ам валидации. */
193
+ readonly preIssues?: readonly ModelIssue[];
194
+ }
195
+ interface ModelBuildResult {
196
+ readonly model: Model;
197
+ readonly issues: readonly ModelIssue[];
198
+ }
199
+ declare const buildModel: (input: ModelBuildInput) => ModelBuildResult;
41
200
 
42
- interface Section {
43
- readonly name: string;
44
- readonly prod_value: string;
45
- }
201
+ /**
202
+ * O(1) container lookup. Возвращает undefined для dangling references
203
+ * (которые validateModel ловит как ModelIssue).
204
+ */
205
+ declare const getContainer: (m: Model, name: string) => Container | undefined;
206
+ /**
207
+ * O(1) boundary lookup.
208
+ */
209
+ declare const getBoundary: (m: Model, name: string) => Boundary | undefined;
210
+ /**
211
+ * Resolve целевого Container'а по Relation.to (name-ref). Самый частый
212
+ * pattern в правилах: `targetOf(model, rel)?.kind === "ContainerDb"`.
213
+ */
214
+ declare const targetOf: (m: Model, rel: Relation) => Container | undefined;
215
+ /**
216
+ * Все контейнеры в model как массив. Удобно для `.filter()` / `.map()`,
217
+ * когда нужен flat iteration.
218
+ */
219
+ declare const allContainers: (m: Model) => Container[];
220
+ /**
221
+ * Все boundaries в model как массив.
222
+ */
223
+ declare const allBoundaries: (m: Model) => Boundary[];
224
+ /**
225
+ * Depth-first iteration всех boundaries — от root'ов вглубь. Visited set
226
+ * защищает от accidental cycles (validateModel ловит их явно).
227
+ */
228
+ declare const walkBoundaries: (m: Model) => Generator<Boundary>;
46
229
 
47
230
  interface CouplingRelation {
48
231
  from: string;
@@ -55,6 +238,10 @@ interface BoundaryAnalysis {
55
238
  coupling: number;
56
239
  couplingRelations: CouplingRelation[];
57
240
  }
241
+ interface DatabasesInfo {
242
+ count: number;
243
+ consumes: number;
244
+ }
58
245
  interface AnalysisReport {
59
246
  elementsCount: number;
60
247
  syncApiCalls: number;
@@ -63,242 +250,346 @@ interface AnalysisReport {
63
250
  boundaries: BoundaryAnalysis[];
64
251
  }
65
252
  interface AnalyzedArchitecture {
66
- model: ArchitectureModel;
253
+ model: Model;
67
254
  report: AnalysisReport;
68
255
  }
69
- interface DatabasesInfo {
70
- count: number;
71
- consumes: number;
72
- }
73
256
  interface AnalyzeOptions {
74
- apiTechnologies?: string[];
75
- externalType?: string;
76
- dbType?: string;
257
+ apiTechnologies?: readonly string[];
258
+ }
259
+ declare const analyzeArchitecture: (model: Model, options?: AnalyzeOptions) => AnalyzedArchitecture;
260
+
261
+ /**
262
+ * Capability-based Format API. Один Format interface, capabilities
263
+ * (load / generate / fix) — optional. Каждый формат self-describes что
264
+ * support'ит. CLI и users-as-library narrowing через type guards.
265
+ *
266
+ * Долгосрочно (десятилетия): новые capabilities добавляются как optional
267
+ * methods в существующем interface, не как новые типы. Никаких
268
+ * "SourceFormat vs ArtifactFormat" junk types под комбинации фич.
269
+ */
270
+ /**
271
+ * Regex-based primitives для in-place editing source files. Используется
272
+ * fix-функциями правил. Future-ready: AST primitives добавятся как
273
+ * `ast?: AstPrimitives` в FixCapability — non-breaking.
274
+ */
275
+ interface SourceSyntax {
276
+ containerPattern(name: string): string;
277
+ containerDecl(name: string, label: string, tags?: string): string;
278
+ relationPattern(from: string, to: string): string;
279
+ relationDecl(from: string, to: string, tech?: string, tags?: string): string;
77
280
  }
78
- declare const analyzeArchitecture: (model: ArchitectureModel, options?: AnalyzeOptions) => AnalyzedArchitecture;
281
+ interface FixCapability {
282
+ readonly syntax: SourceSyntax;
283
+ }
284
+ /**
285
+ * Сериализованный output генератора. Single-file output (PlantUML/Mermaid/
286
+ * Compose) — массив из одного `GeneratedFile`. Multi-file (k8s manifests
287
+ * per service) — несколько. Один shape, CLI iterate'ит без discriminated
288
+ * dispatch'а.
289
+ */
290
+ interface GeneratedFile {
291
+ readonly path: string;
292
+ readonly content: string;
293
+ }
294
+ interface FormatOutput {
295
+ readonly files: readonly GeneratedFile[];
296
+ }
297
+ /**
298
+ * Результат load'а — Model + diagnostics. Loader заполняет `issues` через
299
+ * buildModel (duplicate names, dangling refs, etc.) + post-build
300
+ * validateModel. CLI решает severity (warn / fail), users-as-library
301
+ * могут игнорировать или экспозить пользователю.
302
+ */
303
+ interface LoadResult {
304
+ readonly model: Model;
305
+ readonly issues: readonly ModelIssue[];
306
+ }
307
+ /**
308
+ * Format — единственный contract для всех C4-as-code форматов и IaC
309
+ * artefactов. Capabilities опциональны:
310
+ * - PlantUML / Mermaid / Structurizr: load + generate + fix
311
+ * - Kubernetes / Compose: load + generate (no fix — IaC не authored руками)
312
+ * - Hypothetical write-only: только generate
313
+ * - Hypothetical read-only: только load
314
+ *
315
+ * `name` — уникальный идентификатор в Format registry (config.source.type).
316
+ * `defaultPattern` — glob для CLI `init` шаблонов и автодетекта.
317
+ *
318
+ * Structurizr load/write asymmetry (load workspace.json → fix workspace.dsl)
319
+ * решается через `AactConfig.source.writePath`, не через Format type.
320
+ */
321
+ interface Format {
322
+ readonly name: string;
323
+ readonly defaultPattern?: string;
324
+ load?(path: string): Promise<LoadResult>;
325
+ generate?(model: Model): FormatOutput;
326
+ fix?: FixCapability;
327
+ }
328
+ /** Format с гарантированным load — после canLoad narrow. */
329
+ type LoadableFormat = Format & {
330
+ load: NonNullable<Format["load"]>;
331
+ };
332
+ /** Format с гарантированным generate — после canGenerate narrow. */
333
+ type GeneratableFormat = Format & {
334
+ generate: NonNullable<Format["generate"]>;
335
+ };
336
+ /** Format с гарантированным fix — после canFix narrow. */
337
+ type FixableFormat = Format & {
338
+ fix: NonNullable<Format["fix"]>;
339
+ };
340
+ declare const canLoad: (f: Format) => f is LoadableFormat;
341
+ declare const canGenerate: (f: Format) => f is GeneratableFormat;
342
+ declare const canFix: (f: Format) => f is FixableFormat;
343
+
344
+ interface Violation {
345
+ readonly container: string;
346
+ readonly message: string;
347
+ }
348
+ interface SourceEdit {
349
+ readonly type: "add" | "remove" | "replace";
350
+ readonly search: string;
351
+ readonly content?: string;
352
+ }
353
+ interface FixResult {
354
+ readonly rule: string;
355
+ readonly description: string;
356
+ readonly edits: readonly SourceEdit[];
357
+ }
358
+ /**
359
+ * Function-type aliases — useful когда user пишет check / fix отдельно от
360
+ * RuleDefinition объекта. Внутри RuleDefinition объявлены как методы
361
+ * (bivariant): `RuleDefinition<MyOptions>` assignable to `RuleDefinition<unknown>`,
362
+ * чтобы typed rules без cast'а попадали в `customRules: readonly RuleDefinition[]`.
363
+ *
364
+ * Fix получает `SourceSyntax` (regex primitives). Будущее — `FixCapability`
365
+ * с AST primitives. Эволюция non-breaking: добавляется новое поле SourceSyntax.
366
+ */
367
+ type CheckFn<O = unknown> = (model: Model, options?: O) => readonly Violation[];
368
+ type FixFn<O = unknown> = (model: Model, violations: readonly Violation[], syntax: SourceSyntax, options?: O) => readonly FixResult[];
369
+ interface RuleDefinition<O = unknown> {
370
+ readonly name: string;
371
+ /** Human-readable description — для CLI `rules list`, docs, CHANGELOG. */
372
+ readonly description: string;
373
+ check(model: Model, options?: O): readonly Violation[];
374
+ fix?(model: Model, violations: readonly Violation[], syntax: SourceSyntax, options?: O): readonly FixResult[];
375
+ }
376
+ /**
377
+ * Identity helper для inline RuleDefinition declaracий. Generic с `<const T>`
378
+ * сохраняет literal type для всех полей — particularly `name`, что позволяет
379
+ * defineConfig'у через mapped type вытащить literal rule name и propagate'нуть
380
+ * autocomplete в `rules{}`.
381
+ *
382
+ * `T extends RuleDefinition` (constraint без widening через `extends`) валидирует
383
+ * shape без потери literal'ов.
384
+ *
385
+ * Built-ins и custom rules используют один и тот же `RuleDefinition<O>` —
386
+ * defineRule одинаково применим к обоим.
387
+ */
388
+ declare const defineRule: <const T extends RuleDefinition>(rule: T) => T;
389
+
390
+ interface AclOptions {
391
+ /** Tag, который маркирует ACL-контейнер. Default "acl". */
392
+ readonly tag?: string;
393
+ }
394
+ /**
395
+ * Anti-corruption Layer: контейнер, который зовёт внешние системы, должен
396
+ * быть тэгирован как ACL.
397
+ *
398
+ * v3: внешние системы определяются через `target.external === true`
399
+ * (orthogonal flag), не через kind == "System_Ext".
400
+ */
401
+ declare const aclRule: RuleDefinition<AclOptions>;
402
+
403
+ interface ApiGatewayOptions {
404
+ /** Tag, который маркирует ACL-контейнер. Default "acl". */
405
+ readonly aclTag?: string;
406
+ /** Regex для определения "это gateway technology". Default /gateway/i. */
407
+ readonly gatewayPattern?: RegExp;
408
+ }
409
+ /**
410
+ * API Gateway pattern: ACL-контейнеры, зовущие внешние системы, должны
411
+ * проходить через API Gateway (technology содержит "gateway").
412
+ */
413
+ declare const apiGatewayRule: RuleDefinition<ApiGatewayOptions>;
414
+
415
+ interface CrudOptions {
416
+ /** Tags маркирующие repo/relay контейнеры. Default ["repo", "relay"]. */
417
+ readonly repoTags?: readonly string[];
418
+ }
419
+ /**
420
+ * Database per CRUD-service: containers без repo-tag не должны напрямую
421
+ * обращаться к databases. Доступ через repo/relay прокси. Repo-контейнеры
422
+ * наоборот должны только базы трогать (no external deps).
423
+ */
424
+ declare const crudRule: RuleDefinition<CrudOptions>;
425
+
426
+ interface DbPerServiceOptions {
427
+ /** Tags маркирующие repo/relay контейнеры — определяют owner of DB. */
428
+ readonly ownerTags?: readonly string[];
429
+ }
430
+ /**
431
+ * Database per Service: одна база — один владелец. Если несколько
432
+ * контейнеров напрямую обращаются к одной БД, это нарушение принципа.
433
+ */
434
+ declare const dbPerServiceRule: RuleDefinition<DbPerServiceOptions>;
79
435
 
436
+ /**
437
+ * AactConfig — что пишет пользователь в `aact.config.ts`. Source + rules
438
+ * (per-rule опции) + customRules (external RuleDefinition[]) + generate.
439
+ *
440
+ * v3: убраны legacy options (externalType, dbType, internalType) — kind
441
+ * и external теперь typed fields на Model, а не configurable. Если нужно
442
+ * переопределить detection — это сейчас loader-side concern, не rule.
443
+ *
444
+ * Source shape — accepts:
445
+ * 1. String shorthand: `source: "./architecture.puml"` — type inferred from path
446
+ * 2. Object form: `source: { path, type?, writePath? }` — type optional,
447
+ * inferred from path if missing; explicit overrides infer
448
+ *
449
+ * Type accepts arbitrary string (validated against runtime format registry at
450
+ * load time) — добавление нового формата = entry в registry, не breaking-bump.
451
+ *
452
+ * Rules — looseObject: typed entries для built-ins (autocomplete +
453
+ * options валидация), extra keys разрешены для custom rules. Custom rule
454
+ * options проверяются на check() time через rule.optionsSchema (если есть).
455
+ *
456
+ * CustomRules — array of RuleDefinition. Auto-enabled при load'е (не нужно
457
+ * писать `rules: { myRule: true }`). Чтобы выключить — `rules.<name>: false`.
458
+ */
80
459
  declare const AactConfigSchema: v.StrictObjectSchema<{
81
- readonly source: v.StrictObjectSchema<{
82
- readonly type: v.PicklistSchema<["plantuml", "structurizr"], undefined>;
460
+ readonly source: v.UnionSchema<[v.StringSchema<undefined>, v.StrictObjectSchema<{
83
461
  readonly path: v.StringSchema<undefined>;
462
+ /** Optional — infer'ится из `path` через format registry `defaultPattern` если опущен. */
463
+ readonly type: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
464
+ /** Structurizr only: куда писать fix'ы (workspace.dsl). */
84
465
  readonly writePath: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
85
- }, undefined>;
86
- readonly rules: v.OptionalSchema<v.StrictObjectSchema<{
466
+ }, undefined>], undefined>;
467
+ readonly rules: v.OptionalSchema<v.LooseObjectSchema<{
87
468
  readonly acl: v.OptionalSchema<v.UnionSchema<[v.BooleanSchema<undefined>, v.StrictObjectSchema<{
88
469
  tag: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
89
- externalType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
90
470
  }, undefined>], undefined>, undefined>;
91
471
  readonly acyclic: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
92
472
  readonly apiGateway: v.OptionalSchema<v.UnionSchema<[v.BooleanSchema<undefined>, v.StrictObjectSchema<{
93
473
  aclTag: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
94
- externalType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
95
474
  gatewayPattern: v.OptionalSchema<v.InstanceSchema<RegExpConstructor, undefined>, undefined>;
96
475
  }, undefined>], undefined>, undefined>;
97
476
  readonly crud: v.OptionalSchema<v.UnionSchema<[v.BooleanSchema<undefined>, v.StrictObjectSchema<{
98
477
  repoTags: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
99
- dbType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
100
478
  }, undefined>], undefined>, undefined>;
101
479
  readonly dbPerService: v.OptionalSchema<v.UnionSchema<[v.BooleanSchema<undefined>, v.StrictObjectSchema<{
102
- dbType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
103
480
  ownerTags: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
104
481
  }, undefined>], undefined>, undefined>;
105
- readonly cohesion: v.OptionalSchema<v.UnionSchema<[v.BooleanSchema<undefined>, v.StrictObjectSchema<{
106
- externalType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
107
- internalType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
108
- }, undefined>], undefined>, undefined>;
109
- readonly stableDependencies: v.OptionalSchema<v.UnionSchema<[v.BooleanSchema<undefined>, v.StrictObjectSchema<{
110
- externalType: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
111
- }, undefined>], undefined>, undefined>;
482
+ readonly cohesion: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
483
+ readonly stableDependencies: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
112
484
  readonly commonReuse: v.OptionalSchema<v.BooleanSchema<undefined>, undefined>;
113
485
  }, undefined>, undefined>;
486
+ readonly customRules: v.OptionalSchema<v.ArraySchema<v.AnySchema, undefined>, undefined>;
114
487
  readonly generate: v.OptionalSchema<v.StrictObjectSchema<{
115
488
  readonly kubernetes: v.OptionalSchema<v.StrictObjectSchema<{
116
489
  readonly path: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
117
- readonly exclude: v.OptionalSchema<v.ArraySchema<v.StringSchema<undefined>, undefined>, undefined>;
118
490
  }, undefined>, undefined>;
119
491
  readonly boundaryLabel: v.OptionalSchema<v.StringSchema<undefined>, undefined>;
120
492
  }, undefined>, undefined>;
121
493
  }, undefined>;
122
- type AactConfig = v.InferOutput<typeof AactConfigSchema>;
123
- declare const defineConfig: (config: AactConfig) => AactConfig;
124
-
125
- interface KubernetesGenerateOptions {
126
- defaultPort?: number;
127
- dbConnectionTemplate?: string;
128
- }
129
- interface KubernetesOutput {
130
- fileName: string;
131
- content: string;
132
- }
133
- declare const generateKubernetes: (model: ArchitectureModel, options?: KubernetesGenerateOptions) => KubernetesOutput[];
134
-
135
- interface PlantumlFromModelOptions {
136
- boundaryLabel?: string;
137
- }
138
- declare const generatePlantumlFromModel: (model: ArchitectureModel, options?: PlantumlFromModelOptions) => string;
139
-
140
- interface EnvValue {
141
- prod?: string;
142
- default?: string;
143
- }
144
- interface DeployConfig {
145
- name: string;
146
- fileName?: string;
147
- readonly environment?: Record<string, EnvValue>;
148
- sections: Section[];
149
- }
150
-
151
- interface LoadDeployConfigsOptions {
152
- path?: string;
153
- exclude?: string[];
154
- }
155
- declare const loadMicroserviceDeployConfigs: (options?: LoadDeployConfigsOptions) => Promise<DeployConfig[]>;
156
-
157
- interface KubernetesMapOptions {
158
- envWhitelist?: (string | RegExp)[];
159
- envNamePartsToCleanup?: (string | RegExp)[];
160
- }
161
- declare const mapFromConfigs: (deployConfigs: DeployConfig[], options?: KubernetesMapOptions) => DeployConfig[];
162
-
163
- declare const PLANTUML_CONTAINER = "Container";
164
- declare const PLANTUML_CONTAINER_DB = "ContainerDb";
165
- declare const PLANTUML_SYSTEM_EXT = "System_Ext";
166
- declare const PLANTUML_SYSTEM = "System";
167
- declare const PLANTUML_PERSON = "Person";
168
- declare const PLANTUML_COMPONENT = "Component";
169
- declare const PLANTUML_SYSTEM_BOUNDARY = "System_Boundary";
170
- declare const PLANTUML_CONTAINER_BOUNDARY = "Container_Boundary";
171
- declare const PLANTUML_BOUNDARY = "Boundary";
172
-
173
- declare const loadPlantumlElements: (filePath: string) => Promise<UMLElement[]>;
174
-
175
- declare const mapContainersFromPlantumlElements: (elements: UMLElement[]) => ArchitectureModel;
176
-
177
- declare const STRUCTURIZR_LOCATION_EXTERNAL = "External";
178
- declare const STRUCTURIZR_INTERACTION_ASYNC = "Asynchronous";
179
- declare const STRUCTURIZR_TAG_ASYNC = "async";
180
-
181
- interface StructurizrWorkspace {
182
- id?: number;
183
- name: string;
184
- description?: string;
185
- model: StructurizrModel;
186
- }
187
- interface StructurizrModel {
188
- enterprise?: {
189
- name: string;
494
+ /**
495
+ * Built-in rules config — handcrafted interface (вместо v.InferOutput) чтобы
496
+ * TS user получал чистые option types в `rules{}` без `[key: string]: unknown`
497
+ * index-signature leak из looseObject inference.
498
+ *
499
+ * Runtime parsing идёт через `AactConfigSchema.rules` looseObject; этот TS-тип
500
+ * это user-facing surface для autocomplete.
501
+ */
502
+ interface BuiltinRulesConfig {
503
+ readonly acl?: boolean | AclOptions;
504
+ readonly acyclic?: boolean;
505
+ readonly apiGateway?: boolean | ApiGatewayOptions;
506
+ readonly crud?: boolean | CrudOptions;
507
+ readonly dbPerService?: boolean | DbPerServiceOptions;
508
+ readonly cohesion?: boolean;
509
+ readonly stableDependencies?: boolean;
510
+ readonly commonReuse?: boolean;
511
+ }
512
+ /**
513
+ * Extract'ит options type из RuleDefinition'а через сигнатуру `check(model, options?: O)`.
514
+ * Используется defineConfig'ом для inference custom rule options types в `rules{}`.
515
+ */
516
+ type ExtractRuleOptions<R> = R extends RuleDefinition ? Exclude<Parameters<R["check"]>[1], undefined> : never;
517
+ /**
518
+ * Maps кастомные правила к их config-shape: `{ <rule.name>?: false | options }`.
519
+ * Через `<const C>` в defineConfig — TS preserves литеральные имена,
520
+ * R['name'] становится narrow string literal, а не `string`.
521
+ */
522
+ type CustomRulesConfig<C extends readonly RuleDefinition[]> = {
523
+ readonly [R in C[number] as R["name"]]?: boolean | ExtractRuleOptions<R>;
524
+ };
525
+ type AactRulesConfig<C extends readonly RuleDefinition[]> = BuiltinRulesConfig & CustomRulesConfig<C>;
526
+ /**
527
+ * Raw user-facing shape это что юзер пишет в aact.config.ts. Generic'и
528
+ * подбираются через `defineConfig<const C>` чтобы дать autocomplete на
529
+ * custom rule options в `rules{}`.
530
+ */
531
+ interface AactConfigInput<C extends readonly RuleDefinition[] = readonly RuleDefinition[]> {
532
+ readonly source: string | {
533
+ readonly path: string;
534
+ readonly type?: string;
535
+ readonly writePath?: string;
190
536
  };
191
- people?: StructurizrPerson[];
192
- softwareSystems?: StructurizrSoftwareSystem[];
193
- }
194
- interface StructurizrProperties {
195
- "structurizr.dsl.identifier"?: string;
196
- [key: string]: string | undefined;
197
- }
198
- interface StructurizrPerson {
199
- id: string;
200
- name: string;
201
- description?: string;
202
- tags?: string;
203
- properties?: StructurizrProperties;
204
- relationships?: StructurizrRelationship[];
205
- }
206
- interface StructurizrSoftwareSystem {
207
- id: string;
208
- name: string;
209
- description?: string;
210
- location?: "External" | "Internal" | "Unspecified";
211
- tags?: string;
212
- properties?: StructurizrProperties;
213
- containers?: StructurizrContainer[];
214
- relationships?: StructurizrRelationship[];
215
- }
216
- interface StructurizrContainer {
217
- id: string;
218
- name: string;
219
- description?: string;
220
- technology?: string;
221
- tags?: string;
222
- properties?: StructurizrProperties;
223
- components?: StructurizrComponent[];
224
- relationships?: StructurizrRelationship[];
225
- }
226
- interface StructurizrComponent {
227
- id: string;
228
- name: string;
229
- description?: string;
230
- technology?: string;
231
- tags?: string;
232
- properties?: StructurizrProperties;
233
- relationships?: StructurizrRelationship[];
234
- }
235
- interface StructurizrRelationship {
236
- id: string;
237
- description?: string;
238
- sourceId: string;
239
- destinationId: string;
240
- technology?: string;
241
- interactionStyle?: "Synchronous" | "Asynchronous";
242
- tags?: string;
243
- }
244
-
245
- declare const loadStructurizrWorkspace: (filePath: string) => Promise<StructurizrWorkspace>;
246
- declare const mapContainersFromStructurizr: (workspace: StructurizrWorkspace) => ArchitectureModel;
247
- declare const loadStructurizrElements: (filePath: string) => Promise<ArchitectureModel>;
248
-
249
- interface SourceSyntax {
250
- containerPattern(name: string): string;
251
- containerDecl(name: string, label: string, tags?: string): string;
252
- relationPattern(from: string, to: string): string;
253
- relationDecl(from: string, to: string, tech?: string, tags?: string): string;
254
- }
255
-
256
- declare const structurizrDslSyntax: SourceSyntax;
257
-
258
- interface Violation {
259
- container: string;
260
- message: string;
261
- }
537
+ readonly rules?: AactRulesConfig<C>;
538
+ readonly customRules?: C;
539
+ readonly generate?: v.InferInput<typeof AactConfigSchema>["generate"];
540
+ }
541
+ /** Normalized — то что `loadAndValidateConfig` возвращает. Source всегда object с populated `type`. */
542
+ interface AactConfig {
543
+ readonly source: {
544
+ readonly path: string;
545
+ readonly type: string;
546
+ readonly writePath?: string;
547
+ };
548
+ readonly rules?: BuiltinRulesConfig & Readonly<Record<string, unknown>>;
549
+ readonly customRules?: readonly RuleDefinition[];
550
+ readonly generate?: v.InferOutput<typeof AactConfigSchema>["generate"];
551
+ }
552
+ /**
553
+ * Typed config builder. `<const C>` captures customRules array's literal type
554
+ * — каждое правило сохраняет свой `name` (literal) и `Parameters<check>[1]`
555
+ * (options type). Через mapped type `CustomRulesConfig<C>` это даёт user'у
556
+ * autocomplete + type validation на `rules: { customRuleName: { ←tab } }`.
557
+ */
558
+ declare const defineConfig: <const C extends readonly RuleDefinition[]>(config: AactConfigInput<C>) => AactConfigInput<C>;
262
559
 
263
- interface AclOptions {
264
- tag?: string;
265
- externalType?: string;
266
- }
267
- declare const checkAcl: (containers: Container[], options?: AclOptions) => Violation[];
560
+ /**
561
+ * Async lookup формата по name. Throws если name unknown — let caller
562
+ * surface user-facing error с config context.
563
+ */
564
+ declare const loadFormat: (name: string) => Promise<Format>;
565
+ /** Все зарегистрированные имена форматов. CLI `init` использует для prompt'а. */
566
+ declare const knownFormatNames: () => readonly string[];
268
567
 
269
- declare const checkAcyclic: (containers: Container[]) => Violation[];
568
+ /**
569
+ * Acyclic Dependencies Principle: dependency graph не должен иметь циклов.
570
+ * Per-container DFS, visited set предотвращает infinite loop. Dangling refs
571
+ * (rel.to не в model.containers) — early return false; validateModel
572
+ * surface'ит их отдельно.
573
+ */
574
+ declare const acyclicRule: RuleDefinition;
270
575
 
271
- interface ApiGatewayOptions {
272
- aclTag?: string;
273
- externalType?: string;
274
- gatewayPattern?: RegExp;
275
- }
276
- declare const checkApiGateway: (containers: Container[], options?: ApiGatewayOptions) => Violation[];
576
+ declare const cohesionRule: RuleDefinition;
277
577
 
278
- interface CohesionOptions {
279
- externalType?: string;
280
- internalType?: string;
281
- }
282
- declare const checkCohesion: (model: ArchitectureModel, options?: CohesionOptions) => Violation[];
578
+ declare const commonReuseRule: RuleDefinition;
283
579
 
284
- declare const checkCommonReuse: (model: ArchitectureModel) => Violation[];
580
+ declare const applyEdits: (source: string, edits: readonly SourceEdit[]) => string;
285
581
 
286
- interface CrudOptions {
287
- repoTags?: string[];
288
- dbType?: string;
289
- }
290
- declare const checkCrud: (containers: Container[], options?: CrudOptions) => Violation[];
291
-
292
- interface DbPerServiceOptions {
293
- dbType?: string;
294
- ownerTags?: string[];
295
- }
296
- declare const checkDbPerService: (containers: Container[], options?: DbPerServiceOptions) => Violation[];
582
+ /**
583
+ * Все built-in правила. Порядок определяет default order CLI вывода.
584
+ * Adding new rule: импорт + строчка в массиве, ничего больше не трогать.
585
+ *
586
+ * `check` / `fix` объявлены как методы в `RuleDefinition` (bivariant под
587
+ * strictFunctionTypes), поэтому typed rules упаковываются в `RuleDefinition[]`
588
+ * без cast'ов. Это тот же контракт что используют customRules.
589
+ */
590
+ declare const ruleRegistry: readonly RuleDefinition[];
297
591
 
298
- interface StableDependenciesOptions {
299
- externalType?: string;
300
- }
301
- declare const checkStableDependencies: (containers: Container[], options?: StableDependenciesOptions) => Violation[];
592
+ declare const stableDependenciesRule: RuleDefinition;
302
593
 
303
- export { AactConfigSchema, BOUNDARY_TYPE, COMPONENT_TYPE, CONTAINER_BOUNDARY_TYPE, CONTAINER_DB_TYPE, CONTAINER_TYPE, EXTERNAL_SYSTEM_TYPE, PERSON_TYPE, PLANTUML_BOUNDARY, PLANTUML_COMPONENT, PLANTUML_CONTAINER, PLANTUML_CONTAINER_BOUNDARY, PLANTUML_CONTAINER_DB, PLANTUML_PERSON, PLANTUML_SYSTEM, PLANTUML_SYSTEM_BOUNDARY, PLANTUML_SYSTEM_EXT, STRUCTURIZR_INTERACTION_ASYNC, STRUCTURIZR_LOCATION_EXTERNAL, STRUCTURIZR_TAG_ASYNC, SYSTEM_BOUNDARY_TYPE, SYSTEM_TYPE, analyzeArchitecture, checkAcl, checkAcyclic, checkApiGateway, checkCohesion, checkCommonReuse, checkCrud, checkDbPerService, checkStableDependencies, defineConfig, generateKubernetes, generatePlantumlFromModel, loadMicroserviceDeployConfigs, loadPlantumlElements, loadStructurizrElements, loadStructurizrWorkspace, mapContainersFromPlantumlElements, mapContainersFromStructurizr, mapFromConfigs, structurizrDslSyntax };
304
- export type { AactConfig, AclOptions, AnalysisReport, AnalyzeOptions, AnalyzedArchitecture, ApiGatewayOptions, ArchitectureModel, Boundary, BoundaryAnalysis, CohesionOptions, Container, CouplingRelation, CrudOptions, DbPerServiceOptions, DeployConfig, EnvValue, KubernetesGenerateOptions, KubernetesMapOptions, KubernetesOutput, LoadDeployConfigsOptions, PlantumlFromModelOptions, Relation, Section, StableDependenciesOptions, StructurizrComponent, StructurizrContainer, StructurizrModel, StructurizrPerson, StructurizrProperties, StructurizrRelationship, StructurizrSoftwareSystem, StructurizrWorkspace, Violation };
594
+ export { AactConfigSchema, aclRule, acyclicRule, allBoundaries, allContainers, analyzeArchitecture, apiGatewayRule, applyEdits, buildModel, canFix, canGenerate, canLoad, cohesionRule, commonReuseRule, crudRule, dbPerServiceRule, defineConfig, defineRule, getBoundary, getContainer, isDuplicateContainer, knownFormatNames, loadFormat, ruleRegistry, stableDependenciesRule, targetOf, validateModel, walkBoundaries };
595
+ export type { AactConfig, AactConfigInput, AactRulesConfig, AclOptions, AnalysisReport, AnalyzeOptions, AnalyzedArchitecture, ApiGatewayOptions, Boundary, BoundaryAnalysis, BoundaryKind, BuiltinRulesConfig, CheckFn, Container, ContainerKind, CouplingRelation, CrudOptions, CustomRulesConfig, DbPerServiceOptions, FixCapability, FixFn, FixResult, Format, FormatOutput, LoadResult, Model, ModelBuildInput, ModelBuildResult, ModelIssue, Relation, RuleDefinition, SourceEdit, SourceLocation, SourceSyntax, Violation };