@mytechtoday/augment-extensions 1.3.0 → 1.4.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/LICENSE +22 -22
- package/README.md +105 -6
- package/augment-extensions/domain-rules/software-architecture/README.md +143 -143
- package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -961
- package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -990
- package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -882
- package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -703
- package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -957
- package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -747
- package/augment-extensions/domain-rules/software-architecture/module.json +119 -119
- package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -763
- package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -409
- package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -684
- package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -1381
- package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -616
- package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -306
- package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -554
- package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -776
- package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -503
- package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -1199
- package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -351
- package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -556
- package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -797
- package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -1345
- package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -1039
- package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -711
- package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -568
- package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -961
- package/augment-extensions/visual-design/CHANGELOG.md +132 -132
- package/augment-extensions/visual-design/README.md +255 -255
- package/augment-extensions/visual-design/__tests__/README.md +119 -119
- package/augment-extensions/visual-design/__tests__/style-selector.test.ts +172 -172
- package/augment-extensions/visual-design/__tests__/vendor-styles.test.ts +214 -214
- package/augment-extensions/visual-design/domains/other/ai-prompt-helper.ts +157 -157
- package/augment-extensions/visual-design/domains/other/dotnet-application.ts +156 -156
- package/augment-extensions/visual-design/domains/other/linux-platform.ts +156 -156
- package/augment-extensions/visual-design/domains/other/mobile-application.ts +157 -157
- package/augment-extensions/visual-design/domains/other/motion-picture.ts +156 -156
- package/augment-extensions/visual-design/domains/other/os-application.ts +156 -156
- package/augment-extensions/visual-design/domains/other/print-campaigns.ts +158 -158
- package/augment-extensions/visual-design/domains/other/web-app.ts +157 -157
- package/augment-extensions/visual-design/domains/other/website.ts +161 -161
- package/augment-extensions/visual-design/domains/other/windows-platform.ts +156 -156
- package/augment-extensions/visual-design/domains/web-page-styles/amazon-cloudscape.ts +506 -506
- package/augment-extensions/visual-design/domains/web-page-styles/google-modern.ts +615 -615
- package/augment-extensions/visual-design/domains/web-page-styles/microsoft-fluent.ts +531 -531
- package/augment-extensions/visual-design/examples/README.md +97 -97
- package/augment-extensions/visual-design/examples/ai-prompt-generation.md +233 -233
- package/augment-extensions/visual-design/examples/basic-usage.md +216 -216
- package/augment-extensions/visual-design/examples/domain-workflows.md +257 -257
- package/augment-extensions/visual-design/examples/vendor-comparison.md +247 -247
- package/augment-extensions/visual-design/module.json +78 -78
- package/augment-extensions/visual-design/style-selector.ts +177 -177
- package/augment-extensions/visual-design/types.ts +302 -302
- package/augment-extensions/visual-design/visual-design-core.ts +469 -469
- package/augment-extensions/workflows/adr-support/README.md +227 -227
- package/augment-extensions/workflows/adr-support/__tests__/adr-validator.test.ts +203 -203
- package/augment-extensions/workflows/adr-support/adr-validator.ts +162 -162
- package/augment-extensions/workflows/adr-support/examples/complete-lifecycle-example.md +449 -449
- package/augment-extensions/workflows/adr-support/examples/integration-example.md +580 -580
- package/augment-extensions/workflows/adr-support/examples/superseding-example.md +436 -436
- package/augment-extensions/workflows/adr-support/module.json +112 -112
- package/augment-extensions/workflows/adr-support/rules/adr-creation.md +372 -372
- package/augment-extensions/workflows/adr-support/rules/beads-integration.md +443 -443
- package/augment-extensions/workflows/adr-support/rules/conflict-detection.md +486 -486
- package/augment-extensions/workflows/adr-support/rules/decision-detection.md +362 -362
- package/augment-extensions/workflows/adr-support/rules/lifecycle-management.md +427 -427
- package/augment-extensions/workflows/adr-support/rules/openspec-integration.md +465 -465
- package/augment-extensions/workflows/adr-support/rules/template-selection.md +405 -405
- package/augment-extensions/workflows/adr-support/rules/validation-rules.md +543 -543
- package/augment-extensions/workflows/adr-support/schemas/adr-config.json +191 -191
- package/augment-extensions/workflows/adr-support/schemas/adr-metadata.json +172 -172
- package/augment-extensions/workflows/adr-support/templates/business-case.md +235 -235
- package/augment-extensions/workflows/adr-support/templates/madr-elaborate.md +197 -197
- package/augment-extensions/workflows/adr-support/templates/madr-simple.md +68 -68
- package/augment-extensions/workflows/adr-support/templates/nygard.md +84 -84
- package/augment-extensions/writing-standards/screenplay/rules/file-organization.md +213 -213
- package/augment-extensions/writing-standards/screenplay/utils/__tests__/file-organization.test.ts +169 -169
- package/augment-extensions/writing-standards/screenplay/utils/file-organization.ts +165 -165
- package/cli/dist/commands/agent.d.ts +37 -0
- package/cli/dist/commands/agent.d.ts.map +1 -0
- package/cli/dist/commands/agent.js +222 -0
- package/cli/dist/commands/agent.js.map +1 -0
- package/cli/dist/commands/beads.d.ts +64 -0
- package/cli/dist/commands/beads.d.ts.map +1 -0
- package/cli/dist/commands/beads.js +377 -0
- package/cli/dist/commands/beads.js.map +1 -0
- package/cli/dist/commands/change.d.ts +54 -0
- package/cli/dist/commands/change.d.ts.map +1 -0
- package/cli/dist/commands/change.js +243 -0
- package/cli/dist/commands/change.js.map +1 -0
- package/cli/dist/commands/clean.d.ts +15 -0
- package/cli/dist/commands/clean.d.ts.map +1 -0
- package/cli/dist/commands/clean.js +63 -0
- package/cli/dist/commands/clean.js.map +1 -0
- package/cli/dist/commands/clone.d.ts +15 -0
- package/cli/dist/commands/clone.d.ts.map +1 -0
- package/cli/dist/commands/clone.js +49 -0
- package/cli/dist/commands/clone.js.map +1 -0
- package/cli/dist/commands/config.d.ts +33 -0
- package/cli/dist/commands/config.d.ts.map +1 -0
- package/cli/dist/commands/config.js +166 -0
- package/cli/dist/commands/config.js.map +1 -0
- package/cli/dist/commands/context.d.ts +38 -0
- package/cli/dist/commands/context.d.ts.map +1 -0
- package/cli/dist/commands/context.js +205 -0
- package/cli/dist/commands/context.js.map +1 -0
- package/cli/dist/commands/create.d.ts +18 -0
- package/cli/dist/commands/create.d.ts.map +1 -0
- package/cli/dist/commands/create.js +178 -0
- package/cli/dist/commands/create.js.map +1 -0
- package/cli/dist/commands/diff.d.ts +19 -0
- package/cli/dist/commands/diff.d.ts.map +1 -0
- package/cli/dist/commands/diff.js +104 -0
- package/cli/dist/commands/diff.js.map +1 -0
- package/cli/dist/commands/doctor.d.ts +14 -0
- package/cli/dist/commands/doctor.d.ts.map +1 -0
- package/cli/dist/commands/doctor.js +62 -0
- package/cli/dist/commands/doctor.js.map +1 -0
- package/cli/dist/commands/export.d.ts +28 -0
- package/cli/dist/commands/export.d.ts.map +1 -0
- package/cli/dist/commands/export.js +135 -0
- package/cli/dist/commands/export.js.map +1 -0
- package/cli/dist/commands/import.d.ts +23 -0
- package/cli/dist/commands/import.d.ts.map +1 -0
- package/cli/dist/commands/import.js +118 -0
- package/cli/dist/commands/import.js.map +1 -0
- package/cli/dist/commands/prompt.d.ts +45 -0
- package/cli/dist/commands/prompt.d.ts.map +1 -0
- package/cli/dist/commands/prompt.js +223 -0
- package/cli/dist/commands/prompt.js.map +1 -0
- package/cli/dist/commands/spec.d.ts +57 -0
- package/cli/dist/commands/spec.d.ts.map +1 -0
- package/cli/dist/commands/spec.js +279 -0
- package/cli/dist/commands/spec.js.map +1 -0
- package/cli/dist/commands/stats.d.ts +18 -0
- package/cli/dist/commands/stats.d.ts.map +1 -0
- package/cli/dist/commands/stats.js +85 -0
- package/cli/dist/commands/stats.js.map +1 -0
- package/cli/dist/commands/task.d.ts +65 -0
- package/cli/dist/commands/task.d.ts.map +1 -0
- package/cli/dist/commands/task.js +282 -0
- package/cli/dist/commands/task.js.map +1 -0
- package/cli/dist/commands/template.d.ts +17 -0
- package/cli/dist/commands/template.d.ts.map +1 -0
- package/cli/dist/commands/template.js +55 -0
- package/cli/dist/commands/template.js.map +1 -0
- package/cli/dist/utils/agent-config.d.ts +129 -0
- package/cli/dist/utils/agent-config.d.ts.map +1 -0
- package/cli/dist/utils/agent-config.js +297 -0
- package/cli/dist/utils/agent-config.js.map +1 -0
- package/cli/dist/utils/auto-sync.js +19 -19
- package/cli/dist/utils/beads-graph.d.ts +17 -0
- package/cli/dist/utils/beads-graph.d.ts.map +1 -0
- package/cli/dist/utils/beads-graph.js +150 -0
- package/cli/dist/utils/beads-graph.js.map +1 -0
- package/cli/dist/utils/beads-integration.d.ts +112 -0
- package/cli/dist/utils/beads-integration.d.ts.map +1 -0
- package/cli/dist/utils/beads-integration.js +312 -0
- package/cli/dist/utils/beads-integration.js.map +1 -0
- package/cli/dist/utils/beads-reporter.d.ts +17 -0
- package/cli/dist/utils/beads-reporter.d.ts.map +1 -0
- package/cli/dist/utils/beads-reporter.js +160 -0
- package/cli/dist/utils/beads-reporter.js.map +1 -0
- package/cli/dist/utils/cache-manager.d.ts +55 -0
- package/cli/dist/utils/cache-manager.d.ts.map +1 -0
- package/cli/dist/utils/cache-manager.js +150 -0
- package/cli/dist/utils/cache-manager.js.map +1 -0
- package/cli/dist/utils/change-manager.d.ts +70 -0
- package/cli/dist/utils/change-manager.d.ts.map +1 -0
- package/cli/dist/utils/change-manager.js +412 -0
- package/cli/dist/utils/change-manager.js.map +1 -0
- package/cli/dist/utils/config-manager-enhanced.d.ts +66 -0
- package/cli/dist/utils/config-manager-enhanced.d.ts.map +1 -0
- package/cli/dist/utils/config-manager-enhanced.js +77 -0
- package/cli/dist/utils/config-manager-enhanced.js.map +1 -0
- package/cli/dist/utils/context-manager.d.ts +96 -0
- package/cli/dist/utils/context-manager.d.ts.map +1 -0
- package/cli/dist/utils/context-manager.js +258 -0
- package/cli/dist/utils/context-manager.js.map +1 -0
- package/cli/dist/utils/diff-engine.d.ts +78 -0
- package/cli/dist/utils/diff-engine.d.ts.map +1 -0
- package/cli/dist/utils/diff-engine.js +233 -0
- package/cli/dist/utils/diff-engine.js.map +1 -0
- package/cli/dist/utils/export-system.d.ts +101 -0
- package/cli/dist/utils/export-system.d.ts.map +1 -0
- package/cli/dist/utils/export-system.js +289 -0
- package/cli/dist/utils/export-system.js.map +1 -0
- package/cli/dist/utils/health-checker.d.ts +66 -0
- package/cli/dist/utils/health-checker.d.ts.map +1 -0
- package/cli/dist/utils/health-checker.js +285 -0
- package/cli/dist/utils/health-checker.js.map +1 -0
- package/cli/dist/utils/import-system.d.ts +74 -0
- package/cli/dist/utils/import-system.d.ts.map +1 -0
- package/cli/dist/utils/import-system.js +317 -0
- package/cli/dist/utils/import-system.js.map +1 -0
- package/cli/dist/utils/module-cloner.d.ts +40 -0
- package/cli/dist/utils/module-cloner.d.ts.map +1 -0
- package/cli/dist/utils/module-cloner.js +136 -0
- package/cli/dist/utils/module-cloner.js.map +1 -0
- package/cli/dist/utils/prompt-manager.d.ts +90 -0
- package/cli/dist/utils/prompt-manager.d.ts.map +1 -0
- package/cli/dist/utils/prompt-manager.js +302 -0
- package/cli/dist/utils/prompt-manager.js.map +1 -0
- package/cli/dist/utils/spec-manager.d.ts +65 -0
- package/cli/dist/utils/spec-manager.d.ts.map +1 -0
- package/cli/dist/utils/spec-manager.js +329 -0
- package/cli/dist/utils/spec-manager.js.map +1 -0
- package/cli/dist/utils/stats-collector.d.ts +74 -0
- package/cli/dist/utils/stats-collector.d.ts.map +1 -0
- package/cli/dist/utils/stats-collector.js +164 -0
- package/cli/dist/utils/stats-collector.js.map +1 -0
- package/cli/dist/utils/template-engine.d.ts +47 -0
- package/cli/dist/utils/template-engine.d.ts.map +1 -0
- package/cli/dist/utils/template-engine.js +204 -0
- package/cli/dist/utils/template-engine.js.map +1 -0
- package/package.json +12 -3
- package/augment-extensions/workflows/openspec/README.md +0 -96
- package/augment-extensions/workflows/openspec/examples/complete-change-example.md +0 -244
- package/augment-extensions/workflows/openspec/module.json +0 -54
- package/augment-extensions/workflows/openspec/rules/best-practices.md +0 -272
- package/augment-extensions/workflows/openspec/rules/manual-setup.md +0 -231
- package/augment-extensions/workflows/openspec/rules/spec-format.md +0 -236
- package/augment-extensions/workflows/openspec/rules/workflow.md +0 -214
- package/cli/dist/utils/__tests__/adr-validator.example.d.ts +0 -6
- package/cli/dist/utils/__tests__/adr-validator.example.d.ts.map +0 -1
- package/cli/dist/utils/__tests__/adr-validator.example.js +0 -148
- package/cli/dist/utils/__tests__/adr-validator.example.js.map +0 -1
- package/cli/dist/utils/adr-validator.d.ts +0 -65
- package/cli/dist/utils/adr-validator.d.ts.map +0 -1
- package/cli/dist/utils/adr-validator.js +0 -203
- package/cli/dist/utils/adr-validator.js.map +0 -1
|
@@ -1,162 +1,162 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ADR Validation Module
|
|
3
|
-
* Implements validation rules from validation-rules.md
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface ADR {
|
|
7
|
-
id: string;
|
|
8
|
-
title: string;
|
|
9
|
-
status: string;
|
|
10
|
-
date: string;
|
|
11
|
-
deciders: string[];
|
|
12
|
-
tags?: string[];
|
|
13
|
-
supersedes?: string[];
|
|
14
|
-
superseded_by?: string;
|
|
15
|
-
related_decisions?: string[];
|
|
16
|
-
related_specs?: string[];
|
|
17
|
-
related_tasks?: string[];
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface ValidationResult {
|
|
21
|
-
valid: boolean;
|
|
22
|
-
errors?: string[];
|
|
23
|
-
warnings?: string[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const VALID_STATUSES = ['draft', 'proposed', 'approved', 'implemented', 'maintained', 'superseded', 'sunset'];
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Validate ISO 8601 date format (YYYY-MM-DD)
|
|
30
|
-
*/
|
|
31
|
-
export function isValidISO8601(date: string): boolean {
|
|
32
|
-
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const [year, month, day] = date.split('-').map(Number);
|
|
37
|
-
|
|
38
|
-
// Check basic ranges
|
|
39
|
-
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Create date in UTC to avoid timezone issues
|
|
44
|
-
const d = new Date(Date.UTC(year, month - 1, day));
|
|
45
|
-
|
|
46
|
-
if (isNaN(d.getTime())) {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Verify the date components match (handles invalid dates like 2024-02-30)
|
|
51
|
-
return d.getUTCFullYear() === year &&
|
|
52
|
-
d.getUTCMonth() === month - 1 &&
|
|
53
|
-
d.getUTCDate() === day;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Validate required metadata fields
|
|
58
|
-
*/
|
|
59
|
-
export function validateMetadata(adr: ADR): ValidationResult {
|
|
60
|
-
const errors: string[] = [];
|
|
61
|
-
|
|
62
|
-
// ID validation
|
|
63
|
-
if (!adr.id) {
|
|
64
|
-
errors.push("Missing required field: id");
|
|
65
|
-
} else if (!/^adr-\d{4}$/.test(adr.id)) {
|
|
66
|
-
errors.push("Invalid ID format. Must be adr-NNNN (e.g., adr-0001)");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Title validation
|
|
70
|
-
if (!adr.title) {
|
|
71
|
-
errors.push("Missing required field: title");
|
|
72
|
-
} else if (adr.title.length < 10 || adr.title.length > 100) {
|
|
73
|
-
errors.push("Title must be 10-100 characters");
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Status validation
|
|
77
|
-
if (!adr.status) {
|
|
78
|
-
errors.push("Missing required field: status");
|
|
79
|
-
} else if (!VALID_STATUSES.includes(adr.status)) {
|
|
80
|
-
errors.push(`Invalid status. Must be one of: ${VALID_STATUSES.join(', ')}`);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Date validation
|
|
84
|
-
if (!adr.date) {
|
|
85
|
-
errors.push("Missing required field: date");
|
|
86
|
-
} else if (!isValidISO8601(adr.date)) {
|
|
87
|
-
errors.push("Invalid date format. Must be ISO 8601 (YYYY-MM-DD)");
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Deciders validation
|
|
91
|
-
if (!adr.deciders || adr.deciders.length === 0) {
|
|
92
|
-
errors.push("At least one decider must be specified");
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return { valid: errors.length === 0, errors };
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Validate optional fields
|
|
100
|
-
*/
|
|
101
|
-
export function validateOptionalFields(adr: ADR): ValidationResult {
|
|
102
|
-
const warnings: string[] = [];
|
|
103
|
-
|
|
104
|
-
// Tags validation
|
|
105
|
-
if (adr.tags && !Array.isArray(adr.tags)) {
|
|
106
|
-
warnings.push("Tags must be an array");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Supersedes validation
|
|
110
|
-
if (adr.supersedes) {
|
|
111
|
-
if (!Array.isArray(adr.supersedes)) {
|
|
112
|
-
warnings.push("Supersedes must be an array");
|
|
113
|
-
} else {
|
|
114
|
-
adr.supersedes.forEach(id => {
|
|
115
|
-
if (!/^adr-\d{4}$/.test(id)) {
|
|
116
|
-
warnings.push(`Invalid ADR ID in supersedes: ${id}`);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Superseded_by validation
|
|
123
|
-
if (adr.superseded_by && !/^adr-\d{4}$/.test(adr.superseded_by)) {
|
|
124
|
-
warnings.push(`Invalid ADR ID in superseded_by: ${adr.superseded_by}`);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return { valid: warnings.length === 0, warnings };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Validate ADR references (related_decisions, supersedes, etc.)
|
|
132
|
-
*/
|
|
133
|
-
export function validateADRReferences(adr: ADR, allADRs: ADR[]): ValidationResult {
|
|
134
|
-
const warnings: string[] = [];
|
|
135
|
-
const adrIds = new Set(allADRs.map(a => a.id));
|
|
136
|
-
|
|
137
|
-
// Validate supersedes references
|
|
138
|
-
if (adr.supersedes) {
|
|
139
|
-
adr.supersedes.forEach(id => {
|
|
140
|
-
if (!adrIds.has(id)) {
|
|
141
|
-
warnings.push(`Referenced ADR does not exist: ${id}`);
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Validate superseded_by reference
|
|
147
|
-
if (adr.superseded_by && !adrIds.has(adr.superseded_by)) {
|
|
148
|
-
warnings.push(`Referenced ADR does not exist: ${adr.superseded_by}`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Validate related_decisions
|
|
152
|
-
if (adr.related_decisions) {
|
|
153
|
-
adr.related_decisions.forEach(id => {
|
|
154
|
-
if (!adrIds.has(id)) {
|
|
155
|
-
warnings.push(`Related ADR does not exist: ${id}`);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return { valid: warnings.length === 0, warnings };
|
|
161
|
-
}
|
|
162
|
-
|
|
1
|
+
/**
|
|
2
|
+
* ADR Validation Module
|
|
3
|
+
* Implements validation rules from validation-rules.md
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ADR {
|
|
7
|
+
id: string;
|
|
8
|
+
title: string;
|
|
9
|
+
status: string;
|
|
10
|
+
date: string;
|
|
11
|
+
deciders: string[];
|
|
12
|
+
tags?: string[];
|
|
13
|
+
supersedes?: string[];
|
|
14
|
+
superseded_by?: string;
|
|
15
|
+
related_decisions?: string[];
|
|
16
|
+
related_specs?: string[];
|
|
17
|
+
related_tasks?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ValidationResult {
|
|
21
|
+
valid: boolean;
|
|
22
|
+
errors?: string[];
|
|
23
|
+
warnings?: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const VALID_STATUSES = ['draft', 'proposed', 'approved', 'implemented', 'maintained', 'superseded', 'sunset'];
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Validate ISO 8601 date format (YYYY-MM-DD)
|
|
30
|
+
*/
|
|
31
|
+
export function isValidISO8601(date: string): boolean {
|
|
32
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const [year, month, day] = date.split('-').map(Number);
|
|
37
|
+
|
|
38
|
+
// Check basic ranges
|
|
39
|
+
if (month < 1 || month > 12 || day < 1 || day > 31) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Create date in UTC to avoid timezone issues
|
|
44
|
+
const d = new Date(Date.UTC(year, month - 1, day));
|
|
45
|
+
|
|
46
|
+
if (isNaN(d.getTime())) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Verify the date components match (handles invalid dates like 2024-02-30)
|
|
51
|
+
return d.getUTCFullYear() === year &&
|
|
52
|
+
d.getUTCMonth() === month - 1 &&
|
|
53
|
+
d.getUTCDate() === day;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Validate required metadata fields
|
|
58
|
+
*/
|
|
59
|
+
export function validateMetadata(adr: ADR): ValidationResult {
|
|
60
|
+
const errors: string[] = [];
|
|
61
|
+
|
|
62
|
+
// ID validation
|
|
63
|
+
if (!adr.id) {
|
|
64
|
+
errors.push("Missing required field: id");
|
|
65
|
+
} else if (!/^adr-\d{4}$/.test(adr.id)) {
|
|
66
|
+
errors.push("Invalid ID format. Must be adr-NNNN (e.g., adr-0001)");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Title validation
|
|
70
|
+
if (!adr.title) {
|
|
71
|
+
errors.push("Missing required field: title");
|
|
72
|
+
} else if (adr.title.length < 10 || adr.title.length > 100) {
|
|
73
|
+
errors.push("Title must be 10-100 characters");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Status validation
|
|
77
|
+
if (!adr.status) {
|
|
78
|
+
errors.push("Missing required field: status");
|
|
79
|
+
} else if (!VALID_STATUSES.includes(adr.status)) {
|
|
80
|
+
errors.push(`Invalid status. Must be one of: ${VALID_STATUSES.join(', ')}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Date validation
|
|
84
|
+
if (!adr.date) {
|
|
85
|
+
errors.push("Missing required field: date");
|
|
86
|
+
} else if (!isValidISO8601(adr.date)) {
|
|
87
|
+
errors.push("Invalid date format. Must be ISO 8601 (YYYY-MM-DD)");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Deciders validation
|
|
91
|
+
if (!adr.deciders || adr.deciders.length === 0) {
|
|
92
|
+
errors.push("At least one decider must be specified");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return { valid: errors.length === 0, errors };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Validate optional fields
|
|
100
|
+
*/
|
|
101
|
+
export function validateOptionalFields(adr: ADR): ValidationResult {
|
|
102
|
+
const warnings: string[] = [];
|
|
103
|
+
|
|
104
|
+
// Tags validation
|
|
105
|
+
if (adr.tags && !Array.isArray(adr.tags)) {
|
|
106
|
+
warnings.push("Tags must be an array");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Supersedes validation
|
|
110
|
+
if (adr.supersedes) {
|
|
111
|
+
if (!Array.isArray(adr.supersedes)) {
|
|
112
|
+
warnings.push("Supersedes must be an array");
|
|
113
|
+
} else {
|
|
114
|
+
adr.supersedes.forEach(id => {
|
|
115
|
+
if (!/^adr-\d{4}$/.test(id)) {
|
|
116
|
+
warnings.push(`Invalid ADR ID in supersedes: ${id}`);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Superseded_by validation
|
|
123
|
+
if (adr.superseded_by && !/^adr-\d{4}$/.test(adr.superseded_by)) {
|
|
124
|
+
warnings.push(`Invalid ADR ID in superseded_by: ${adr.superseded_by}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return { valid: warnings.length === 0, warnings };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Validate ADR references (related_decisions, supersedes, etc.)
|
|
132
|
+
*/
|
|
133
|
+
export function validateADRReferences(adr: ADR, allADRs: ADR[]): ValidationResult {
|
|
134
|
+
const warnings: string[] = [];
|
|
135
|
+
const adrIds = new Set(allADRs.map(a => a.id));
|
|
136
|
+
|
|
137
|
+
// Validate supersedes references
|
|
138
|
+
if (adr.supersedes) {
|
|
139
|
+
adr.supersedes.forEach(id => {
|
|
140
|
+
if (!adrIds.has(id)) {
|
|
141
|
+
warnings.push(`Referenced ADR does not exist: ${id}`);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Validate superseded_by reference
|
|
147
|
+
if (adr.superseded_by && !adrIds.has(adr.superseded_by)) {
|
|
148
|
+
warnings.push(`Referenced ADR does not exist: ${adr.superseded_by}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Validate related_decisions
|
|
152
|
+
if (adr.related_decisions) {
|
|
153
|
+
adr.related_decisions.forEach(id => {
|
|
154
|
+
if (!adrIds.has(id)) {
|
|
155
|
+
warnings.push(`Related ADR does not exist: ${id}`);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return { valid: warnings.length === 0, warnings };
|
|
161
|
+
}
|
|
162
|
+
|