@transitrix/diagrams 1.10.0 → 1.11.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/activities/resolver.d.ts +3 -0
- package/dist/activities/resolver.js +39 -18
- package/dist/activities/validate.js +59 -0
- package/dist/canon-resolver-utils.d.ts +3 -0
- package/dist/canon-resolver-utils.js +16 -0
- package/dist/compliance/classify.js +1 -0
- package/dist/compliance/impact.d.ts +3 -1
- package/dist/compliance/impact.js +41 -13
- package/dist/compliance/types.d.ts +6 -0
- package/dist/compliance-verification-matrix/build.d.ts +17 -0
- package/dist/compliance-verification-matrix/build.js +65 -0
- package/dist/compliance-verification-matrix/csv.d.ts +6 -0
- package/dist/compliance-verification-matrix/csv.js +41 -0
- package/dist/compliance-verification-matrix/index.d.ts +3 -0
- package/dist/compliance-verification-matrix/index.js +2 -0
- package/dist/compliance-verification-matrix/types.d.ts +75 -0
- package/dist/compliance-verification-matrix/types.js +4 -0
- package/dist/fgca/action-change-ids.d.ts +7 -0
- package/dist/fgca/action-change-ids.js +11 -0
- package/dist/fgca/parse-canonical.d.ts +3 -1
- package/dist/fgca/parse-canonical.js +13 -8
- package/dist/fgca/resolver.d.ts +6 -2
- package/dist/fgca/resolver.js +12 -6
- package/dist/fgca/validate.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/process-blueprint/index.d.ts +3 -1
- package/dist/process-blueprint/index.js +1 -0
- package/dist/process-blueprint/layout.js +33 -29
- package/dist/process-blueprint/resolve-columns.d.ts +52 -0
- package/dist/process-blueprint/resolve-columns.js +138 -0
- package/dist/process-blueprint/types.d.ts +23 -5
- package/dist/process-blueprint/validate.d.ts +19 -1
- package/dist/process-blueprint/validate.js +73 -21
- package/dist/repo-validate/check-process-parent.d.ts +8 -0
- package/dist/repo-validate/check-process-parent.js +172 -0
- package/dist/repo-validate/index.d.ts +1 -0
- package/dist/repo-validate/index.js +1 -0
- package/dist/repo-validate/validate-repo.js +3 -0
- package/dist/webview/render-fgca.js +1 -1
- package/dist/webview/render-process.d.ts +19 -1
- package/dist/webview/render-process.js +75 -42
- package/package.json +1 -1
- package/src/activities/resolver.ts +40 -20
- package/src/activities/validate.ts +58 -0
- package/src/canon-resolver-utils.ts +19 -0
- package/src/compliance/classify.ts +1 -0
- package/src/compliance/impact.ts +41 -12
- package/src/compliance/types.ts +6 -0
- package/src/compliance-verification-matrix/build.ts +84 -0
- package/src/compliance-verification-matrix/csv.ts +47 -0
- package/src/compliance-verification-matrix/index.ts +7 -0
- package/src/compliance-verification-matrix/types.ts +85 -0
- package/src/fgca/action-change-ids.ts +13 -0
- package/src/fgca/parse-canonical.ts +12 -8
- package/src/fgca/resolver.ts +15 -6
- package/src/fgca/validate.ts +2 -0
- package/src/index.ts +1 -0
- package/src/process-blueprint/index.ts +11 -0
- package/src/process-blueprint/layout.ts +48 -29
- package/src/process-blueprint/resolve-columns.ts +147 -0
- package/src/process-blueprint/types.ts +19 -5
- package/src/process-blueprint/validate.ts +107 -21
- package/src/repo-validate/check-process-parent.ts +184 -0
- package/src/repo-validate/index.ts +5 -0
- package/src/repo-validate/validate-repo.ts +3 -0
- package/src/webview/render-fgca.ts +1 -1
- package/src/webview/render-process.ts +94 -49
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Typed string IDs per `IDS_AND_REFERENCES.md` (`FACTOR-1`,
|
|
9
9
|
* `GOAL-RET-1`, `CHANGE-1`, `ACTION-ONBOARD-1` (legacy `ACTIVITY-*` accepted).
|
|
10
10
|
* - Plural canonical-direction cross-references: `goal.factors`,
|
|
11
|
-
* `change.goals`, `
|
|
11
|
+
* `change.goals`, `action.delivers_changes`, `action.goals`.
|
|
12
12
|
* - Per-notation validation codes `FGCA-001 … FGCA-015`.
|
|
13
13
|
*
|
|
14
14
|
* Returns the validation result plus, on success, an internal `FGCADoc`
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* unify the internal types with the canonical form across all sister
|
|
24
24
|
* modules.
|
|
25
25
|
*/
|
|
26
|
+
import { actionChangeLinkField } from './action-change-ids.js';
|
|
26
27
|
// Canonical ID grammars per IDS_AND_REFERENCES.md §1. The TYPE prefix
|
|
27
28
|
// is fixed per layer; middle segments are optional; the terminal is a
|
|
28
29
|
// positive integer with no leading zeros.
|
|
@@ -43,9 +44,11 @@ function asObjectArray(v) {
|
|
|
43
44
|
return null;
|
|
44
45
|
return v.map((el) => (el && typeof el === 'object' ? el : null));
|
|
45
46
|
}
|
|
46
|
-
/** DGA mode (`view_config.layers.changes: off`)
|
|
47
|
-
function
|
|
48
|
-
|
|
47
|
+
/** DGA mode (`view_config.layers.changes: off`) omits the Changes column. */
|
|
48
|
+
export function isDgcaChangesLayerOff(input) {
|
|
49
|
+
if (!input || typeof input !== 'object')
|
|
50
|
+
return false;
|
|
51
|
+
const vc = input['view_config'];
|
|
49
52
|
if (!vc || typeof vc !== 'object')
|
|
50
53
|
return false;
|
|
51
54
|
const layers = vc['layers'];
|
|
@@ -99,7 +102,7 @@ export function parseCanonicalFGCA(input) {
|
|
|
99
102
|
const factorsRaw = asObjectArray(raw['factors']);
|
|
100
103
|
const goalsRaw = asObjectArray(raw['goals']);
|
|
101
104
|
let changesRaw = asObjectArray(raw['changes']);
|
|
102
|
-
if (changesRaw === null && raw['changes'] === undefined &&
|
|
105
|
+
if (changesRaw === null && raw['changes'] === undefined && isDgcaChangesLayerOff(raw)) {
|
|
103
106
|
changesRaw = [];
|
|
104
107
|
}
|
|
105
108
|
const activitiesRaw = asObjectArray(raw['actions']);
|
|
@@ -212,11 +215,12 @@ export function parseCanonicalFGCA(input) {
|
|
|
212
215
|
factor: refIds.map((r) => ({ id: r })),
|
|
213
216
|
};
|
|
214
217
|
});
|
|
215
|
-
// Build a reverse mapping: which changes does each
|
|
216
|
-
// canonical
|
|
218
|
+
// Build a reverse mapping: which changes does each action deliver (via
|
|
219
|
+
// canonical `delivers_changes`, or the pre-rename `changes` alias)?
|
|
217
220
|
const activityChangesByCanonicalActivityId = new Map();
|
|
218
221
|
activities.forEach((el, i) => {
|
|
219
|
-
const
|
|
222
|
+
const field = actionChangeLinkField(el);
|
|
223
|
+
const refIds = checkRefArray(el, field, changeIds, CHANGE_ID_RE, 'FGCA-010', `activities[${i}]`);
|
|
220
224
|
activityChangesByCanonicalActivityId.set(String(el['id']), refIds);
|
|
221
225
|
});
|
|
222
226
|
// For each change, find the activities that reference it.
|
|
@@ -286,6 +290,7 @@ export function parseCanonicalFGCA(input) {
|
|
|
286
290
|
goals: internalGoals,
|
|
287
291
|
changes: internalChanges,
|
|
288
292
|
activities: internalActivities,
|
|
293
|
+
hideChanges: isDgcaChangesLayerOff(raw),
|
|
289
294
|
};
|
|
290
295
|
return { valid: true, errors, warnings, parsed };
|
|
291
296
|
}
|
package/dist/fgca/resolver.d.ts
CHANGED
|
@@ -18,6 +18,10 @@ export interface FGCAViewConfig {
|
|
|
18
18
|
changes?: {
|
|
19
19
|
surface?: 'derived' | 'all';
|
|
20
20
|
};
|
|
21
|
+
/** Canonical projection key. `activities` remains a deprecated alias. */
|
|
22
|
+
actions?: {
|
|
23
|
+
surface?: 'derived' | 'all';
|
|
24
|
+
};
|
|
21
25
|
activities?: {
|
|
22
26
|
surface?: 'derived' | 'all';
|
|
23
27
|
};
|
|
@@ -43,7 +47,7 @@ export declare function isFGCAViewDoc(parsed: unknown): boolean;
|
|
|
43
47
|
* to pass to `parseCanonicalFGCA`.
|
|
44
48
|
*
|
|
45
49
|
* Cross-reference fields (`goal.factors[]`, `change.goals[]`,
|
|
46
|
-
* `action.
|
|
47
|
-
* resolver decides which elements to include, not how they are shaped.
|
|
50
|
+
* `action.delivers_changes[]`) are carried from the canon elements unchanged;
|
|
51
|
+
* the resolver decides which elements to include, not how they are shaped.
|
|
48
52
|
*/
|
|
49
53
|
export declare function resolveFGCA(viewDoc: unknown, sources: FGCACanonSources): Record<string, unknown>;
|
package/dist/fgca/resolver.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* top-level `factors[]`, `goals[]`, `changes[]`, `actions[]` with typed
|
|
7
7
|
* string IDs. Filesystem-free — callable from unit tests without vscode.
|
|
8
8
|
*/
|
|
9
|
+
import { actionChangeLinkField } from './action-change-ids.js';
|
|
9
10
|
function isObject(v) {
|
|
10
11
|
return !!v && typeof v === 'object' && !Array.isArray(v);
|
|
11
12
|
}
|
|
@@ -49,8 +50,8 @@ export function isFGCAViewDoc(parsed) {
|
|
|
49
50
|
* to pass to `parseCanonicalFGCA`.
|
|
50
51
|
*
|
|
51
52
|
* Cross-reference fields (`goal.factors[]`, `change.goals[]`,
|
|
52
|
-
* `action.
|
|
53
|
-
* resolver decides which elements to include, not how they are shaped.
|
|
53
|
+
* `action.delivers_changes[]`) are carried from the canon elements unchanged;
|
|
54
|
+
* the resolver decides which elements to include, not how they are shaped.
|
|
54
55
|
*/
|
|
55
56
|
export function resolveFGCA(viewDoc, sources) {
|
|
56
57
|
if (!isObject(viewDoc)) {
|
|
@@ -60,7 +61,11 @@ export function resolveFGCA(viewDoc, sources) {
|
|
|
60
61
|
const goalsConf = isObject(vc['goals']) ? vc['goals'] : {};
|
|
61
62
|
const factorsConf = isObject(vc['factors']) ? vc['factors'] : {};
|
|
62
63
|
const changesConf = isObject(vc['changes']) ? vc['changes'] : {};
|
|
63
|
-
const
|
|
64
|
+
const actionsConf = isObject(vc['actions'])
|
|
65
|
+
? vc['actions']
|
|
66
|
+
: isObject(vc['activities'])
|
|
67
|
+
? vc['activities']
|
|
68
|
+
: {};
|
|
64
69
|
const factorElemsLegacy = collectByNotation(sources.elements, 'factor');
|
|
65
70
|
const factorElemsNew = collectByNotation(sources.elements, 'driver');
|
|
66
71
|
const factorElems = new Map([...factorElemsLegacy, ...factorElemsNew]);
|
|
@@ -108,13 +113,13 @@ export function resolveFGCA(viewDoc, sources) {
|
|
|
108
113
|
selectedChanges = [...changeElems.values()].filter((c) => strArray(c['goals']).some((gid) => selectedGoalIds.has(gid)));
|
|
109
114
|
}
|
|
110
115
|
const selectedChangeIds = new Set(selectedChanges.map((c) => str(c['id'])).filter((x) => x !== undefined));
|
|
111
|
-
// 4. Select
|
|
116
|
+
// 4. Select actions: derived = delivers ≥1 selected change, or (DGA) a selected goal
|
|
112
117
|
let selectedActivities;
|
|
113
|
-
if (str(
|
|
118
|
+
if (str(actionsConf['surface']) === 'all') {
|
|
114
119
|
selectedActivities = [...activityElems.values()];
|
|
115
120
|
}
|
|
116
121
|
else {
|
|
117
|
-
selectedActivities = [...activityElems.values()].filter((a) => strArray(a[
|
|
122
|
+
selectedActivities = [...activityElems.values()].filter((a) => strArray(a[actionChangeLinkField(a)]).some((cid) => selectedChangeIds.has(cid)) ||
|
|
118
123
|
strArray(a['goals']).some((gid) => selectedGoalIds.has(gid)));
|
|
119
124
|
}
|
|
120
125
|
return {
|
|
@@ -126,5 +131,6 @@ export function resolveFGCA(viewDoc, sources) {
|
|
|
126
131
|
goals: selectedGoals,
|
|
127
132
|
changes: selectedChanges,
|
|
128
133
|
actions: selectedActivities,
|
|
134
|
+
view_config: viewDoc['view_config'],
|
|
129
135
|
};
|
|
130
136
|
}
|
package/dist/fgca/validate.d.ts
CHANGED
|
@@ -10,5 +10,7 @@ export interface FGCADoc {
|
|
|
10
10
|
goals: GoalItem[];
|
|
11
11
|
changes: BdnChangeWithActivities[];
|
|
12
12
|
activities: ActivityItem[];
|
|
13
|
+
/** DGA mode: omit the Changes column (`view_config.layers.changes: off`). */
|
|
14
|
+
hideChanges?: boolean;
|
|
13
15
|
}
|
|
14
16
|
export declare function validateFGCADoc(input: unknown): FGCAValidationResult;
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export { validateCapabilityMap, layoutCapabilityTree, TREE_NODE_WIDTH, TREE_NODE
|
|
|
11
11
|
export * from "./change/index";
|
|
12
12
|
export * from "./compliance/index";
|
|
13
13
|
export * from "./compliance-matrix/index";
|
|
14
|
+
export * from "./compliance-verification-matrix/index";
|
|
14
15
|
export * from "./confidence/index";
|
|
15
16
|
export * from "./factor/index";
|
|
16
17
|
export * from "./fgca/index";
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { validateCapabilityMap, layoutCapabilityTree, TREE_NODE_WIDTH, TREE_NODE
|
|
|
10
10
|
export * from "./change/index.js";
|
|
11
11
|
export * from "./compliance/index.js";
|
|
12
12
|
export * from "./compliance-matrix/index.js";
|
|
13
|
+
export * from "./compliance-verification-matrix/index.js";
|
|
13
14
|
export * from "./confidence/index.js";
|
|
14
15
|
export * from "./factor/index.js";
|
|
15
16
|
export * from "./fgca/index.js";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type { AspectCategory, RowId, Stage, AspectEntry, LaneConfig, ProcessBlueprintHeader, ProcessBlueprintFile, ProcessBlueprintLayoutOptions, LegendCell, StageHeaderCell, StageTextCell, AspectPill, AspectRow, ProcessBlueprintLayout, ComplianceDecoration, ComplianceChip, ComplianceRow, ComplianceLaneConfig, ComplianceLaneAssertion, ComplianceLaneRequirement, ComplianceLaneInput, } from './types.js';
|
|
2
2
|
export { validateProcessBlueprint } from './validate.js';
|
|
3
|
-
export type { ValidationError as ProcessBlueprintValidationError, ValidationWarning as ProcessBlueprintValidationWarning, ValidationResult as ProcessBlueprintValidationResult, } from './validate.js';
|
|
3
|
+
export type { ValidationError as ProcessBlueprintValidationError, ValidationWarning as ProcessBlueprintValidationWarning, ValidationResult as ProcessBlueprintValidationResult, ProcessBlueprintValidateOptions, ProcessParentEdge, } from './validate.js';
|
|
4
4
|
export { layoutProcessBlueprint } from './layout.js';
|
|
5
|
+
export { collectProcessColumnRecords, collectStepHomeProcess, columnIndexesForRealisedVia, isProcessColumnId, isStageColumnId, resolveColumnDisplay, } from './resolve-columns.js';
|
|
6
|
+
export type { ProcessColumnRecord } from './resolve-columns.js';
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
export { validateProcessBlueprint } from './validate.js';
|
|
2
2
|
export { layoutProcessBlueprint } from './layout.js';
|
|
3
|
+
export { collectProcessColumnRecords, collectStepHomeProcess, columnIndexesForRealisedVia, isProcessColumnId, isStageColumnId, resolveColumnDisplay, } from './resolve-columns.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { wrapTextLines } from '../webview/entity-text-layout.js';
|
|
2
|
+
import { columnIndexesForRealisedVia, resolveColumnDisplay } from './resolve-columns.js';
|
|
2
3
|
const ASPECT_CATEGORIES = ['systems', 'actors', 'equipment', 'information_entities'];
|
|
3
4
|
const ASPECT_LABEL = {
|
|
4
5
|
systems: 'Systems',
|
|
@@ -181,29 +182,31 @@ function deriveComplianceRow(stages, stageIndexById, input, opts, yStart) {
|
|
|
181
182
|
for (const stageRef of realisedVia) {
|
|
182
183
|
if (typeof stageRef !== 'string')
|
|
183
184
|
continue;
|
|
184
|
-
const
|
|
185
|
-
if (
|
|
185
|
+
const idxs = columnIndexesForRealisedVia(stageRef, stageIndexById, opts.stepHomeProcess);
|
|
186
|
+
if (idxs.length === 0)
|
|
186
187
|
continue;
|
|
187
|
-
for (const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
stageAccum.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
existing.deadline
|
|
188
|
+
for (const idx of idxs) {
|
|
189
|
+
for (const lawId of lawIds) {
|
|
190
|
+
// Apply jurisdiction filter.
|
|
191
|
+
if (filterJurisdictions) {
|
|
192
|
+
const jur = input.codexJurisdictions?.[lawId];
|
|
193
|
+
if (!jur || !filterJurisdictions.has(jur))
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (!stageAccum.has(idx))
|
|
197
|
+
stageAccum.set(idx, new Map());
|
|
198
|
+
const lawMap = stageAccum.get(idx);
|
|
199
|
+
const existing = lawMap.get(lawId);
|
|
200
|
+
const isGap = a.status === 'non_compliant' || a.status === 'partial';
|
|
201
|
+
if (!existing) {
|
|
202
|
+
lawMap.set(lawId, { gap: isGap, deadline: req.deadline });
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
existing.gap = existing.gap || isGap;
|
|
206
|
+
// Keep the earlier deadline (more urgent).
|
|
207
|
+
if (req.deadline && (!existing.deadline || req.deadline < existing.deadline)) {
|
|
208
|
+
existing.deadline = req.deadline;
|
|
209
|
+
}
|
|
207
210
|
}
|
|
208
211
|
}
|
|
209
212
|
}
|
|
@@ -253,6 +256,7 @@ export function layoutProcessBlueprint(file, options) {
|
|
|
253
256
|
? allStages.filter(s => s?.id != null && opts.visibleStages.includes(s.id))
|
|
254
257
|
: allStages;
|
|
255
258
|
const stageIndexById = buildStageIndex(stages);
|
|
259
|
+
const display = stages.map(s => resolveColumnDisplay(s, opts.processCatalog));
|
|
256
260
|
// Row visibility from visibleRows
|
|
257
261
|
const visRows = opts.visibleRows;
|
|
258
262
|
const showGoal = !visRows || visRows.includes('goal');
|
|
@@ -266,7 +270,7 @@ export function layoutProcessBlueprint(file, options) {
|
|
|
266
270
|
const stageHeaders = stages.map((s, i) => ({
|
|
267
271
|
stageIndex: i,
|
|
268
272
|
id: s?.id ?? '',
|
|
269
|
-
name:
|
|
273
|
+
name: display[i].name,
|
|
270
274
|
x: opts.legendColumnWidth + i * opts.stageColumnWidth,
|
|
271
275
|
y: 0,
|
|
272
276
|
width: opts.stageColumnWidth,
|
|
@@ -280,8 +284,8 @@ export function layoutProcessBlueprint(file, options) {
|
|
|
280
284
|
const maxLines = Math.max(1, ...lineCounts);
|
|
281
285
|
return Math.max(minHeight, maxLines * opts.textLineHeight + 2 * opts.cellTextPadY);
|
|
282
286
|
};
|
|
283
|
-
const goalLines =
|
|
284
|
-
const resultLines =
|
|
287
|
+
const goalLines = display.map(d => wrap(d.goal));
|
|
288
|
+
const resultLines = display.map(d => wrap(d.result));
|
|
285
289
|
let cursorY = opts.stageHeaderHeight;
|
|
286
290
|
let goalRowY = 0, goalRowHeight = 0;
|
|
287
291
|
let resultRowY = 0, resultRowHeight = 0;
|
|
@@ -290,8 +294,8 @@ export function layoutProcessBlueprint(file, options) {
|
|
|
290
294
|
if (showGoal) {
|
|
291
295
|
goalRowY = cursorY;
|
|
292
296
|
goalRowHeight = rowHeightFor(goalLines.map(l => l.length), opts.goalRowHeight);
|
|
293
|
-
goalCells.push(...
|
|
294
|
-
stageIndex: i, text:
|
|
297
|
+
goalCells.push(...display.map((d, i) => ({
|
|
298
|
+
stageIndex: i, text: d.goal, lines: goalLines[i],
|
|
295
299
|
x: opts.legendColumnWidth + i * opts.stageColumnWidth, y: goalRowY,
|
|
296
300
|
width: opts.stageColumnWidth, height: goalRowHeight,
|
|
297
301
|
})));
|
|
@@ -300,8 +304,8 @@ export function layoutProcessBlueprint(file, options) {
|
|
|
300
304
|
if (showResult) {
|
|
301
305
|
resultRowY = cursorY;
|
|
302
306
|
resultRowHeight = rowHeightFor(resultLines.map(l => l.length), opts.resultRowHeight);
|
|
303
|
-
resultCells.push(...
|
|
304
|
-
stageIndex: i, text:
|
|
307
|
+
resultCells.push(...display.map((d, i) => ({
|
|
308
|
+
stageIndex: i, text: d.result, lines: resultLines[i],
|
|
305
309
|
x: opts.legendColumnWidth + i * opts.stageColumnWidth, y: resultRowY,
|
|
306
310
|
width: opts.stageColumnWidth, height: resultRowHeight,
|
|
307
311
|
})));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render-time resolution of Process Blueprint column headers and the
|
|
3
|
+
* compliance-lane join key.
|
|
4
|
+
*
|
|
5
|
+
* A `PROCESS-…` column is the process: `name` / `goal` / `result` come from
|
|
6
|
+
* the child PROCESS element (ELEMENT_PRIMITIVES §7.5), never from restated
|
|
7
|
+
* view fields. A `STAGE-…` column keeps the authored sketch copy.
|
|
8
|
+
*
|
|
9
|
+
* Pure: no I/O. The host (VS Code preview, JCEF, CLI) already owns loading
|
|
10
|
+
* canon/elements/** — this module only knows how to pick PROCESS / STEP
|
|
11
|
+
* records out of that pool.
|
|
12
|
+
*
|
|
13
|
+
* This is a read model, never storage. Callers render an ephemeral display
|
|
14
|
+
* copy and must never serialise it back onto the view.
|
|
15
|
+
*/
|
|
16
|
+
import type { Stage } from './types.js';
|
|
17
|
+
export declare function isProcessColumnId(id: string): boolean;
|
|
18
|
+
export declare function isStageColumnId(id: string): boolean;
|
|
19
|
+
/** Display fields taken from a `notation: process` element. */
|
|
20
|
+
export interface ProcessColumnRecord {
|
|
21
|
+
name: string;
|
|
22
|
+
goal?: string;
|
|
23
|
+
result?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Collect admitted PROCESS elements from a raw canon/elements/** doc pool,
|
|
27
|
+
* keyed by id. Malformed documents are skipped.
|
|
28
|
+
*/
|
|
29
|
+
export declare function collectProcessColumnRecords(docs: readonly unknown[]): Map<string, ProcessColumnRecord>;
|
|
30
|
+
/**
|
|
31
|
+
* Map each STEP id onto the PROCESS that contains it — either inline in
|
|
32
|
+
* `PROCESS.flow.steps[]` or a promoted `{ notation: step, process }` element.
|
|
33
|
+
* First writer wins; a later duplicate is ignored.
|
|
34
|
+
*/
|
|
35
|
+
export declare function collectStepHomeProcess(docs: readonly unknown[]): Map<string, string>;
|
|
36
|
+
/**
|
|
37
|
+
* Display copy for one column. PROCESS- columns ignore any restated view
|
|
38
|
+
* fields; missing catalogue falls back to the id (header) and empty
|
|
39
|
+
* goal/result. STAGE- columns keep authored name/goal/result.
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveColumnDisplay(stage: Stage, catalog?: ReadonlyMap<string, ProcessColumnRecord>): {
|
|
42
|
+
name: string;
|
|
43
|
+
goal: string;
|
|
44
|
+
result: string;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Column indexes a `realised_via` token pins on this blueprint.
|
|
48
|
+
*
|
|
49
|
+
* `STAGE-…` is never a join key (ASSERT-004). A `PROCESS-…` token pins that
|
|
50
|
+
* column. A STEP whose home process is a column pins that column.
|
|
51
|
+
*/
|
|
52
|
+
export declare function columnIndexesForRealisedVia(ref: string, stageIndexById: ReadonlyMap<string, number>, stepHomeProcess?: ReadonlyMap<string, string>): number[];
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render-time resolution of Process Blueprint column headers and the
|
|
3
|
+
* compliance-lane join key.
|
|
4
|
+
*
|
|
5
|
+
* A `PROCESS-…` column is the process: `name` / `goal` / `result` come from
|
|
6
|
+
* the child PROCESS element (ELEMENT_PRIMITIVES §7.5), never from restated
|
|
7
|
+
* view fields. A `STAGE-…` column keeps the authored sketch copy.
|
|
8
|
+
*
|
|
9
|
+
* Pure: no I/O. The host (VS Code preview, JCEF, CLI) already owns loading
|
|
10
|
+
* canon/elements/** — this module only knows how to pick PROCESS / STEP
|
|
11
|
+
* records out of that pool.
|
|
12
|
+
*
|
|
13
|
+
* This is a read model, never storage. Callers render an ephemeral display
|
|
14
|
+
* copy and must never serialise it back onto the view.
|
|
15
|
+
*/
|
|
16
|
+
const PROCESS_ID_RE = /^PROCESS(-[A-Z0-9][A-Z0-9_]*)*-\d+$/;
|
|
17
|
+
const STAGE_ID_RE = /^STAGE(-[A-Z0-9][A-Z0-9_]*)*-\d+$/;
|
|
18
|
+
export function isProcessColumnId(id) {
|
|
19
|
+
return PROCESS_ID_RE.test(id);
|
|
20
|
+
}
|
|
21
|
+
export function isStageColumnId(id) {
|
|
22
|
+
return STAGE_ID_RE.test(id);
|
|
23
|
+
}
|
|
24
|
+
function isRecord(v) {
|
|
25
|
+
return v !== null && typeof v === 'object' && !Array.isArray(v);
|
|
26
|
+
}
|
|
27
|
+
function optionalString(v) {
|
|
28
|
+
return typeof v === 'string' && v.trim().length > 0 ? v.trim() : undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Collect admitted PROCESS elements from a raw canon/elements/** doc pool,
|
|
32
|
+
* keyed by id. Malformed documents are skipped.
|
|
33
|
+
*/
|
|
34
|
+
export function collectProcessColumnRecords(docs) {
|
|
35
|
+
const out = new Map();
|
|
36
|
+
for (const doc of docs) {
|
|
37
|
+
if (!isRecord(doc))
|
|
38
|
+
continue;
|
|
39
|
+
if (doc['notation'] !== 'process')
|
|
40
|
+
continue;
|
|
41
|
+
const id = optionalString(doc['id']);
|
|
42
|
+
if (!id || !isProcessColumnId(id))
|
|
43
|
+
continue;
|
|
44
|
+
const name = optionalString(doc['name']);
|
|
45
|
+
if (!name)
|
|
46
|
+
continue;
|
|
47
|
+
const rec = { name };
|
|
48
|
+
const goal = optionalString(doc['goal']);
|
|
49
|
+
const result = optionalString(doc['result']);
|
|
50
|
+
if (goal)
|
|
51
|
+
rec.goal = goal;
|
|
52
|
+
if (result)
|
|
53
|
+
rec.result = result;
|
|
54
|
+
out.set(id, rec);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Map each STEP id onto the PROCESS that contains it — either inline in
|
|
60
|
+
* `PROCESS.flow.steps[]` or a promoted `{ notation: step, process }` element.
|
|
61
|
+
* First writer wins; a later duplicate is ignored.
|
|
62
|
+
*/
|
|
63
|
+
export function collectStepHomeProcess(docs) {
|
|
64
|
+
const out = new Map();
|
|
65
|
+
for (const doc of docs) {
|
|
66
|
+
if (!isRecord(doc))
|
|
67
|
+
continue;
|
|
68
|
+
if (doc['notation'] === 'process') {
|
|
69
|
+
const processId = optionalString(doc['id']);
|
|
70
|
+
if (!processId || !isProcessColumnId(processId))
|
|
71
|
+
continue;
|
|
72
|
+
const flow = isRecord(doc['flow']) ? doc['flow'] : undefined;
|
|
73
|
+
const steps = flow && Array.isArray(flow['steps']) ? flow['steps'] : [];
|
|
74
|
+
for (const step of steps) {
|
|
75
|
+
if (!isRecord(step))
|
|
76
|
+
continue;
|
|
77
|
+
const stepId = optionalString(step['id']);
|
|
78
|
+
if (!stepId || out.has(stepId))
|
|
79
|
+
continue;
|
|
80
|
+
out.set(stepId, processId);
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
if (doc['notation'] === 'step') {
|
|
85
|
+
const stepId = optionalString(doc['id']);
|
|
86
|
+
const processId = optionalString(doc['process']);
|
|
87
|
+
if (!stepId || !processId || !isProcessColumnId(processId))
|
|
88
|
+
continue;
|
|
89
|
+
if (!out.has(stepId))
|
|
90
|
+
out.set(stepId, processId);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Display copy for one column. PROCESS- columns ignore any restated view
|
|
97
|
+
* fields; missing catalogue falls back to the id (header) and empty
|
|
98
|
+
* goal/result. STAGE- columns keep authored name/goal/result.
|
|
99
|
+
*/
|
|
100
|
+
export function resolveColumnDisplay(stage, catalog) {
|
|
101
|
+
const id = typeof stage.id === 'string' ? stage.id.trim() : '';
|
|
102
|
+
if (isProcessColumnId(id)) {
|
|
103
|
+
const rec = catalog?.get(id);
|
|
104
|
+
return {
|
|
105
|
+
name: rec?.name ?? id,
|
|
106
|
+
goal: rec?.goal ?? '',
|
|
107
|
+
result: rec?.result ?? '',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
name: typeof stage.name === 'string' ? stage.name : '',
|
|
112
|
+
goal: typeof stage.goal === 'string' ? stage.goal : '',
|
|
113
|
+
result: typeof stage.result === 'string' ? stage.result : '',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Column indexes a `realised_via` token pins on this blueprint.
|
|
118
|
+
*
|
|
119
|
+
* `STAGE-…` is never a join key (ASSERT-004). A `PROCESS-…` token pins that
|
|
120
|
+
* column. A STEP whose home process is a column pins that column.
|
|
121
|
+
*/
|
|
122
|
+
export function columnIndexesForRealisedVia(ref, stageIndexById, stepHomeProcess) {
|
|
123
|
+
const token = ref.trim();
|
|
124
|
+
if (token.length === 0)
|
|
125
|
+
return [];
|
|
126
|
+
if (isStageColumnId(token))
|
|
127
|
+
return [];
|
|
128
|
+
const direct = stageIndexById.get(token);
|
|
129
|
+
if (direct !== undefined && isProcessColumnId(token))
|
|
130
|
+
return [direct];
|
|
131
|
+
const home = stepHomeProcess?.get(token);
|
|
132
|
+
if (home && isProcessColumnId(home)) {
|
|
133
|
+
const idx = stageIndexById.get(home);
|
|
134
|
+
if (idx !== undefined)
|
|
135
|
+
return [idx];
|
|
136
|
+
}
|
|
137
|
+
return [];
|
|
138
|
+
}
|
|
@@ -27,8 +27,9 @@ export interface ComplianceLaneAssertion {
|
|
|
27
27
|
/** Compliance realisation status. */
|
|
28
28
|
status: 'compliant' | 'partial' | 'non_compliant' | 'under_review' | 'pending_owner' | 'n_a';
|
|
29
29
|
/**
|
|
30
|
-
* Typed IDs of
|
|
31
|
-
*
|
|
30
|
+
* Typed IDs of processes or steps where the requirement is realised.
|
|
31
|
+
* Sketch `STAGE-…` ids are not a join key. When empty/absent, the assertion
|
|
32
|
+
* covers the entire subject, not a specific column.
|
|
32
33
|
*/
|
|
33
34
|
realised_via?: string[];
|
|
34
35
|
}
|
|
@@ -89,9 +90,12 @@ export interface ComplianceRow {
|
|
|
89
90
|
}
|
|
90
91
|
export interface Stage {
|
|
91
92
|
id: string;
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
/** Required on `STAGE-…` sketch columns (`BP-005`); omitted on `PROCESS-…`. */
|
|
94
|
+
name?: string;
|
|
95
|
+
/** Required on `STAGE-…` sketch columns (`BP-005`); omitted on `PROCESS-…`. */
|
|
96
|
+
goal?: string;
|
|
97
|
+
/** Required on `STAGE-…` sketch columns (`BP-005`); omitted on `PROCESS-…`. */
|
|
98
|
+
result?: string;
|
|
95
99
|
description?: string;
|
|
96
100
|
}
|
|
97
101
|
export interface AspectEntry {
|
|
@@ -188,6 +192,20 @@ export interface ProcessBlueprintLayoutOptions {
|
|
|
188
192
|
* When absent, all stages are shown.
|
|
189
193
|
*/
|
|
190
194
|
visibleStages?: string[];
|
|
195
|
+
/**
|
|
196
|
+
* Catalogue of `PROCESS-…` column records (id → name / optional goal / result).
|
|
197
|
+
* Required to header catalogued columns; ignored for `STAGE-…` sketches.
|
|
198
|
+
*/
|
|
199
|
+
processCatalog?: ReadonlyMap<string, {
|
|
200
|
+
name: string;
|
|
201
|
+
goal?: string;
|
|
202
|
+
result?: string;
|
|
203
|
+
}>;
|
|
204
|
+
/**
|
|
205
|
+
* STEP id → home PROCESS id (contained in `PROCESS.flow` or promoted).
|
|
206
|
+
* Used by the compliance-lane join; omit to skip STEP-level pins.
|
|
207
|
+
*/
|
|
208
|
+
stepHomeProcess?: ReadonlyMap<string, string>;
|
|
191
209
|
}
|
|
192
210
|
import type { LayoutBounds } from '../geometry.js';
|
|
193
211
|
export type { LayoutBounds };
|
|
@@ -1,3 +1,21 @@
|
|
|
1
1
|
import type { ValidationError, ValidationWarning, ValidationResult } from '../validation-types.js';
|
|
2
|
+
import type { CanonCatalog } from '../typed-id.js';
|
|
2
3
|
export type { ValidationError, ValidationWarning, ValidationResult };
|
|
3
|
-
export
|
|
4
|
+
export interface ProcessParentEdge {
|
|
5
|
+
/** Child process id (`from`). */
|
|
6
|
+
from: string;
|
|
7
|
+
/** Parent process id (`to`). */
|
|
8
|
+
to: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ProcessBlueprintValidateOptions {
|
|
11
|
+
/** When provided, BP-012 resolves `PROCESS-…` column ids against admitted canon. */
|
|
12
|
+
catalog?: CanonCatalog;
|
|
13
|
+
/**
|
|
14
|
+
* In-effect `process_parent` edges (child → parent). When provided, BP-014
|
|
15
|
+
* warns if `process_blueprint.process` is set and a `PROCESS-…` column has
|
|
16
|
+
* no such edge to that parent. Omit to skip BP-014 (file-scope without the
|
|
17
|
+
* relation catalogue).
|
|
18
|
+
*/
|
|
19
|
+
processParentEdges?: readonly ProcessParentEdge[];
|
|
20
|
+
}
|
|
21
|
+
export declare function validateProcessBlueprint(input: unknown, options?: ProcessBlueprintValidateOptions): ValidationResult;
|