@transitrix/diagrams 1.8.11 → 1.8.18
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/activities/validate.js +9 -1
- package/dist/blocks/index.d.ts +5 -4
- package/dist/blocks/index.js +3 -2
- package/dist/blocks/layout.d.ts +8 -1
- package/dist/blocks/layout.js +57 -0
- package/dist/blocks/templates/index.d.ts +9 -0
- package/dist/blocks/templates/index.js +11 -0
- package/dist/blocks/templates/raci.d.ts +9 -0
- package/dist/blocks/templates/raci.js +24 -0
- package/dist/blocks/types.d.ts +58 -0
- package/dist/blocks/validate.d.ts +31 -1
- package/dist/blocks/validate.js +127 -0
- package/dist/capability-map/validate.js +41 -0
- package/dist/fgca/parse-canonical.js +8 -0
- package/dist/repo-validate/check-element-hygiene.d.ts +8 -0
- package/dist/repo-validate/check-element-hygiene.js +211 -0
- package/dist/repo-validate/check-strategy-chain.d.ts +8 -0
- package/dist/repo-validate/check-strategy-chain.js +491 -0
- package/dist/repo-validate/index.d.ts +2 -1
- package/dist/repo-validate/index.js +1 -0
- package/dist/repo-validate/resolve-model.d.ts +5 -0
- package/dist/repo-validate/resolve-model.js +71 -0
- package/dist/repo-validate/types.d.ts +70 -1
- package/dist/repo-validate/types.js +22 -3
- package/dist/repo-validate/validate-repo.d.ts +14 -3
- package/dist/repo-validate/validate-repo.js +21 -8
- package/dist/webview/render-blocks.d.ts +23 -1
- package/dist/webview/render-blocks.js +100 -2
- package/package.json +1 -1
- package/src/activities/validate.ts +9 -1
- package/src/blocks/index.ts +16 -2
- package/src/blocks/layout.ts +70 -0
- package/src/blocks/templates/index.ts +13 -0
- package/src/blocks/templates/raci.ts +28 -0
- package/src/blocks/types.ts +67 -0
- package/src/blocks/validate.ts +157 -1
- package/src/capability-map/validate.ts +40 -0
- package/src/fgca/parse-canonical.ts +8 -0
- package/src/repo-validate/check-element-hygiene.ts +236 -0
- package/src/repo-validate/check-strategy-chain.ts +528 -0
- package/src/repo-validate/index.ts +2 -1
- package/src/repo-validate/resolve-model.ts +79 -0
- package/src/repo-validate/types.ts +95 -4
- package/src/repo-validate/validate-repo.ts +21 -8
- package/src/webview/render-blocks.ts +159 -2
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// Standalone-element envelope checks — the error-severity subset of DSM's Go
|
|
2
|
+
// `Validate*Element` functions (`api02/internal/importer/{goal_element,
|
|
3
|
+
// action_element}.go` in transitrix-dsm), ported onto the standalone-element
|
|
4
|
+
// repo shape (`canon/elements/**`) that `validate --scope=repo` already
|
|
5
|
+
// loads. Sibling to `check-strategy-chain.ts` (which covers cross-element
|
|
6
|
+
// reference/cycle rules); this file covers the per-element envelope rules —
|
|
7
|
+
// id presence/grammar, name presence, and the ACTION type vocabulary +
|
|
8
|
+
// deprecated-alias warnings.
|
|
9
|
+
//
|
|
10
|
+
// DSM identifies "this file is a GOAL/ACTION element" by its folder location
|
|
11
|
+
// during the import walk (`canon/elements/01_motivation/goals/`,
|
|
12
|
+
// `canon/elements/05_implementation/actions/`) — the validator functions
|
|
13
|
+
// receive an already-typed struct, so a wrong `notation` value on that
|
|
14
|
+
// struct is still checkable (`GOAL-ELEM-001`/the notation branch of
|
|
15
|
+
// `ACTION-001`). This repo-scope model has no such pre-typing
|
|
16
|
+
// (`RepoModelInput.elements` is a flat, untyped list from `canon/elements/**`)
|
|
17
|
+
// — candidate selection here is content-based (the element's own `notation`
|
|
18
|
+
// field), same convention as `check-strategy-chain.ts`'s `collectByNotation`.
|
|
19
|
+
// That means a candidate is by construction already notation-correct, so
|
|
20
|
+
// GOAL-ELEM-001's and ACTION-001's "wrong notation" case can never fire here
|
|
21
|
+
// — tried an id-prefix-based candidate signal instead (matching on a `GOAL-`/
|
|
22
|
+
// `ACTION-` id TYPE prefix regardless of notation) to cover that case, but it
|
|
23
|
+
// produced false positives against this repo's own test fixtures, which
|
|
24
|
+
// reuse a `GOAL-`-prefixed id under a `goals/` path for an unrelated
|
|
25
|
+
// notation as a referential-integrity test double
|
|
26
|
+
// (`validate-repo.test.ts`'s `GOAL-OPS-1`/notation:'assessment' fixture) —
|
|
27
|
+
// there is no reliable, adopter-folder-layout-independent way to tell
|
|
28
|
+
// "misfiled element" from "id reused for something else" without DSM's own
|
|
29
|
+
// folder-based typing. Flagged for a decision, same as `GOALS-008`: skip
|
|
30
|
+
// permanently, or scope a follow-up once the repo-scope model gains
|
|
31
|
+
// path-aware typing.
|
|
32
|
+
//
|
|
33
|
+
// Rule codes are DSM's own — not invented here — so DSM can map a CLI
|
|
34
|
+
// finding straight back onto its import-log taxonomy (`RepoFinding.ruleId`).
|
|
35
|
+
//
|
|
36
|
+
// Ported (error-severity, blocking):
|
|
37
|
+
// GOAL-ELEM-002 — GOAL element `id` is missing.
|
|
38
|
+
// GOAL-ELEM-003 — GOAL element `name` is missing.
|
|
39
|
+
// ACTION-001 — ACTION element `id` or `name` is missing.
|
|
40
|
+
// ACTION-002 — ACTION element `type` is set but not one of
|
|
41
|
+
// Initiative | Strategic Initiative | Programme |
|
|
42
|
+
// Project | Task (Strategic Initiative is an accepted
|
|
43
|
+
// alias for Initiative). DSM treats this as fatal — the
|
|
44
|
+
// type vocabulary has real behavioural teeth downstream.
|
|
45
|
+
//
|
|
46
|
+
// Ported (warning-severity, advisory):
|
|
47
|
+
// GOAL-ELEM-002 — GOAL element `id` does not match the canonical
|
|
48
|
+
// `GOAL-[<middle>-]<INTEGER>` grammar (non-fatal —
|
|
49
|
+
// DSM still imports it).
|
|
50
|
+
// ACTION-001 — ACTION element `id` does not match the canonical
|
|
51
|
+
// `ACTION-[<middle>-]<INTEGER>` grammar.
|
|
52
|
+
// ACTION-005 — ACTION element uses a deprecated alias: `notation:
|
|
53
|
+
// activity` (pre-2026-06-25), an `ACTIVITY-` id prefix,
|
|
54
|
+
// or the `activity_type` field (rename to `type`).
|
|
55
|
+
//
|
|
56
|
+
// Not ported: GOALS-007 (duplicate id) / ACT-004 (duplicate id) — already
|
|
57
|
+
// covered generically by `validate-repo.ts`'s `checkIdUniqueness`, which
|
|
58
|
+
// spans every canon element/relation id, not just GOAL/ACTION. Porting a
|
|
59
|
+
// second, notation-scoped duplicate check here would just double-report the
|
|
60
|
+
// same defect under two rule codes.
|
|
61
|
+
import { docId } from './validate-repo.js';
|
|
62
|
+
const PScope = 'repo';
|
|
63
|
+
const GOAL_ELEM_ID_RE = /^GOAL-([A-Z0-9]+-)*[0-9]+$/;
|
|
64
|
+
const ACTION_ELEM_ID_RE = /^ACTION-([A-Z0-9]+-)*[0-9]+$/;
|
|
65
|
+
/** ACTION scale-level vocabulary (elements/24-action.md §1). "Strategic
|
|
66
|
+
* Initiative" is an accepted alias for "Initiative", matching DSM's
|
|
67
|
+
* `actionTypeVocabulary` (action_element.go). */
|
|
68
|
+
const ACTION_TYPE_VOCABULARY = new Set([
|
|
69
|
+
'Initiative',
|
|
70
|
+
'Strategic Initiative',
|
|
71
|
+
'Programme',
|
|
72
|
+
'Project',
|
|
73
|
+
'Task',
|
|
74
|
+
]);
|
|
75
|
+
function readString(data, key) {
|
|
76
|
+
const v = data[key];
|
|
77
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
78
|
+
}
|
|
79
|
+
function collectCandidates(elements, matches) {
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const doc of elements) {
|
|
82
|
+
if (!doc.data)
|
|
83
|
+
continue;
|
|
84
|
+
if (!matches(doc.data))
|
|
85
|
+
continue;
|
|
86
|
+
out.push({ id: docId(doc) ?? undefined, doc, data: doc.data });
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
/** GOAL-ELEM-002/003 — the GOAL element envelope: id presence + grammar,
|
|
91
|
+
* name presence. Candidate selection is content-based (`notation === 'goal'`)
|
|
92
|
+
* — see the module header for why `GOAL-ELEM-001` (wrong notation) isn't
|
|
93
|
+
* ported here. */
|
|
94
|
+
function checkGoalElements(elements, findings) {
|
|
95
|
+
const candidates = collectCandidates(elements, (data) => data['notation'] === 'goal');
|
|
96
|
+
for (const { id, data } of candidates) {
|
|
97
|
+
const where = id ?? '';
|
|
98
|
+
if (!id) {
|
|
99
|
+
findings.push({
|
|
100
|
+
scope: PScope,
|
|
101
|
+
id: '',
|
|
102
|
+
ruleId: 'GOAL-ELEM-002',
|
|
103
|
+
message: 'GOAL-ELEM-002: GOAL element id is missing.',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
else if (!GOAL_ELEM_ID_RE.test(id)) {
|
|
107
|
+
findings.push({
|
|
108
|
+
scope: PScope,
|
|
109
|
+
id,
|
|
110
|
+
ruleId: 'GOAL-ELEM-002',
|
|
111
|
+
severity: 'warning',
|
|
112
|
+
message: `GOAL-ELEM-002: goal id '${id}' does not match GOAL-[<middle>-]<INTEGER>.`,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
if (!readString(data, 'name')) {
|
|
116
|
+
findings.push({
|
|
117
|
+
scope: PScope,
|
|
118
|
+
id: where,
|
|
119
|
+
ruleId: 'GOAL-ELEM-003',
|
|
120
|
+
message: `GOAL-ELEM-003: GOAL element '${where || '(no id)'}' name is missing.`,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** ACTION-001/002/005 — the ACTION element envelope: id presence + grammar,
|
|
126
|
+
* name presence, type vocabulary, and the pre-2026-06-25 deprecated aliases
|
|
127
|
+
* (`notation: activity`, `ACTIVITY-` id prefix, `activity_type` field).
|
|
128
|
+
* Candidate selection is content-based (`notation === 'action'` or the
|
|
129
|
+
* deprecated `'activity'` alias) — see the module header for why
|
|
130
|
+
* `ACTION-001`'s "wrong notation" case isn't ported here. */
|
|
131
|
+
function checkActionElements(elements, findings) {
|
|
132
|
+
const candidates = collectCandidates(elements, (data) => data['notation'] === 'action' || data['notation'] === 'activity');
|
|
133
|
+
for (const { id, data } of candidates) {
|
|
134
|
+
const where = id ?? '';
|
|
135
|
+
if (data['notation'] === 'activity') {
|
|
136
|
+
findings.push({
|
|
137
|
+
scope: PScope,
|
|
138
|
+
id: where,
|
|
139
|
+
ruleId: 'ACTION-005',
|
|
140
|
+
severity: 'warning',
|
|
141
|
+
message: `ACTION-005: element '${where || '(no id)'}' notation 'activity' is deprecated; migrate to 'action'.`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (!id) {
|
|
145
|
+
findings.push({
|
|
146
|
+
scope: PScope,
|
|
147
|
+
id: '',
|
|
148
|
+
ruleId: 'ACTION-001',
|
|
149
|
+
message: 'ACTION-001: ACTION element id is missing.',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else if (id.startsWith('ACTIVITY-')) {
|
|
153
|
+
findings.push({
|
|
154
|
+
scope: PScope,
|
|
155
|
+
id,
|
|
156
|
+
ruleId: 'ACTION-005',
|
|
157
|
+
severity: 'warning',
|
|
158
|
+
message: `ACTION-005: id '${id}' uses the deprecated ACTIVITY- prefix; migrate to ACTION-.`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
else if (!ACTION_ELEM_ID_RE.test(id)) {
|
|
162
|
+
findings.push({
|
|
163
|
+
scope: PScope,
|
|
164
|
+
id,
|
|
165
|
+
ruleId: 'ACTION-001',
|
|
166
|
+
severity: 'warning',
|
|
167
|
+
message: `ACTION-001: action id '${id}' does not match ACTION-[<middle>-]<INTEGER>.`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (!readString(data, 'name')) {
|
|
171
|
+
findings.push({
|
|
172
|
+
scope: PScope,
|
|
173
|
+
id: where,
|
|
174
|
+
ruleId: 'ACTION-001',
|
|
175
|
+
message: `ACTION-001: ACTION element '${where || '(no id)'}' name is missing.`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
let actionType = readString(data, 'type');
|
|
179
|
+
if (!actionType) {
|
|
180
|
+
const legacy = readString(data, 'activity_type');
|
|
181
|
+
if (legacy) {
|
|
182
|
+
findings.push({
|
|
183
|
+
scope: PScope,
|
|
184
|
+
id: where,
|
|
185
|
+
ruleId: 'ACTION-005',
|
|
186
|
+
severity: 'warning',
|
|
187
|
+
message: `ACTION-005: element '${where || '(no id)'}' field 'activity_type' is deprecated; migrate to 'type'.`,
|
|
188
|
+
});
|
|
189
|
+
actionType = legacy;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (actionType && !ACTION_TYPE_VOCABULARY.has(actionType)) {
|
|
193
|
+
findings.push({
|
|
194
|
+
scope: PScope,
|
|
195
|
+
id: where,
|
|
196
|
+
ruleId: 'ACTION-002',
|
|
197
|
+
message: `ACTION-002: element '${where || '(no id)'}' type '${actionType}' is not one of Initiative, Programme, Project, Task.`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Run the standalone-element envelope checks (GOAL-ELEM-001..003,
|
|
204
|
+
* ACTION-001/002/005) over the loaded element set and append findings.
|
|
205
|
+
* Called from `validateRepoModel` alongside `checkStrategyChainSemantics`.
|
|
206
|
+
* Pure, deterministic order.
|
|
207
|
+
*/
|
|
208
|
+
export function checkElementHygiene(input, findings) {
|
|
209
|
+
checkGoalElements(input.elements, findings);
|
|
210
|
+
checkActionElements(input.elements, findings);
|
|
211
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { RepoFinding, RepoModelInput } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Run the strategy-chain semantic checks (GOALS-009..011, ACT-005..009,
|
|
4
|
+
* FGCA-008..014 except GOALS-008 — see the module header) over the loaded
|
|
5
|
+
* element set and append findings. Called from `validateRepoModel` after the
|
|
6
|
+
* structural phases. Pure, deterministic order.
|
|
7
|
+
*/
|
|
8
|
+
export declare function checkStrategyChainSemantics(input: RepoModelInput, findings: RepoFinding[]): void;
|