@transitrix/diagrams 1.0.0 → 1.0.1
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 +21 -21
- package/README.md +47 -47
- package/dist/__tests__/edge-path.test.js +8 -0
- package/dist/activity-card/__tests__/example.test.js +20 -1
- package/dist/activity-card/__tests__/layout.test.js +102 -11
- package/dist/activity-card/__tests__/resolver.test.js +139 -6
- package/dist/activity-card/index.d.ts +1 -1
- package/dist/activity-card/layout.d.ts +1 -1
- package/dist/activity-card/layout.js +220 -103
- package/dist/activity-card/resolver.js +107 -26
- package/dist/activity-card/types.d.ts +150 -27
- package/dist/activity-card/validate.js +3 -0
- package/dist/actor/__tests__/validate.test.js +63 -31
- package/dist/actor/index.d.ts +1 -1
- package/dist/actor/index.js +1 -1
- package/dist/actor/types.d.ts +7 -3
- package/dist/actor/types.js +17 -3
- package/dist/actor/validate.js +55 -26
- package/dist/assertion/types.d.ts +3 -1
- package/dist/assertion/types.js +1 -1
- package/dist/change/__tests__/validate.test.js +40 -34
- package/dist/change/index.d.ts +1 -0
- package/dist/change/types.d.ts +1 -1
- package/dist/change/types.js +2 -2
- package/dist/change/validate.d.ts +6 -1
- package/dist/change/validate.js +68 -41
- package/dist/compliance/__tests__/classify.test.js +34 -0
- package/dist/compliance/__tests__/coverage-metric.test.js +146 -46
- package/dist/compliance/__tests__/html.test.js +2 -2
- package/dist/compliance/__tests__/impact.test.js +311 -6
- package/dist/compliance/classify.d.ts +6 -0
- package/dist/compliance/classify.js +9 -1
- package/dist/compliance/coverage-metric.d.ts +31 -11
- package/dist/compliance/coverage-metric.js +149 -39
- package/dist/compliance/html.js +77 -74
- package/dist/compliance/impact.d.ts +77 -16
- package/dist/compliance/impact.js +193 -25
- package/dist/compliance/index.d.ts +2 -2
- package/dist/compliance/index.js +1 -1
- package/dist/compliance/markdown.js +1 -0
- package/dist/compliance/types.d.ts +25 -6
- package/dist/edge-path.d.ts +8 -4
- package/dist/edge-path.js +11 -6
- package/dist/factor/__tests__/validate.test.js +74 -45
- package/dist/factor/index.d.ts +3 -2
- package/dist/factor/index.js +1 -1
- package/dist/factor/types.d.ts +4 -7
- package/dist/factor/types.js +10 -5
- package/dist/factor/validate.d.ts +6 -1
- package/dist/factor/validate.js +68 -50
- package/dist/fgca/__tests__/resolver.test.js +185 -0
- package/dist/fgca/index.d.ts +2 -0
- package/dist/fgca/index.js +1 -0
- package/dist/fgca/resolver.d.ts +49 -0
- package/dist/fgca/resolver.js +124 -0
- package/dist/goals/index.d.ts +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/process-blueprint/__tests__/layout.test.js +37 -0
- package/dist/process-blueprint/layout.js +5 -1
- package/dist/process-blueprint/types.d.ts +22 -1
- package/dist/stakeholder/__tests__/validate.test.js +49 -47
- package/dist/stakeholder/index.d.ts +1 -0
- package/dist/stakeholder/types.d.ts +3 -4
- package/dist/stakeholder/types.js +2 -3
- package/dist/stakeholder/validate.d.ts +6 -1
- package/dist/stakeholder/validate.js +71 -50
- package/dist/target-state/__tests__/validate.test.js +43 -27
- package/dist/target-state/index.d.ts +2 -0
- package/dist/target-state/index.js +1 -0
- package/dist/target-state/types.d.ts +6 -1
- package/dist/target-state/types.js +8 -7
- package/dist/target-state/validate.d.ts +6 -1
- package/dist/target-state/validate.js +69 -45
- package/dist/theme/themes.js +69 -69
- package/dist/webview/__tests__/entry.test.js +11 -11
- package/dist/webview/render-activities.d.ts +3 -1
- package/dist/webview/render-activities.js +2 -2
- package/dist/webview/render-activity-card.js +104 -77
- package/dist/webview/render-fgca.d.ts +4 -0
- package/dist/webview/render-fgca.js +2 -5
- package/dist/webview/render-goals.d.ts +1 -0
- package/dist/webview/render-goals.js +15 -15
- package/dist/webview/render-process-blueprint.js +10 -10
- package/package.json +40 -40
- package/src/__tests__/edge-path.test.ts +58 -46
- package/src/__tests__/scope.test.ts +27 -27
- package/src/__tests__/yaml-normalize.test.ts +158 -158
- package/src/activities/__tests__/cpm.test.ts +164 -164
- package/src/activities/__tests__/gantt.test.ts +245 -245
- package/src/activities/__tests__/layout.test.ts +112 -112
- package/src/activities/__tests__/validate.test.ts +409 -409
- package/src/activities/cpm.ts +95 -95
- package/src/activities/gantt.ts +276 -276
- package/src/activities/index.ts +28 -28
- package/src/activities/layout.ts +112 -112
- package/src/activities/types.ts +148 -148
- package/src/activities/validate.ts +357 -357
- package/src/activity-card/__tests__/example.test.ts +85 -66
- package/src/activity-card/__tests__/layout.test.ts +169 -63
- package/src/activity-card/__tests__/resolver.test.ts +307 -161
- package/src/activity-card/__tests__/validate.test.ts +131 -131
- package/src/activity-card/index.ts +38 -32
- package/src/activity-card/layout.ts +324 -194
- package/src/activity-card/resolver.ts +415 -337
- package/src/activity-card/types.ts +376 -237
- package/src/activity-card/validate.ts +162 -158
- package/src/actor/__tests__/validate.test.ts +70 -31
- package/src/actor/index.ts +1 -1
- package/src/actor/types.ts +21 -7
- package/src/actor/validate.ts +59 -27
- package/src/applications/__tests__/validate.test.ts +256 -256
- package/src/applications/index.ts +11 -11
- package/src/applications/types.ts +43 -43
- package/src/applications/validate.ts +131 -131
- package/src/assertion/__tests__/example.test.ts +37 -37
- package/src/assertion/__tests__/validate.test.ts +142 -142
- package/src/assertion/index.ts +12 -12
- package/src/assertion/types.ts +60 -58
- package/src/assertion/validate.ts +145 -145
- package/src/blocks/__tests__/layout.test.ts +169 -169
- package/src/blocks/__tests__/validate.test.ts +260 -260
- package/src/blocks/index.ts +17 -17
- package/src/blocks/layout.ts +186 -186
- package/src/blocks/types.ts +62 -62
- package/src/blocks/validate.ts +206 -206
- package/src/capability-map/__tests__/validate.test.ts +238 -238
- package/src/capability-map/index.ts +8 -8
- package/src/capability-map/types.ts +29 -29
- package/src/capability-map/validate.ts +127 -127
- package/src/change/__tests__/validate.test.ts +43 -34
- package/src/change/index.ts +1 -0
- package/src/change/types.ts +5 -3
- package/src/change/validate.ts +75 -43
- package/src/compliance/__tests__/classify.test.ts +64 -27
- package/src/compliance/__tests__/confidence.test.ts +98 -98
- package/src/compliance/__tests__/coverage-metric.test.ts +300 -188
- package/src/compliance/__tests__/demo-scenario.test.ts +273 -273
- package/src/compliance/__tests__/example.test.ts +57 -57
- package/src/compliance/__tests__/gap-report.test.ts +128 -128
- package/src/compliance/__tests__/html.test.ts +141 -141
- package/src/compliance/__tests__/impact.test.ts +840 -481
- package/src/compliance/__tests__/markdown.test.ts +94 -94
- package/src/compliance/__tests__/views.test.ts +64 -64
- package/src/compliance/classify.ts +100 -84
- package/src/compliance/confidence.ts +69 -69
- package/src/compliance/coverage-metric.ts +404 -263
- package/src/compliance/gap-report.ts +94 -94
- package/src/compliance/html.ts +298 -295
- package/src/compliance/impact.ts +861 -677
- package/src/compliance/index.ts +57 -56
- package/src/compliance/markdown.ts +136 -135
- package/src/compliance/reverse-index.ts +33 -33
- package/src/compliance/types.ts +136 -120
- package/src/compliance/views.ts +46 -46
- package/src/compliance-matrix/__tests__/build.test.ts +200 -200
- package/src/compliance-matrix/__tests__/example.test.ts +57 -57
- package/src/compliance-matrix/index.ts +11 -11
- package/src/compliance-matrix/types.ts +102 -102
- package/src/edge-path.ts +50 -44
- package/src/factor/__tests__/validate.test.ts +80 -45
- package/src/factor/index.ts +3 -7
- package/src/factor/types.ts +14 -18
- package/src/factor/validate.ts +77 -51
- package/src/fgca/__tests__/chain-table.test.ts +172 -172
- package/src/fgca/__tests__/layout.test.ts +179 -179
- package/src/fgca/__tests__/parse-canonical.test.ts +248 -248
- package/src/fgca/__tests__/preview-layout.test.ts +124 -124
- package/src/fgca/__tests__/resolver.test.ts +209 -0
- package/src/fgca/__tests__/validate.test.ts +142 -142
- package/src/fgca/chain-table.ts +225 -225
- package/src/fgca/index.ts +47 -45
- package/src/fgca/layout.ts +204 -204
- package/src/fgca/nodeTypes.ts +11 -11
- package/src/fgca/nodes/FGCAActivityNode.tsx +65 -65
- package/src/fgca/nodes/FGCAChangeNode.tsx +64 -64
- package/src/fgca/nodes/FGCAFactorNode.tsx +64 -64
- package/src/fgca/nodes/FGCAGoalNode.tsx +72 -72
- package/src/fgca/parse-canonical.ts +400 -400
- package/src/fgca/preview-layout.ts +217 -217
- package/src/fgca/resolver.ts +157 -0
- package/src/fgca/types.ts +50 -50
- package/src/fgca/validate.ts +126 -126
- package/src/geometry.ts +9 -9
- package/src/goals/__tests__/layout.test.ts +175 -175
- package/src/goals/__tests__/mutations.test.ts +111 -111
- package/src/goals/__tests__/parse-canonical.test.ts +145 -145
- package/src/goals/__tests__/validate.test.ts +202 -202
- package/src/goals/index.ts +20 -21
- package/src/goals/layout.ts +172 -172
- package/src/goals/mutations.ts +123 -123
- package/src/goals/parse-canonical.ts +286 -286
- package/src/goals/types.ts +85 -85
- package/src/goals/validate.ts +136 -136
- package/src/index.ts +28 -23
- package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -320
- package/src/process-blueprint/__tests__/layout.test.ts +240 -195
- package/src/process-blueprint/__tests__/validate.test.ts +310 -310
- package/src/process-blueprint/index.ts +31 -31
- package/src/process-blueprint/layout.ts +535 -531
- package/src/process-blueprint/types.ts +263 -242
- package/src/process-blueprint/validate.ts +181 -181
- package/src/process-map/__tests__/validate.test.ts +223 -223
- package/src/process-map/index.ts +10 -10
- package/src/process-map/types.ts +36 -36
- package/src/process-map/validate.ts +135 -135
- package/src/products/__tests__/validate.test.ts +239 -239
- package/src/products/index.ts +9 -9
- package/src/products/types.ts +31 -31
- package/src/products/validate.ts +112 -112
- package/src/repo-validate/__tests__/validate-repo.test.ts +149 -149
- package/src/repo-validate/index.ts +2 -2
- package/src/repo-validate/types.ts +50 -50
- package/src/repo-validate/validate-repo.ts +196 -196
- package/src/requirement/__tests__/example.test.ts +24 -24
- package/src/requirement/__tests__/validate.test.ts +96 -96
- package/src/requirement/index.ts +4 -4
- package/src/requirement/types.ts +35 -35
- package/src/requirement/validate.ts +92 -92
- package/src/scenarios/__tests__/validate.test.ts +209 -209
- package/src/scenarios/index.ts +15 -15
- package/src/scenarios/types.ts +37 -37
- package/src/scenarios/validate.ts +122 -122
- package/src/schema-version.ts +16 -16
- package/src/scope.ts +46 -46
- package/src/stakeholder/__tests__/validate.test.ts +51 -47
- package/src/stakeholder/index.ts +1 -0
- package/src/stakeholder/types.ts +7 -7
- package/src/stakeholder/validate.ts +79 -52
- package/src/target-state/__tests__/validate.test.ts +48 -27
- package/src/target-state/index.ts +2 -0
- package/src/target-state/types.ts +11 -7
- package/src/target-state/validate.ts +76 -46
- package/src/theme/index.ts +4 -4
- package/src/theme/themes.ts +237 -237
- package/src/theme/tokens.ts +133 -133
- package/src/typed-id.ts +56 -56
- package/src/validation-types.ts +36 -36
- package/src/webview/__tests__/entry-notations.test.ts +77 -77
- package/src/webview/__tests__/entry.test.ts +64 -64
- package/src/webview/__tests__/render-goals.test.ts +72 -72
- package/src/webview/entry.ts +292 -292
- package/src/webview/render-activities.ts +5 -3
- package/src/webview/render-activity-card.ts +266 -234
- package/src/webview/render-fgca.ts +6 -5
- package/src/webview/render-goals.ts +111 -110
- package/src/webview/render-process-blueprint.ts +207 -207
- package/src/webview/styles.css +322 -323
- package/src/yaml-normalize.ts +56 -56
- package/dist/element-envelope.d.ts +0 -15
- package/dist/element-envelope.js +0 -55
- package/dist/issues/__tests__/layout.test.js +0 -62
- package/dist/issues/__tests__/validate.test.d.ts +0 -1
- package/dist/issues/__tests__/validate.test.js +0 -82
- package/dist/issues/index.d.ts +0 -4
- package/dist/issues/index.js +0 -2
- package/dist/issues/layout.d.ts +0 -10
- package/dist/issues/layout.js +0 -82
- package/dist/issues/types.d.ts +0 -61
- package/dist/issues/types.js +0 -6
- package/dist/issues/validate.d.ts +0 -3
- package/dist/issues/validate.js +0 -143
- package/dist/webview/transitrix-render.css +0 -323
- package/dist/webview/transitrix-render.js +0 -6452
- package/dist/webview/transitrix-render.js.map +0 -7
- package/src/element-envelope.ts +0 -76
- /package/dist/{issues/__tests__/layout.test.d.ts → fgca/__tests__/resolver.test.d.ts} +0 -0
package/dist/factor/types.d.ts
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import type { GateChecks } from '../requirement/types.js';
|
|
2
|
-
/** Optional subtype — internal/external organisation force. */
|
|
3
2
|
export type FactorType = 'external' | 'internal';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export type FactorCategory = 'political' | 'economic' | 'social' | 'technological' | 'legal' | 'environmental';
|
|
8
|
-
export declare const FACTOR_CATEGORIES: readonly ["political", "economic", "social", "technological", "legal", "environmental"];
|
|
3
|
+
/** PESTLE sub-classification — external factors only (§7.1). */
|
|
4
|
+
export declare const FACTOR_PESTLE_CATEGORIES: readonly ["political", "economic", "social", "technological", "legal", "environmental"];
|
|
5
|
+
export type FactorPestleCategory = typeof FACTOR_PESTLE_CATEGORIES[number];
|
|
9
6
|
export interface Factor {
|
|
10
7
|
notation: 'factor';
|
|
11
8
|
id: string;
|
|
12
9
|
name: string;
|
|
13
10
|
type?: FactorType;
|
|
14
|
-
category?:
|
|
11
|
+
category?: FactorPestleCategory;
|
|
15
12
|
description?: string;
|
|
16
13
|
references_constraint?: string[];
|
|
17
14
|
zone: 'canon';
|
package/dist/factor/types.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
// FACTOR — motivation-layer
|
|
2
|
-
// Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.1
|
|
3
|
-
|
|
4
|
-
export const
|
|
5
|
-
'political',
|
|
1
|
+
// FACTOR — motivation-layer Driver (ArchiMate).
|
|
2
|
+
// Schema: methodology notations/ELEMENT_PRIMITIVES.md §7.1.
|
|
3
|
+
/** PESTLE sub-classification — external factors only (§7.1). */
|
|
4
|
+
export const FACTOR_PESTLE_CATEGORIES = [
|
|
5
|
+
'political',
|
|
6
|
+
'economic',
|
|
7
|
+
'social',
|
|
8
|
+
'technological',
|
|
9
|
+
'legal',
|
|
10
|
+
'environmental',
|
|
6
11
|
];
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import type { ValidationResult } from '../validation-types.js';
|
|
2
|
-
|
|
2
|
+
import { type CanonCatalog } from '../typed-id.js';
|
|
3
|
+
export interface FactorValidateOptions {
|
|
4
|
+
/** When provided, enforces that each `references_constraint` id is admitted. */
|
|
5
|
+
catalog?: CanonCatalog;
|
|
6
|
+
}
|
|
7
|
+
export declare function validateFactor(input: unknown, options?: FactorValidateOptions): ValidationResult;
|
package/dist/factor/validate.js
CHANGED
|
@@ -1,66 +1,84 @@
|
|
|
1
1
|
// FACTOR validator — methodology notations/ELEMENT_PRIMITIVES.md §7.1.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
// Codes:
|
|
4
|
+
// FACTOR-001 — shape / id grammar / required envelope fields.
|
|
5
|
+
// FACTOR-002 — `type` outside {external, internal}.
|
|
6
|
+
// FACTOR-003 — `category` outside PESTLE vocabulary, or PESTLE applied to a
|
|
7
|
+
// non-external factor (PESTLE applies only to external drivers).
|
|
8
|
+
// FACTOR-004 — `references_constraint` entry malformed or wrong TYPE.
|
|
9
|
+
//
|
|
10
|
+
// `references_constraint` existence (resolves to an admitted artefact) runs
|
|
11
|
+
// only when a `CanonCatalog` is supplied; the prefix-TYPE check runs either way.
|
|
12
|
+
import { typeOfId, isCanonicalIdOfType } from '../typed-id.js';
|
|
13
|
+
import { FACTOR_PESTLE_CATEGORIES } from './types.js';
|
|
14
|
+
const REQUIRED_STRING_FIELDS = [
|
|
15
|
+
'name', 'admitted_at', 'admitted_by', 'valid_from',
|
|
16
|
+
];
|
|
17
|
+
const PESTLE = FACTOR_PESTLE_CATEGORIES;
|
|
18
|
+
export function validateFactor(input, options = {}) {
|
|
10
19
|
const errors = [];
|
|
11
20
|
const warnings = [];
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
idType: 'FACTOR',
|
|
15
|
-
code: 'FACTOR-001',
|
|
16
|
-
});
|
|
17
|
-
errors.push(...envErrors);
|
|
18
|
-
if (!record)
|
|
21
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input)) {
|
|
22
|
+
errors.push({ code: 'FACTOR-001', message: 'Factor must be a YAML mapping.' });
|
|
19
23
|
return { valid: false, errors, warnings };
|
|
20
|
-
// FACTOR-002 — type subtype enum (optional field).
|
|
21
|
-
if (record.type !== undefined && !FACTOR_TYPES.includes(record.type)) {
|
|
22
|
-
errors.push({
|
|
23
|
-
code: 'FACTOR-002',
|
|
24
|
-
message: `type "${String(record.type)}" must be one of ${FACTOR_TYPES.join(', ')}.`,
|
|
25
|
-
path: 'type',
|
|
26
|
-
});
|
|
27
24
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
const f = input;
|
|
26
|
+
// FACTOR-001 — id grammar + notation tag + envelope.
|
|
27
|
+
if (!isCanonicalIdOfType(f.id, 'FACTOR')) {
|
|
28
|
+
errors.push({ code: 'FACTOR-001', message: `id "${String(f.id)}" must match FACTOR-[<middle>-]<INTEGER>.`, path: 'id' });
|
|
29
|
+
}
|
|
30
|
+
if (f.notation !== 'factor') {
|
|
31
|
+
errors.push({ code: 'FACTOR-001', message: 'notation must be the fixed value "factor".', path: 'notation' });
|
|
32
|
+
}
|
|
33
|
+
if (f.zone !== undefined && f.zone !== 'canon') {
|
|
34
|
+
errors.push({ code: 'FACTOR-001', message: 'zone must be "canon" for a FACTOR.', path: 'zone' });
|
|
35
|
+
}
|
|
36
|
+
else if (f.zone === undefined) {
|
|
37
|
+
errors.push({ code: 'FACTOR-001', message: 'zone is required.', path: 'zone' });
|
|
38
|
+
}
|
|
39
|
+
for (const field of REQUIRED_STRING_FIELDS) {
|
|
40
|
+
const v = f[field];
|
|
41
|
+
if (typeof v !== 'string' || v.trim() === '') {
|
|
42
|
+
errors.push({ code: 'FACTOR-001', message: `${field} is required.`, path: field });
|
|
36
43
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
}
|
|
45
|
+
if (f.gate_checks === null || typeof f.gate_checks !== 'object') {
|
|
46
|
+
errors.push({ code: 'FACTOR-001', message: 'gate_checks is required and must be a mapping.', path: 'gate_checks' });
|
|
47
|
+
}
|
|
48
|
+
if (!('valid_to' in f) || !(typeof f.valid_to === 'string' || f.valid_to === null)) {
|
|
49
|
+
errors.push({ code: 'FACTOR-001', message: 'valid_to is required (an ISO date string or null).', path: 'valid_to' });
|
|
50
|
+
}
|
|
51
|
+
// FACTOR-002 — type enum (optional field; only check when present).
|
|
52
|
+
if (f.type !== undefined && f.type !== 'external' && f.type !== 'internal') {
|
|
53
|
+
errors.push({ code: 'FACTOR-002', message: `type "${String(f.type)}" must be one of external, internal.`, path: 'type' });
|
|
54
|
+
}
|
|
55
|
+
// FACTOR-003 — category PESTLE vocabulary + external-only constraint.
|
|
56
|
+
if (f.category !== undefined) {
|
|
57
|
+
if (typeof f.category !== 'string' || !PESTLE.includes(f.category)) {
|
|
58
|
+
errors.push({ code: 'FACTOR-003', message: `category "${String(f.category)}" must be one of ${PESTLE.join(', ')}.`, path: 'category' });
|
|
59
|
+
}
|
|
60
|
+
else if (f.type === 'internal') {
|
|
61
|
+
errors.push({ code: 'FACTOR-003', message: 'category is PESTLE — applies only to external factors; omit on internal factors.', path: 'category' });
|
|
44
62
|
}
|
|
45
63
|
}
|
|
46
|
-
// FACTOR-
|
|
47
|
-
if (
|
|
48
|
-
if (!Array.isArray(
|
|
49
|
-
errors.push({
|
|
50
|
-
code: 'FACTOR-001',
|
|
51
|
-
message: 'references_constraint must be a list of typed CONSTRAINT IDs.',
|
|
52
|
-
path: 'references_constraint',
|
|
53
|
-
});
|
|
64
|
+
// FACTOR-004 — references_constraint refs.
|
|
65
|
+
if (f.references_constraint !== undefined) {
|
|
66
|
+
if (!Array.isArray(f.references_constraint)) {
|
|
67
|
+
errors.push({ code: 'FACTOR-001', message: 'references_constraint must be a list of typed IDs.', path: 'references_constraint' });
|
|
54
68
|
}
|
|
55
69
|
else {
|
|
56
|
-
|
|
70
|
+
f.references_constraint.forEach((ref, i) => {
|
|
57
71
|
const type = typeOfId(ref);
|
|
72
|
+
if (!type) {
|
|
73
|
+
errors.push({ code: 'FACTOR-004', message: `references_constraint[${i}] "${String(ref)}" is not a resolvable typed ID.`, path: `references_constraint[${i}]` });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
58
76
|
if (type !== 'CONSTRAINT') {
|
|
59
|
-
errors.push({
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
77
|
+
errors.push({ code: 'FACTOR-004', message: `references_constraint[${i}] TYPE "${type}" must be CONSTRAINT.`, path: `references_constraint[${i}]` });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (options.catalog && options.catalog.typeOf(ref) === undefined) {
|
|
81
|
+
errors.push({ code: 'FACTOR-004', message: `references_constraint[${i}] "${String(ref)}" does not resolve to an admitted artefact.`, path: `references_constraint[${i}]` });
|
|
64
82
|
}
|
|
65
83
|
});
|
|
66
84
|
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import yaml from 'js-yaml';
|
|
5
|
+
import { resolveFGCA, isFGCAViewDoc } from '../resolver.js';
|
|
6
|
+
import { parseCanonicalFGCA } from '../parse-canonical.js';
|
|
7
|
+
// ── Inline canon element store (mirrors strategy-2026 data split into per-element form) ─
|
|
8
|
+
const ELEMENTS = [
|
|
9
|
+
{ notation: 'factor', id: 'FACTOR-1', name: 'Competitive market pressure', type: 'external' },
|
|
10
|
+
{ notation: 'factor', id: 'FACTOR-2', name: 'Digital adoption acceleration', type: 'external' },
|
|
11
|
+
{ notation: 'goal', id: 'GOAL-1', name: 'Grow revenue by 20%', factors: ['FACTOR-1', 'FACTOR-2'] },
|
|
12
|
+
{ notation: 'goal', id: 'GOAL-2', name: 'Reduce operational costs', factors: ['FACTOR-2'] },
|
|
13
|
+
{ notation: 'goal', id: 'GOAL-3', name: 'Improve customer retention', factors: ['FACTOR-1'] },
|
|
14
|
+
{ notation: 'change', id: 'CHANGE-1', name: 'Launch new product line', goals: ['GOAL-1'] },
|
|
15
|
+
{ notation: 'change', id: 'CHANGE-2', name: 'Automate manual processes', goals: ['GOAL-2'] },
|
|
16
|
+
{ notation: 'change', id: 'CHANGE-3', name: 'Enhance support platform', goals: ['GOAL-3'] },
|
|
17
|
+
{ notation: 'activity', id: 'ACTIVITY-1', name: 'Market research', changes: ['CHANGE-1'] },
|
|
18
|
+
{ notation: 'activity', id: 'ACTIVITY-2', name: 'MVP development', changes: ['CHANGE-1'] },
|
|
19
|
+
{ notation: 'activity', id: 'ACTIVITY-3', name: 'Process audit', changes: ['CHANGE-2'] },
|
|
20
|
+
{ notation: 'activity', id: 'ACTIVITY-4', name: 'RPA tooling rollout', changes: ['CHANGE-2'] },
|
|
21
|
+
{ notation: 'activity', id: 'ACTIVITY-5', name: 'CRM implementation', changes: ['CHANGE-3'] },
|
|
22
|
+
];
|
|
23
|
+
const SOURCES = { elements: ELEMENTS, relations: [] };
|
|
24
|
+
const VIEW_DOC = {
|
|
25
|
+
notation: 'fgca',
|
|
26
|
+
id: 'FGCA-STRAT-1',
|
|
27
|
+
name: 'Strategy 2026 — FGCA chain',
|
|
28
|
+
spec_version: '0.1',
|
|
29
|
+
view_config: {
|
|
30
|
+
goals: { filter: 'all' },
|
|
31
|
+
factors: { surface: 'derived' },
|
|
32
|
+
changes: { surface: 'derived' },
|
|
33
|
+
activities: { surface: 'derived' },
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
// ── isFGCAViewDoc ─────────────────────────────────────────────────────────────
|
|
37
|
+
describe('isFGCAViewDoc', () => {
|
|
38
|
+
it('returns true for a view_config-based doc', () => {
|
|
39
|
+
expect(isFGCAViewDoc(VIEW_DOC)).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
it('returns false for an inline doc with factors/goals arrays', () => {
|
|
42
|
+
expect(isFGCAViewDoc({
|
|
43
|
+
notation: 'fgca', id: 'FGCA-1', name: 'x',
|
|
44
|
+
factors: [], goals: [], changes: [], activities: [],
|
|
45
|
+
})).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
it('returns false for non-objects', () => {
|
|
48
|
+
expect(isFGCAViewDoc(null)).toBe(false);
|
|
49
|
+
expect(isFGCAViewDoc('string')).toBe(false);
|
|
50
|
+
expect(isFGCAViewDoc(42)).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
// ── resolveFGCA — goals.filter=all (default) ──────────────────────────────────
|
|
54
|
+
describe('resolveFGCA — goals.filter=all', () => {
|
|
55
|
+
it('includes all goals, changes, and activities', () => {
|
|
56
|
+
const doc = resolveFGCA(VIEW_DOC, SOURCES);
|
|
57
|
+
expect(doc['goals'].length).toBe(3);
|
|
58
|
+
expect(doc['changes'].length).toBe(3);
|
|
59
|
+
expect(doc['activities'].length).toBe(5);
|
|
60
|
+
});
|
|
61
|
+
it('derives factors from all goal.factors[] refs', () => {
|
|
62
|
+
const doc = resolveFGCA(VIEW_DOC, SOURCES);
|
|
63
|
+
const factorIds = doc['factors'].map((f) => f.id);
|
|
64
|
+
expect(factorIds).toContain('FACTOR-1');
|
|
65
|
+
expect(factorIds).toContain('FACTOR-2');
|
|
66
|
+
expect(factorIds.length).toBe(2);
|
|
67
|
+
});
|
|
68
|
+
it('passes parseCanonicalFGCA and produces a fully valid internal doc', () => {
|
|
69
|
+
const doc = resolveFGCA(VIEW_DOC, SOURCES);
|
|
70
|
+
const r = parseCanonicalFGCA(doc);
|
|
71
|
+
expect(r.valid).toBe(true);
|
|
72
|
+
expect(r.errors).toEqual([]);
|
|
73
|
+
expect(r.parsed?.goals).toHaveLength(3);
|
|
74
|
+
expect(r.parsed?.factors).toHaveLength(2);
|
|
75
|
+
expect(r.parsed?.changes).toHaveLength(3);
|
|
76
|
+
expect(r.parsed?.activities).toHaveLength(5);
|
|
77
|
+
});
|
|
78
|
+
it('carries view doc metadata (id, name, spec_version)', () => {
|
|
79
|
+
const doc = resolveFGCA(VIEW_DOC, SOURCES);
|
|
80
|
+
expect(doc['notation']).toBe('fgca');
|
|
81
|
+
expect(doc['id']).toBe('FGCA-STRAT-1');
|
|
82
|
+
expect(doc['name']).toBe('Strategy 2026 — FGCA chain');
|
|
83
|
+
expect(doc['spec_version']).toBe('0.1');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
// ── resolveFGCA — goals.filter=ids ────────────────────────────────────────────
|
|
87
|
+
describe('resolveFGCA — goals.filter=ids', () => {
|
|
88
|
+
it('narrows to the specified goal and its derived changes + activities', () => {
|
|
89
|
+
const viewDoc = {
|
|
90
|
+
...VIEW_DOC,
|
|
91
|
+
view_config: { goals: { filter: 'ids', ids: ['GOAL-1'] }, factors: { surface: 'derived' }, changes: { surface: 'derived' }, activities: { surface: 'derived' } },
|
|
92
|
+
};
|
|
93
|
+
const doc = resolveFGCA(viewDoc, SOURCES);
|
|
94
|
+
const goalIds = doc['goals'].map((g) => g.id);
|
|
95
|
+
expect(goalIds).toEqual(['GOAL-1']);
|
|
96
|
+
const changeIds = doc['changes'].map((c) => c.id);
|
|
97
|
+
expect(changeIds).toEqual(['CHANGE-1']);
|
|
98
|
+
const actIds = doc['activities'].map((a) => a.id).sort();
|
|
99
|
+
expect(actIds).toEqual(['ACTIVITY-1', 'ACTIVITY-2']);
|
|
100
|
+
const r = parseCanonicalFGCA(doc);
|
|
101
|
+
expect(r.valid).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
it('returns empty arrays when none of the requested ids exist in canon', () => {
|
|
104
|
+
const viewDoc = {
|
|
105
|
+
...VIEW_DOC,
|
|
106
|
+
view_config: { goals: { filter: 'ids', ids: ['GOAL-NONEXISTENT-1'] }, factors: { surface: 'derived' }, changes: { surface: 'derived' }, activities: { surface: 'derived' } },
|
|
107
|
+
};
|
|
108
|
+
const doc = resolveFGCA(viewDoc, SOURCES);
|
|
109
|
+
expect(doc['goals'].length).toBe(0);
|
|
110
|
+
expect(doc['changes'].length).toBe(0);
|
|
111
|
+
expect(doc['factors'].length).toBe(0);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
// ── resolveFGCA — surface=all ─────────────────────────────────────────────────
|
|
115
|
+
describe('resolveFGCA — surface=all', () => {
|
|
116
|
+
it('factors.surface=all includes every factor even when only some are referenced', () => {
|
|
117
|
+
const viewDoc = {
|
|
118
|
+
...VIEW_DOC,
|
|
119
|
+
view_config: { goals: { filter: 'ids', ids: ['GOAL-3'] }, factors: { surface: 'all' }, changes: { surface: 'derived' }, activities: { surface: 'derived' } },
|
|
120
|
+
};
|
|
121
|
+
const doc = resolveFGCA(viewDoc, SOURCES);
|
|
122
|
+
// GOAL-3 only references FACTOR-1, but surface=all → both factors
|
|
123
|
+
expect(doc['factors'].length).toBe(2);
|
|
124
|
+
});
|
|
125
|
+
it('changes.surface=all includes every change', () => {
|
|
126
|
+
const viewDoc = {
|
|
127
|
+
...VIEW_DOC,
|
|
128
|
+
view_config: { goals: { filter: 'ids', ids: ['GOAL-1'] }, factors: { surface: 'derived' }, changes: { surface: 'all' }, activities: { surface: 'derived' } },
|
|
129
|
+
};
|
|
130
|
+
const doc = resolveFGCA(viewDoc, SOURCES);
|
|
131
|
+
expect(doc['changes'].length).toBe(3);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
// ── resolveFGCA — empty / degenerate inputs ───────────────────────────────────
|
|
135
|
+
describe('resolveFGCA — empty sources', () => {
|
|
136
|
+
it('returns empty arrays when canon has no elements', () => {
|
|
137
|
+
const doc = resolveFGCA(VIEW_DOC, { elements: [], relations: [] });
|
|
138
|
+
expect(doc['goals'].length).toBe(0);
|
|
139
|
+
expect(doc['factors'].length).toBe(0);
|
|
140
|
+
expect(doc['changes'].length).toBe(0);
|
|
141
|
+
expect(doc['activities'].length).toBe(0);
|
|
142
|
+
});
|
|
143
|
+
it('returns empty arrays for a non-object viewDoc', () => {
|
|
144
|
+
const doc = resolveFGCA(null, SOURCES);
|
|
145
|
+
expect(doc['goals'].length).toBe(0);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
// ── File-based regression — resolver + canon fixture + parseCanonicalFGCA ─────
|
|
149
|
+
describe('resolveFGCA — file-based regression against canon fixture', () => {
|
|
150
|
+
const CANON_ROOT = path.resolve(process.cwd(), '..', '..', 'tests', 'fixtures', 'notation-corpus', 'fgca', 'canon');
|
|
151
|
+
const VIEW_DIR = path.join(CANON_ROOT, 'views');
|
|
152
|
+
const ELEM_DIR = path.join(CANON_ROOT, 'elements');
|
|
153
|
+
function loadYamlsUnder(dir) {
|
|
154
|
+
if (!fs.existsSync(dir))
|
|
155
|
+
return [];
|
|
156
|
+
const out = [];
|
|
157
|
+
function walk(d) {
|
|
158
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
159
|
+
const full = path.join(d, entry.name);
|
|
160
|
+
if (entry.isDirectory()) {
|
|
161
|
+
walk(full);
|
|
162
|
+
}
|
|
163
|
+
else if (entry.name.endsWith('.yaml')) {
|
|
164
|
+
out.push(yaml.load(fs.readFileSync(full, 'utf8')));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
walk(dir);
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
const viewFiles = fs.existsSync(VIEW_DIR)
|
|
172
|
+
? fs.readdirSync(VIEW_DIR).filter((f) => f.endsWith('.transitrix.yaml'))
|
|
173
|
+
: [];
|
|
174
|
+
for (const file of viewFiles) {
|
|
175
|
+
it(`resolves ${file} against canon fixtures and passes parseCanonicalFGCA`, () => {
|
|
176
|
+
const viewDoc = yaml.load(fs.readFileSync(path.join(VIEW_DIR, file), 'utf8'));
|
|
177
|
+
expect(isFGCAViewDoc(viewDoc)).toBe(true);
|
|
178
|
+
const elements = loadYamlsUnder(ELEM_DIR);
|
|
179
|
+
const doc = resolveFGCA(viewDoc, { elements, relations: [] });
|
|
180
|
+
const r = parseCanonicalFGCA(doc);
|
|
181
|
+
expect(r.valid).toBe(true);
|
|
182
|
+
expect(r.errors).toEqual([]);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|
package/dist/fgca/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export { validateFGCADoc } from "./validate";
|
|
|
8
8
|
export type { FGCADoc, FGCAValidationResult, FGCAValidationError, FGCAValidationWarning } from "./validate";
|
|
9
9
|
export { ALL_FGCA_COLUMNS, FGCA_COLUMN_LABELS, } from "./types";
|
|
10
10
|
export type { FactorItem, GoalItem, BdnChangeWithActivities, ActivityItem, ActivityTypeItem, DiagramStyle, FGCAColumn, } from "./types";
|
|
11
|
+
export { resolveFGCA, isFGCAViewDoc } from './resolver.js';
|
|
12
|
+
export type { FGCAViewConfig, FGCACanonSources } from './resolver.js';
|
|
11
13
|
export { default as FGCAFactorNode } from "./nodes/FGCAFactorNode";
|
|
12
14
|
export { default as FGCAGoalNode } from "./nodes/FGCAGoalNode";
|
|
13
15
|
export { default as FGCAChangeNode } from "./nodes/FGCAChangeNode";
|
package/dist/fgca/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { layoutFGCAPreview, selectScopedFGCA, FGCA_NODE_W, FGCA_NODE_H, FGCA_HEA
|
|
|
3
3
|
export { buildChainTable } from "./chain-table";
|
|
4
4
|
export { validateFGCADoc } from "./validate";
|
|
5
5
|
export { ALL_FGCA_COLUMNS, FGCA_COLUMN_LABELS, } from "./types";
|
|
6
|
+
export { resolveFGCA, isFGCAViewDoc } from './resolver.js';
|
|
6
7
|
export { default as FGCAFactorNode } from "./nodes/FGCAFactorNode";
|
|
7
8
|
export { default as FGCAGoalNode } from "./nodes/FGCAGoalNode";
|
|
8
9
|
export { default as FGCAChangeNode } from "./nodes/FGCAChangeNode";
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FGCA canon resolver — assembles a flat canonical FGCA document from a
|
|
3
|
+
* view_config projection and a canon element/relation store (VP-3).
|
|
4
|
+
*
|
|
5
|
+
* Output shape matches the flat form that `parseCanonicalFGCA` expects:
|
|
6
|
+
* top-level `factors[]`, `goals[]`, `changes[]`, `activities[]` with typed
|
|
7
|
+
* string IDs. Filesystem-free — callable from unit tests without vscode.
|
|
8
|
+
*/
|
|
9
|
+
export interface FGCAViewConfig {
|
|
10
|
+
goals?: {
|
|
11
|
+
filter?: 'all' | 'ids' | 'tags';
|
|
12
|
+
ids?: string[];
|
|
13
|
+
tags?: string[];
|
|
14
|
+
};
|
|
15
|
+
factors?: {
|
|
16
|
+
surface?: 'derived' | 'all';
|
|
17
|
+
};
|
|
18
|
+
changes?: {
|
|
19
|
+
surface?: 'derived' | 'all';
|
|
20
|
+
};
|
|
21
|
+
activities?: {
|
|
22
|
+
surface?: 'derived' | 'all';
|
|
23
|
+
};
|
|
24
|
+
display?: {
|
|
25
|
+
depth?: number | null;
|
|
26
|
+
collapsed?: string[];
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export interface FGCACanonSources {
|
|
30
|
+
elements: unknown[];
|
|
31
|
+
relations: unknown[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Returns true when the parsed view document uses the canon-projection form
|
|
35
|
+
* (`view_config` key present, no inline `factors[]` / `goals[]` arrays).
|
|
36
|
+
* Used by the preview to decide whether to run the resolver or fall back to
|
|
37
|
+
* direct `parseCanonicalFGCA` on the inline document.
|
|
38
|
+
*/
|
|
39
|
+
export declare function isFGCAViewDoc(parsed: unknown): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Assemble a flat canonical FGCA document from the canon element store,
|
|
42
|
+
* filtered by the view document's `view_config`. The return value is ready
|
|
43
|
+
* to pass to `parseCanonicalFGCA`.
|
|
44
|
+
*
|
|
45
|
+
* Cross-reference fields (`goal.factors[]`, `change.goals[]`,
|
|
46
|
+
* `activity.changes[]`) are carried from the canon elements unchanged; the
|
|
47
|
+
* resolver decides which elements to include, not how they are shaped.
|
|
48
|
+
*/
|
|
49
|
+
export declare function resolveFGCA(viewDoc: unknown, sources: FGCACanonSources): Record<string, unknown>;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FGCA canon resolver — assembles a flat canonical FGCA document from a
|
|
3
|
+
* view_config projection and a canon element/relation store (VP-3).
|
|
4
|
+
*
|
|
5
|
+
* Output shape matches the flat form that `parseCanonicalFGCA` expects:
|
|
6
|
+
* top-level `factors[]`, `goals[]`, `changes[]`, `activities[]` with typed
|
|
7
|
+
* string IDs. Filesystem-free — callable from unit tests without vscode.
|
|
8
|
+
*/
|
|
9
|
+
function isObject(v) {
|
|
10
|
+
return !!v && typeof v === 'object' && !Array.isArray(v);
|
|
11
|
+
}
|
|
12
|
+
function str(v) {
|
|
13
|
+
return typeof v === 'string' && v.trim().length > 0 ? v : undefined;
|
|
14
|
+
}
|
|
15
|
+
function strArray(v) {
|
|
16
|
+
if (!Array.isArray(v))
|
|
17
|
+
return [];
|
|
18
|
+
return v.filter((x) => typeof x === 'string' && x.trim().length > 0);
|
|
19
|
+
}
|
|
20
|
+
function collectByNotation(docs, notation) {
|
|
21
|
+
const out = new Map();
|
|
22
|
+
for (const doc of docs) {
|
|
23
|
+
if (!isObject(doc))
|
|
24
|
+
continue;
|
|
25
|
+
if (str(doc['notation']) !== notation)
|
|
26
|
+
continue;
|
|
27
|
+
const id = str(doc['id']);
|
|
28
|
+
if (!id)
|
|
29
|
+
continue;
|
|
30
|
+
if (!out.has(id))
|
|
31
|
+
out.set(id, doc);
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Returns true when the parsed view document uses the canon-projection form
|
|
37
|
+
* (`view_config` key present, no inline `factors[]` / `goals[]` arrays).
|
|
38
|
+
* Used by the preview to decide whether to run the resolver or fall back to
|
|
39
|
+
* direct `parseCanonicalFGCA` on the inline document.
|
|
40
|
+
*/
|
|
41
|
+
export function isFGCAViewDoc(parsed) {
|
|
42
|
+
if (!isObject(parsed))
|
|
43
|
+
return false;
|
|
44
|
+
return 'view_config' in parsed && !('factors' in parsed) && !('goals' in parsed);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Assemble a flat canonical FGCA document from the canon element store,
|
|
48
|
+
* filtered by the view document's `view_config`. The return value is ready
|
|
49
|
+
* to pass to `parseCanonicalFGCA`.
|
|
50
|
+
*
|
|
51
|
+
* Cross-reference fields (`goal.factors[]`, `change.goals[]`,
|
|
52
|
+
* `activity.changes[]`) are carried from the canon elements unchanged; the
|
|
53
|
+
* resolver decides which elements to include, not how they are shaped.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveFGCA(viewDoc, sources) {
|
|
56
|
+
if (!isObject(viewDoc)) {
|
|
57
|
+
return { notation: 'fgca', factors: [], goals: [], changes: [], activities: [] };
|
|
58
|
+
}
|
|
59
|
+
const vc = isObject(viewDoc['view_config']) ? viewDoc['view_config'] : {};
|
|
60
|
+
const goalsConf = isObject(vc['goals']) ? vc['goals'] : {};
|
|
61
|
+
const factorsConf = isObject(vc['factors']) ? vc['factors'] : {};
|
|
62
|
+
const changesConf = isObject(vc['changes']) ? vc['changes'] : {};
|
|
63
|
+
const activitiesConf = isObject(vc['activities']) ? vc['activities'] : {};
|
|
64
|
+
const factorElems = collectByNotation(sources.elements, 'factor');
|
|
65
|
+
const goalElems = collectByNotation(sources.elements, 'goal');
|
|
66
|
+
const changeElems = collectByNotation(sources.elements, 'change');
|
|
67
|
+
const activityElems = collectByNotation(sources.elements, 'activity');
|
|
68
|
+
// 1. Select goal set
|
|
69
|
+
const goalsFilter = str(goalsConf['filter']) ?? 'all';
|
|
70
|
+
let selectedGoals;
|
|
71
|
+
if (goalsFilter === 'ids') {
|
|
72
|
+
const ids = strArray(goalsConf['ids']);
|
|
73
|
+
selectedGoals = ids.flatMap((id) => { const g = goalElems.get(id); return g ? [g] : []; });
|
|
74
|
+
}
|
|
75
|
+
else if (goalsFilter === 'tags') {
|
|
76
|
+
const tags = strArray(goalsConf['tags']);
|
|
77
|
+
selectedGoals = [...goalElems.values()].filter((g) => strArray(g['tags']).some((t) => tags.includes(t)));
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// 'all' — include every goal element in the canon store
|
|
81
|
+
selectedGoals = [...goalElems.values()];
|
|
82
|
+
}
|
|
83
|
+
const selectedGoalIds = new Set(selectedGoals.map((g) => str(g['id'])).filter((x) => x !== undefined));
|
|
84
|
+
// 2. Select factors: derived follows goal.factors[]; all = every factor
|
|
85
|
+
let selectedFactors;
|
|
86
|
+
if (str(factorsConf['surface']) === 'all') {
|
|
87
|
+
selectedFactors = [...factorElems.values()];
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const refIds = new Set();
|
|
91
|
+
for (const g of selectedGoals)
|
|
92
|
+
for (const fid of strArray(g['factors']))
|
|
93
|
+
refIds.add(fid);
|
|
94
|
+
selectedFactors = [...refIds].flatMap((id) => { const f = factorElems.get(id); return f ? [f] : []; });
|
|
95
|
+
}
|
|
96
|
+
// 3. Select changes: derived = changes referencing ≥1 selected goal
|
|
97
|
+
let selectedChanges;
|
|
98
|
+
if (str(changesConf['surface']) === 'all') {
|
|
99
|
+
selectedChanges = [...changeElems.values()];
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
selectedChanges = [...changeElems.values()].filter((c) => strArray(c['goals']).some((gid) => selectedGoalIds.has(gid)));
|
|
103
|
+
}
|
|
104
|
+
const selectedChangeIds = new Set(selectedChanges.map((c) => str(c['id'])).filter((x) => x !== undefined));
|
|
105
|
+
// 4. Select activities: derived = reference ≥1 selected change or goal (degenerate FGA link)
|
|
106
|
+
let selectedActivities;
|
|
107
|
+
if (str(activitiesConf['surface']) === 'all') {
|
|
108
|
+
selectedActivities = [...activityElems.values()];
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
selectedActivities = [...activityElems.values()].filter((a) => strArray(a['changes']).some((cid) => selectedChangeIds.has(cid)) ||
|
|
112
|
+
strArray(a['goals']).some((gid) => selectedGoalIds.has(gid)));
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
notation: 'fgca',
|
|
116
|
+
id: viewDoc['id'],
|
|
117
|
+
name: viewDoc['name'],
|
|
118
|
+
spec_version: viewDoc['spec_version'],
|
|
119
|
+
factors: selectedFactors,
|
|
120
|
+
goals: selectedGoals,
|
|
121
|
+
changes: selectedChanges,
|
|
122
|
+
activities: selectedActivities,
|
|
123
|
+
};
|
|
124
|
+
}
|
package/dist/goals/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { Goal, GoalType, GoalTree,
|
|
1
|
+
export type { Goal, GoalType, GoalTree, ImpactType, ValidationResult, ValidationError, ValidationWarning, MutationResult, LayoutOptions, LaidOutNode, LaidOutEdge, GoalTreeLayout, } from './types.js';
|
|
2
2
|
export { validateGoalTree } from './validate.js';
|
|
3
3
|
export { parseCanonicalGoals } from './parse-canonical.js';
|
|
4
4
|
export type { CanonicalGoalsResult } from './parse-canonical.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export * from "./activities/index";
|
|
2
2
|
export * from "./activity-card/index";
|
|
3
|
+
export * from "./actor/index";
|
|
3
4
|
export * from "./geometry";
|
|
4
5
|
export * from "./applications/index";
|
|
5
6
|
export * from "./assertion/index";
|
|
6
7
|
export * from "./blocks/index";
|
|
7
8
|
export * from "./capability-map/index";
|
|
9
|
+
export * from "./change/index";
|
|
8
10
|
export * from "./compliance/index";
|
|
9
11
|
export * from "./compliance-matrix/index";
|
|
10
12
|
export * from "./confidence/index";
|
|
13
|
+
export * from "./factor/index";
|
|
11
14
|
export * from "./fgca/index";
|
|
12
15
|
export * from "./goals/index";
|
|
13
16
|
export * from "./process-blueprint/index";
|
|
@@ -16,6 +19,8 @@ export * from "./products/index";
|
|
|
16
19
|
export * from "./repo-validate/index";
|
|
17
20
|
export * from "./requirement/index";
|
|
18
21
|
export * from "./scenarios/index";
|
|
22
|
+
export * from "./stakeholder/index";
|
|
23
|
+
export * from "./target-state/index";
|
|
19
24
|
export { SCHEMA_VERSION } from "./schema-version";
|
|
20
25
|
export * from "./theme/index";
|
|
21
26
|
export * from "./typed-id";
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export * from "./activities/index";
|
|
2
2
|
export * from "./activity-card/index";
|
|
3
|
+
export * from "./actor/index";
|
|
3
4
|
export * from "./geometry";
|
|
4
5
|
export * from "./applications/index";
|
|
5
6
|
export * from "./assertion/index";
|
|
6
7
|
export * from "./blocks/index";
|
|
7
8
|
export * from "./capability-map/index";
|
|
9
|
+
export * from "./change/index";
|
|
8
10
|
export * from "./compliance/index";
|
|
9
11
|
export * from "./compliance-matrix/index";
|
|
10
12
|
export * from "./confidence/index";
|
|
13
|
+
export * from "./factor/index";
|
|
11
14
|
export * from "./fgca/index";
|
|
12
15
|
export * from "./goals/index";
|
|
13
16
|
export * from "./process-blueprint/index";
|
|
@@ -16,6 +19,8 @@ export * from "./products/index";
|
|
|
16
19
|
export * from "./repo-validate/index";
|
|
17
20
|
export * from "./requirement/index";
|
|
18
21
|
export * from "./scenarios/index";
|
|
22
|
+
export * from "./stakeholder/index";
|
|
23
|
+
export * from "./target-state/index";
|
|
19
24
|
export { SCHEMA_VERSION } from "./schema-version";
|
|
20
25
|
export * from "./theme/index";
|
|
21
26
|
export * from "./typed-id";
|