@transitrix/diagrams 1.3.0 → 1.5.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/dist/__tests__/yaml-normalize.test.js +9 -9
- package/dist/activities/__tests__/gantt.test.js +39 -0
- package/dist/activities/__tests__/validate.test.js +77 -74
- package/dist/activities/validate.js +5 -12
- package/dist/activity-card/__tests__/example.test.js +2 -2
- package/dist/activity-card/__tests__/validate.test.js +29 -18
- package/dist/activity-card/validate.js +3 -10
- package/dist/actor/__tests__/validate.test.js +6 -0
- package/dist/actor/types.d.ts +1 -1
- package/dist/actor/types.js +2 -0
- package/dist/applications/types.d.ts +7 -0
- package/dist/applications/validate.js +18 -0
- package/dist/blocks/__tests__/layout.test.js +1 -1
- package/dist/blocks/layout.js +1 -1
- package/dist/business-service/__tests__/validate.test.d.ts +1 -0
- package/dist/business-service/__tests__/validate.test.js +135 -0
- package/dist/business-service/index.d.ts +3 -0
- package/dist/business-service/index.js +2 -0
- package/dist/business-service/types.d.ts +20 -0
- package/dist/business-service/types.js +3 -0
- package/dist/business-service/validate.d.ts +2 -0
- package/dist/business-service/validate.js +74 -0
- package/dist/fgca/__tests__/parse-canonical.test.js +10 -10
- package/dist/fgca/__tests__/resolver.test.js +7 -7
- package/dist/fgca/__tests__/validate.test.js +11 -11
- package/dist/fgca/parse-canonical.js +7 -11
- package/dist/fgca/resolver.d.ts +2 -2
- package/dist/fgca/resolver.js +5 -5
- package/dist/fgca/validate.js +4 -13
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/integration/__tests__/validate.test.d.ts +1 -0
- package/dist/integration/__tests__/validate.test.js +169 -0
- package/dist/integration/index.d.ts +2 -0
- package/dist/integration/index.js +1 -0
- package/dist/integration/types.d.ts +27 -0
- package/dist/integration/types.js +5 -0
- package/dist/integration/validate.d.ts +2 -0
- package/dist/integration/validate.js +94 -0
- package/dist/location/__tests__/validate.test.d.ts +1 -0
- package/dist/location/__tests__/validate.test.js +107 -0
- package/dist/location/index.d.ts +3 -0
- package/dist/location/index.js +2 -0
- package/dist/location/types.d.ts +20 -0
- package/dist/location/types.js +3 -0
- package/dist/location/validate.d.ts +2 -0
- package/dist/location/validate.js +63 -0
- package/dist/node/__tests__/validate.test.d.ts +1 -0
- package/dist/node/__tests__/validate.test.js +100 -0
- package/dist/node/index.d.ts +2 -0
- package/dist/node/index.js +1 -0
- package/dist/node/types.d.ts +18 -0
- package/dist/node/types.js +3 -0
- package/dist/node/validate.d.ts +2 -0
- package/dist/node/validate.js +53 -0
- package/dist/repo-validate/__tests__/validate-repo.test.js +444 -0
- package/dist/repo-validate/validate-repo.js +224 -10
- package/dist/technology-service/__tests__/validate.test.d.ts +1 -0
- package/dist/technology-service/__tests__/validate.test.js +121 -0
- package/dist/technology-service/index.d.ts +2 -0
- package/dist/technology-service/index.js +1 -0
- package/dist/technology-service/types.d.ts +18 -0
- package/dist/technology-service/types.js +3 -0
- package/dist/technology-service/validate.d.ts +2 -0
- package/dist/technology-service/validate.js +64 -0
- package/dist/webview/__tests__/entry-notations.test.js +2 -4
- package/dist/webview/__tests__/render-activities.test.d.ts +1 -0
- package/dist/webview/__tests__/render-activities.test.js +91 -0
- package/dist/webview/__tests__/render-blocks.test.d.ts +1 -0
- package/dist/webview/__tests__/render-blocks.test.js +178 -0
- package/dist/webview/entry.d.ts +1 -1
- package/dist/webview/entry.js +8 -15
- package/dist/webview/notation-style.d.ts +11 -0
- package/dist/webview/notation-style.js +11 -0
- package/dist/webview/render-activities.d.ts +12 -0
- package/dist/webview/render-activities.js +9 -3
- package/dist/webview/render-blocks.js +102 -19
- package/dist/webview/render-goals.js +2 -1
- package/package.json +1 -1
- package/src/__tests__/yaml-normalize.test.ts +11 -11
- package/src/activities/__tests__/gantt.test.ts +45 -0
- package/src/activities/__tests__/validate.test.ts +77 -74
- package/src/activities/validate.ts +5 -12
- package/src/activity-card/__tests__/example.test.ts +2 -2
- package/src/activity-card/__tests__/validate.test.ts +30 -18
- package/src/activity-card/validate.ts +3 -9
- package/src/actor/__tests__/validate.test.ts +8 -0
- package/src/actor/types.ts +2 -0
- package/src/applications/types.ts +8 -0
- package/src/applications/validate.ts +20 -0
- package/src/blocks/__tests__/layout.test.ts +1 -1
- package/src/blocks/layout.ts +1 -1
- package/src/business-service/__tests__/validate.test.ts +160 -0
- package/src/business-service/index.ts +3 -0
- package/src/business-service/types.ts +29 -0
- package/src/business-service/validate.ts +82 -0
- package/src/fgca/__tests__/parse-canonical.test.ts +10 -10
- package/src/fgca/__tests__/resolver.test.ts +7 -7
- package/src/fgca/__tests__/validate.test.ts +11 -11
- package/src/fgca/parse-canonical.ts +7 -11
- package/src/fgca/resolver.ts +5 -5
- package/src/fgca/validate.ts +4 -12
- package/src/index.ts +5 -0
- package/src/integration/__tests__/validate.test.ts +203 -0
- package/src/integration/index.ts +2 -0
- package/src/integration/types.ts +38 -0
- package/src/integration/validate.ts +104 -0
- package/src/location/__tests__/validate.test.ts +127 -0
- package/src/location/index.ts +3 -0
- package/src/location/types.ts +29 -0
- package/src/location/validate.ts +70 -0
- package/src/node/__tests__/validate.test.ts +118 -0
- package/src/node/index.ts +2 -0
- package/src/node/types.ts +27 -0
- package/src/node/validate.ts +59 -0
- package/src/repo-validate/__tests__/validate-repo.test.ts +550 -0
- package/src/repo-validate/validate-repo.ts +233 -10
- package/src/technology-service/__tests__/validate.test.ts +143 -0
- package/src/technology-service/index.ts +2 -0
- package/src/technology-service/types.ts +27 -0
- package/src/technology-service/validate.ts +71 -0
- package/src/webview/__tests__/entry-notations.test.ts +2 -4
- package/src/webview/__tests__/render-activities.test.ts +100 -0
- package/src/webview/__tests__/render-blocks.test.ts +209 -0
- package/src/webview/entry.ts +10 -19
- package/src/webview/notation-style.ts +12 -0
- package/src/webview/render-activities.ts +29 -4
- package/src/webview/render-blocks.ts +106 -21
- package/src/webview/render-goals.ts +2 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// LOCATION validator — methodology notations/elements/21-locations.md §6.
|
|
2
|
+
//
|
|
3
|
+
// Implements LOC-001..003. The shared HDR-/LIFECYCLE- rules are
|
|
4
|
+
// cross-cutting concerns (CONTRACT.md §8) and out of scope for the
|
|
5
|
+
// single-artefact validator.
|
|
6
|
+
import { isCanonicalIdOfType } from '../typed-id.js';
|
|
7
|
+
import { LOCATION_TYPES } from './types.js';
|
|
8
|
+
const REQUIRED_STRING_FIELDS = [
|
|
9
|
+
'name', 'admitted_at', 'admitted_by', 'valid_from',
|
|
10
|
+
];
|
|
11
|
+
const TYPES = LOCATION_TYPES;
|
|
12
|
+
export function validateLocation(input) {
|
|
13
|
+
const errors = [];
|
|
14
|
+
const warnings = [];
|
|
15
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
16
|
+
errors.push({ code: 'LOC-001', message: 'Location must be a YAML mapping.' });
|
|
17
|
+
return { valid: false, errors, warnings };
|
|
18
|
+
}
|
|
19
|
+
const a = input;
|
|
20
|
+
// LOC-001 — id grammar + notation tag + envelope.
|
|
21
|
+
if (!isCanonicalIdOfType(a.id, 'LOCATION')) {
|
|
22
|
+
errors.push({ code: 'LOC-001', message: `id "${String(a.id)}" must match LOCATION-[<middle>-]<INTEGER>.`, path: 'id' });
|
|
23
|
+
}
|
|
24
|
+
if (a.notation !== 'location') {
|
|
25
|
+
errors.push({ code: 'LOC-001', message: 'notation must be the fixed value "location".', path: 'notation' });
|
|
26
|
+
}
|
|
27
|
+
if (a.zone !== undefined && a.zone !== 'canon') {
|
|
28
|
+
errors.push({ code: 'LOC-001', message: 'zone must be "canon" for a LOCATION.', path: 'zone' });
|
|
29
|
+
}
|
|
30
|
+
else if (a.zone === undefined) {
|
|
31
|
+
errors.push({ code: 'LOC-001', message: 'zone is required.', path: 'zone' });
|
|
32
|
+
}
|
|
33
|
+
for (const field of REQUIRED_STRING_FIELDS) {
|
|
34
|
+
const v = a[field];
|
|
35
|
+
if (typeof v !== 'string' || v.trim() === '') {
|
|
36
|
+
errors.push({ code: 'LOC-001', message: `${field} is required.`, path: field });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (a.gate_checks === null || typeof a.gate_checks !== 'object') {
|
|
40
|
+
errors.push({ code: 'LOC-001', message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
|
|
41
|
+
}
|
|
42
|
+
if (!('valid_to' in a) || !(typeof a.valid_to === 'string' || a.valid_to === null)) {
|
|
43
|
+
errors.push({ code: 'LOC-001', message: 'valid_to is required (an ISO date string or null).', path: 'valid_to' });
|
|
44
|
+
}
|
|
45
|
+
if (typeof a.type !== 'string' || a.type.trim() === '') {
|
|
46
|
+
errors.push({ code: 'LOC-001', message: 'type is required.', path: 'type' });
|
|
47
|
+
}
|
|
48
|
+
else if (!TYPES.includes(a.type)) {
|
|
49
|
+
// LOC-002 — type enum.
|
|
50
|
+
errors.push({ code: 'LOC-002', message: `type "${a.type}" must be one of ${TYPES.join(', ')}.`, path: 'type' });
|
|
51
|
+
}
|
|
52
|
+
// LOC-003 — parent must resolve to a LOCATION when present.
|
|
53
|
+
if ('parent' in a && a.parent !== undefined && a.parent !== null) {
|
|
54
|
+
if (typeof a.parent !== 'string' || !isCanonicalIdOfType(a.parent, 'LOCATION')) {
|
|
55
|
+
errors.push({
|
|
56
|
+
code: 'LOC-003',
|
|
57
|
+
message: `parent "${String(a.parent)}" must be a canonical LOCATION-… id.`,
|
|
58
|
+
path: 'parent',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { validateNode } from '../validate.js';
|
|
3
|
+
function valid() {
|
|
4
|
+
return {
|
|
5
|
+
notation: 'node',
|
|
6
|
+
id: 'NODE-KAFKA-HOST-1',
|
|
7
|
+
name: 'Kafka Cluster Host',
|
|
8
|
+
type: 'cloud_instance',
|
|
9
|
+
description: 'AWS EC2 auto-scaling group hosting the Kafka broker cluster.',
|
|
10
|
+
provider: 'AWS',
|
|
11
|
+
region: 'eu-central-1',
|
|
12
|
+
zone: 'canon',
|
|
13
|
+
admitted_at: '2026-06-28',
|
|
14
|
+
admitted_by: 'v.korobeinikov',
|
|
15
|
+
gate_checks: { uniqueness: 'pass', consistency: 'pass', completeness: 'pass' },
|
|
16
|
+
valid_from: '2024-01-01',
|
|
17
|
+
valid_to: null,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const codes = (input) => validateNode(input).errors.map(e => e.code);
|
|
21
|
+
describe('validateNode — positive', () => {
|
|
22
|
+
it('accepts a well-formed cloud_instance node with all optional fields', () => {
|
|
23
|
+
const r = validateNode(valid());
|
|
24
|
+
expect(r.valid, JSON.stringify(r.errors)).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
it('accepts a server node with no optional fields', () => {
|
|
27
|
+
const a = valid();
|
|
28
|
+
a.id = 'NODE-DB-1';
|
|
29
|
+
a.name = 'Primary DB Server';
|
|
30
|
+
a.type = 'server';
|
|
31
|
+
delete a.description;
|
|
32
|
+
delete a.provider;
|
|
33
|
+
delete a.region;
|
|
34
|
+
expect(validateNode(a).valid).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
it('accepts all five type values', () => {
|
|
37
|
+
for (const t of ['server', 'cloud_instance', 'container_platform', 'database_server', 'network_device']) {
|
|
38
|
+
expect(validateNode({ ...valid(), type: t }).valid).toBe(true);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
it('accepts valid_to as a date string', () => {
|
|
42
|
+
expect(validateNode({ ...valid(), valid_to: '2026-12-31' }).valid).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('validateNode — NOD-001 (shape / id grammar)', () => {
|
|
46
|
+
it('flags a non-object input', () => {
|
|
47
|
+
expect(codes(null)).toEqual(['NOD-001']);
|
|
48
|
+
expect(codes('string')).toEqual(['NOD-001']);
|
|
49
|
+
});
|
|
50
|
+
it('flags an id that violates the grammar', () => {
|
|
51
|
+
expect(codes({ ...valid(), id: 'NODE-001' })).toContain('NOD-001');
|
|
52
|
+
expect(codes({ ...valid(), id: 'NOD-1' })).toContain('NOD-001');
|
|
53
|
+
expect(codes({ ...valid(), id: 'node-kafka-1' })).toContain('NOD-001');
|
|
54
|
+
});
|
|
55
|
+
it('flags a wrong notation tag', () => {
|
|
56
|
+
expect(codes({ ...valid(), notation: 'nodes' })).toContain('NOD-001');
|
|
57
|
+
expect(codes({ ...valid(), notation: 'infrastructure' })).toContain('NOD-001');
|
|
58
|
+
});
|
|
59
|
+
it('flags a non-canon zone', () => {
|
|
60
|
+
expect(codes({ ...valid(), zone: 'sandbox' })).toContain('NOD-001');
|
|
61
|
+
});
|
|
62
|
+
it('flags a missing zone', () => {
|
|
63
|
+
const a = valid();
|
|
64
|
+
delete a.zone;
|
|
65
|
+
expect(codes(a)).toContain('NOD-001');
|
|
66
|
+
});
|
|
67
|
+
it('flags a missing name', () => {
|
|
68
|
+
const a = valid();
|
|
69
|
+
delete a.name;
|
|
70
|
+
expect(codes(a)).toContain('NOD-001');
|
|
71
|
+
});
|
|
72
|
+
it('flags a missing valid_to key', () => {
|
|
73
|
+
const a = valid();
|
|
74
|
+
delete a.valid_to;
|
|
75
|
+
expect(codes(a)).toContain('NOD-001');
|
|
76
|
+
});
|
|
77
|
+
it('flags missing gate_checks', () => {
|
|
78
|
+
const a = valid();
|
|
79
|
+
delete a.gate_checks;
|
|
80
|
+
expect(codes(a)).toContain('NOD-001');
|
|
81
|
+
});
|
|
82
|
+
it('flags a missing type', () => {
|
|
83
|
+
const a = valid();
|
|
84
|
+
delete a.type;
|
|
85
|
+
expect(codes(a)).toContain('NOD-001');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('validateNode — NOD-002 (type enum)', () => {
|
|
89
|
+
it('flags a type outside the allowed enum', () => {
|
|
90
|
+
expect(codes({ ...valid(), type: 'virtual_machine' })).toContain('NOD-002');
|
|
91
|
+
expect(codes({ ...valid(), type: 'storage' })).toContain('NOD-002');
|
|
92
|
+
expect(codes({ ...valid(), type: 'cluster' })).toContain('NOD-002');
|
|
93
|
+
});
|
|
94
|
+
it('does not flag a missing type with NOD-002 (NOD-001 fires instead)', () => {
|
|
95
|
+
const a = valid();
|
|
96
|
+
delete a.type;
|
|
97
|
+
expect(codes(a)).not.toContain('NOD-002');
|
|
98
|
+
expect(codes(a)).toContain('NOD-001');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { validateNode } from './validate.js';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { GateChecks } from '../requirement/types.js';
|
|
2
|
+
export declare const NODE_TYPES: readonly ["server", "cloud_instance", "container_platform", "database_server", "network_device"];
|
|
3
|
+
export type NodeType = typeof NODE_TYPES[number];
|
|
4
|
+
export interface Node {
|
|
5
|
+
notation: 'node';
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
type: NodeType;
|
|
9
|
+
description?: string;
|
|
10
|
+
provider?: string;
|
|
11
|
+
region?: string;
|
|
12
|
+
zone: 'canon';
|
|
13
|
+
admitted_at: string;
|
|
14
|
+
admitted_by: string;
|
|
15
|
+
gate_checks: GateChecks;
|
|
16
|
+
valid_from: string;
|
|
17
|
+
valid_to: string | null;
|
|
18
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// NODE validator — methodology notations/elements/25-nodes.md §5.
|
|
2
|
+
//
|
|
3
|
+
// Implements NOD-001, NOD-002. The shared HDR-/LIFECYCLE- rules are
|
|
4
|
+
// cross-cutting concerns (CONTRACT.md §8) and out of scope for the
|
|
5
|
+
// single-artefact validator.
|
|
6
|
+
import { isCanonicalIdOfType } from '../typed-id.js';
|
|
7
|
+
import { NODE_TYPES } from './types.js';
|
|
8
|
+
const REQUIRED_STRING_FIELDS = [
|
|
9
|
+
'name', 'admitted_at', 'admitted_by', 'valid_from',
|
|
10
|
+
];
|
|
11
|
+
const TYPES = NODE_TYPES;
|
|
12
|
+
export function validateNode(input) {
|
|
13
|
+
const errors = [];
|
|
14
|
+
const warnings = [];
|
|
15
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
16
|
+
errors.push({ code: 'NOD-001', message: 'Node must be a YAML mapping.' });
|
|
17
|
+
return { valid: false, errors, warnings };
|
|
18
|
+
}
|
|
19
|
+
const a = input;
|
|
20
|
+
// NOD-001 — id grammar + notation tag + envelope.
|
|
21
|
+
if (!isCanonicalIdOfType(a.id, 'NODE')) {
|
|
22
|
+
errors.push({ code: 'NOD-001', message: `id "${String(a.id)}" must match NODE-[<middle>-]<INTEGER>.`, path: 'id' });
|
|
23
|
+
}
|
|
24
|
+
if (a.notation !== 'node') {
|
|
25
|
+
errors.push({ code: 'NOD-001', message: 'notation must be the fixed value "node".', path: 'notation' });
|
|
26
|
+
}
|
|
27
|
+
if (a.zone !== undefined && a.zone !== 'canon') {
|
|
28
|
+
errors.push({ code: 'NOD-001', message: 'zone must be "canon" for a NODE.', path: 'zone' });
|
|
29
|
+
}
|
|
30
|
+
else if (a.zone === undefined) {
|
|
31
|
+
errors.push({ code: 'NOD-001', message: 'zone is required.', path: 'zone' });
|
|
32
|
+
}
|
|
33
|
+
for (const field of REQUIRED_STRING_FIELDS) {
|
|
34
|
+
const v = a[field];
|
|
35
|
+
if (typeof v !== 'string' || v.trim() === '') {
|
|
36
|
+
errors.push({ code: 'NOD-001', message: `${field} is required.`, path: field });
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (a.gate_checks === null || typeof a.gate_checks !== 'object') {
|
|
40
|
+
errors.push({ code: 'NOD-001', message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
|
|
41
|
+
}
|
|
42
|
+
if (!('valid_to' in a) || !(typeof a.valid_to === 'string' || a.valid_to === null)) {
|
|
43
|
+
errors.push({ code: 'NOD-001', message: 'valid_to is required (an ISO date string or null).', path: 'valid_to' });
|
|
44
|
+
}
|
|
45
|
+
if (typeof a.type !== 'string' || a.type.trim() === '') {
|
|
46
|
+
errors.push({ code: 'NOD-001', message: 'type is required.', path: 'type' });
|
|
47
|
+
}
|
|
48
|
+
else if (!TYPES.includes(a.type)) {
|
|
49
|
+
// NOD-002 — type enum.
|
|
50
|
+
errors.push({ code: 'NOD-002', message: `type "${a.type}" must be one of ${TYPES.join(', ')}.`, path: 'type' });
|
|
51
|
+
}
|
|
52
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
53
|
+
}
|