yarramate 0.15.0 → 0.16.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/adapters/graphify-entry.d.ts +1 -1
- package/dist/adapters/graphify.d.ts +5 -0
- package/dist/adapters/likec4-export.js +1 -1
- package/dist/compiler.d.ts +1 -0
- package/dist/compiler.js +33 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/projection.d.ts +8 -0
- package/dist/projection.js +68 -10
- package/package.json +1 -1
- package/schema/yarramate-profile.schema.json +16 -1
- package/schema/yarramate-projection-result.schema.json +19 -0
- package/schema/yarramate-projection.schema.json +50 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
export { observeGraphify, type
|
|
1
|
+
export { observeGraphify, type GraphifyObservationIssue, type GraphifyGraph, type GraphifyObservationResult, } from './graphify.js';
|
|
@@ -4,6 +4,11 @@ export interface GraphifyGraph {
|
|
|
4
4
|
readonly nodes: readonly {
|
|
5
5
|
readonly id: string;
|
|
6
6
|
}[];
|
|
7
|
+
readonly edges?: readonly {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly source: string;
|
|
10
|
+
readonly target: string;
|
|
11
|
+
}[];
|
|
7
12
|
}
|
|
8
13
|
export interface GraphifyObservationIssue {
|
|
9
14
|
readonly code: 'YMG101' | 'YMG102';
|
|
@@ -233,6 +233,6 @@ export function exportLikeC4(projection, mapping, kindMapping, options = {}) {
|
|
|
233
233
|
return [` style ${external} { color amber }`];
|
|
234
234
|
}
|
|
235
235
|
return [];
|
|
236
|
-
})),
|
|
236
|
+
})), ` autoLayout ${projection.presentation?.direction === 'top-down' ? 'TopBottom' : 'LeftRight'}`, ' }', '}', '');
|
|
237
237
|
return { ok: true, source: lines.join('\n') };
|
|
238
238
|
}
|
package/dist/compiler.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export interface SemanticGraph {
|
|
|
46
46
|
export interface ResolvedProfileContext {
|
|
47
47
|
readonly conceptKindLineages: ReadonlyMap<string, readonly string[]>;
|
|
48
48
|
readonly relationshipKindLineages: ReadonlyMap<string, readonly string[]>;
|
|
49
|
+
readonly conceptKindLayers: ReadonlyMap<string, string>;
|
|
49
50
|
}
|
|
50
51
|
export type CompilationResult = {
|
|
51
52
|
readonly ok: true;
|
package/dist/compiler.js
CHANGED
|
@@ -10,6 +10,24 @@ const coreProfile = 'yarramate/core@0.1';
|
|
|
10
10
|
const Ajv2020 = Ajv2020Module.default;
|
|
11
11
|
const validateDocument = new Ajv2020({ allErrors: true }).compile(documentSchema);
|
|
12
12
|
const validateProfile = new Ajv2020({ allErrors: true }).compile(profileSchema);
|
|
13
|
+
const immutableMap = (entries) => {
|
|
14
|
+
const backing = new Map(entries);
|
|
15
|
+
const facade = {
|
|
16
|
+
get: backing.get.bind(backing),
|
|
17
|
+
has: backing.has.bind(backing),
|
|
18
|
+
forEach(callback, thisArg) {
|
|
19
|
+
backing.forEach((value, key) => callback.call(thisArg, value, key, facade));
|
|
20
|
+
},
|
|
21
|
+
entries: backing.entries.bind(backing),
|
|
22
|
+
keys: backing.keys.bind(backing),
|
|
23
|
+
values: backing.values.bind(backing),
|
|
24
|
+
[Symbol.iterator]: backing[Symbol.iterator].bind(backing),
|
|
25
|
+
get size() {
|
|
26
|
+
return backing.size;
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
return Object.freeze(facade);
|
|
30
|
+
};
|
|
13
31
|
const compareById = (left, right) => left.id.localeCompare(right.id);
|
|
14
32
|
const presenceClaimId = (subject, state) => `${subject}~present-in-${Buffer.from(state, 'utf8').toString('hex')}`;
|
|
15
33
|
// Alternative labels and distinctness records are unordered sets, not
|
|
@@ -64,6 +82,7 @@ function compileWorkspaceResolved(sources) {
|
|
|
64
82
|
const resolved = {
|
|
65
83
|
identity: `${coreProfile}#${kind.id}`,
|
|
66
84
|
aspect: kind.aspect,
|
|
85
|
+
layer: kind.layer,
|
|
67
86
|
lineage: [`${coreProfile}#${kind.id}`],
|
|
68
87
|
...(kind.rigidity === undefined ? {} : { rigidity: kind.rigidity }),
|
|
69
88
|
};
|
|
@@ -226,6 +245,7 @@ function compileWorkspaceResolved(sources) {
|
|
|
226
245
|
const resolved = {
|
|
227
246
|
identity: `${identity}#${kind.id}`,
|
|
228
247
|
aspect: parent.aspect,
|
|
248
|
+
layer: kind.layer ?? parent.layer,
|
|
229
249
|
lineage: [...parent.lineage, `${identity}#${kind.id}`],
|
|
230
250
|
...(kind.rigidity === undefined ? {} : { rigidity: kind.rigidity }),
|
|
231
251
|
};
|
|
@@ -1267,12 +1287,21 @@ function compileWorkspaceResolved(sources) {
|
|
|
1267
1287
|
return {
|
|
1268
1288
|
ok: true,
|
|
1269
1289
|
profileContext: {
|
|
1270
|
-
conceptKindLineages:
|
|
1290
|
+
conceptKindLineages: immutableMap([...conceptKindByIdentity]
|
|
1271
1291
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
1272
|
-
.map(([identity, kind]) => [
|
|
1273
|
-
|
|
1292
|
+
.map(([identity, kind]) => [
|
|
1293
|
+
identity,
|
|
1294
|
+
Object.freeze([...kind.lineage]),
|
|
1295
|
+
])),
|
|
1296
|
+
relationshipKindLineages: immutableMap([...relationshipKindByIdentity]
|
|
1297
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
1298
|
+
.map(([identity, kind]) => [
|
|
1299
|
+
identity,
|
|
1300
|
+
Object.freeze([...kind.lineage]),
|
|
1301
|
+
])),
|
|
1302
|
+
conceptKindLayers: immutableMap([...conceptKindByIdentity]
|
|
1274
1303
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
1275
|
-
.map(([identity, kind]) => [identity, kind.
|
|
1304
|
+
.map(([identity, kind]) => [identity, kind.layer])),
|
|
1276
1305
|
},
|
|
1277
1306
|
graph: {
|
|
1278
1307
|
format: 'yarramate/graph/v2',
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,6 @@ export { constraintExpectsPredicate, reconcileEvidenceReports, type AssertedRela
|
|
|
8
8
|
export { deriveAttestationStaleness } from './attestation-staleness.js';
|
|
9
9
|
export { buildRtm, renderRtmMarkdown, type RequirementsTraceabilityMatrix, type RtmAttestation, type RtmContextEntry, type RtmDescopedEntry, type RtmEvidenceVerdict, type RtmLineageEntry, type RtmRealizer, type RtmRow, type RtmSource, } from './rtm.js';
|
|
10
10
|
export type { CompilationResult, ContextualCompilationResult, Diagnostic, GraphClaim, GraphSource, SemanticGraph, ResolvedProfileContext, WorkspaceSource, } from './compiler.js';
|
|
11
|
-
export { evaluateProjection, loadProjection, renderProjectionMarkdown, } from './projection.js';
|
|
11
|
+
export { canonicalProjection, evaluateProjection, loadProjection, renderProjectionMarkdown, } from './projection.js';
|
|
12
12
|
export { loadAdapterMapping, validateAdapterMapping, validateAdapterMappings, type AdapterMapping, type AdapterMappingLoadResult, type AdapterMappingValidationResult, type AdapterMappingsValidationResult, type AdapterSubjectMapping, } from './adapter-mapping.js';
|
|
13
13
|
export type { LifecycleStatus, ProjectionDefinition, ProjectionLoadResult, ProjectionResult, } from './projection.js';
|
package/dist/index.js
CHANGED
|
@@ -7,5 +7,5 @@ export { evaluateEvidence, evaluateEvidenceWorkspace, loadEvidence, } from './ev
|
|
|
7
7
|
export { constraintExpectsPredicate, reconcileEvidenceReports, } from './reconciliation.js';
|
|
8
8
|
export { deriveAttestationStaleness } from './attestation-staleness.js';
|
|
9
9
|
export { buildRtm, renderRtmMarkdown, } from './rtm.js';
|
|
10
|
-
export { evaluateProjection, loadProjection, renderProjectionMarkdown, } from './projection.js';
|
|
10
|
+
export { canonicalProjection, evaluateProjection, loadProjection, renderProjectionMarkdown, } from './projection.js';
|
|
11
11
|
export { loadAdapterMapping, validateAdapterMapping, validateAdapterMappings, } from './adapter-mapping.js';
|
package/dist/projection.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface ProjectionDefinition {
|
|
|
8
8
|
readonly subjects?: readonly string[];
|
|
9
9
|
readonly documents?: readonly string[];
|
|
10
10
|
readonly kinds?: readonly string[];
|
|
11
|
+
readonly layers?: readonly string[];
|
|
11
12
|
readonly statuses?: readonly LifecycleStatus[];
|
|
12
13
|
readonly excludeStatuses?: readonly LifecycleStatus[];
|
|
13
14
|
readonly states?: readonly string[];
|
|
@@ -21,6 +22,12 @@ export interface ProjectionDefinition {
|
|
|
21
22
|
readonly presentation?: {
|
|
22
23
|
readonly title?: string;
|
|
23
24
|
readonly description?: string;
|
|
25
|
+
readonly layout?: 'layered' | 'radial' | 'force';
|
|
26
|
+
readonly direction?: 'top-down' | 'left-right';
|
|
27
|
+
readonly seed?: string;
|
|
28
|
+
readonly showLifecycle?: boolean;
|
|
29
|
+
readonly showEvidence?: boolean;
|
|
30
|
+
readonly showOwnership?: boolean;
|
|
24
31
|
};
|
|
25
32
|
}
|
|
26
33
|
export interface ProjectionResult {
|
|
@@ -39,6 +46,7 @@ export type ProjectionLoadResult = {
|
|
|
39
46
|
readonly diagnostics: readonly Diagnostic[];
|
|
40
47
|
};
|
|
41
48
|
export declare function loadProjection(source: WorkspaceSource): ProjectionLoadResult;
|
|
49
|
+
export declare function canonicalProjection(projection: ProjectionDefinition): ProjectionDefinition;
|
|
42
50
|
export declare function evaluateProjection(graph: SemanticGraph, projection: ProjectionDefinition, profileContext?: ResolvedProfileContext): ProjectionResult;
|
|
43
51
|
export declare function renderProjectionMarkdown(result: ProjectionResult, profileContext?: ResolvedProfileContext): string;
|
|
44
52
|
export declare function renderBudgetedContext(result: ProjectionResult, budgetTokens: number): string;
|
package/dist/projection.js
CHANGED
|
@@ -11,6 +11,44 @@ export function loadProjection(source) {
|
|
|
11
11
|
? { ok: true, projection: loaded.document.value }
|
|
12
12
|
: loaded;
|
|
13
13
|
}
|
|
14
|
+
export function canonicalProjection(projection) {
|
|
15
|
+
const query = projection.query;
|
|
16
|
+
const presentation = projection.presentation;
|
|
17
|
+
return {
|
|
18
|
+
format: projection.format,
|
|
19
|
+
id: projection.id,
|
|
20
|
+
version: projection.version,
|
|
21
|
+
query: {
|
|
22
|
+
...(query.subjects === undefined ? {} : { subjects: [...query.subjects].sort() }),
|
|
23
|
+
...(query.documents === undefined ? {} : { documents: [...query.documents].sort() }),
|
|
24
|
+
...(query.kinds === undefined ? {} : { kinds: [...query.kinds].sort() }),
|
|
25
|
+
...(query.layers === undefined ? {} : { layers: [...query.layers].sort() }),
|
|
26
|
+
...(query.statuses === undefined ? {} : { statuses: [...query.statuses].sort() }),
|
|
27
|
+
...(query.excludeStatuses === undefined ? {} : { excludeStatuses: [...query.excludeStatuses].sort() }),
|
|
28
|
+
...(query.states === undefined ? {} : { states: [...query.states].sort() }),
|
|
29
|
+
...(query.owners === undefined ? {} : { owners: [...query.owners].sort() }),
|
|
30
|
+
...(query.constraints === undefined ? {} : { constraints: [...query.constraints].sort() }),
|
|
31
|
+
...(query.relationshipKinds === undefined ? {} : { relationshipKinds: [...query.relationshipKinds].sort() }),
|
|
32
|
+
...(query.kindMatching === undefined ? {} : { kindMatching: query.kindMatching }),
|
|
33
|
+
...(query.relationships === undefined ? {} : { relationships: query.relationships }),
|
|
34
|
+
...(query.isolatedConcepts === undefined ? {} : { isolatedConcepts: query.isolatedConcepts }),
|
|
35
|
+
},
|
|
36
|
+
...(presentation === undefined
|
|
37
|
+
? {}
|
|
38
|
+
: {
|
|
39
|
+
presentation: {
|
|
40
|
+
...(presentation.title === undefined ? {} : { title: presentation.title }),
|
|
41
|
+
...(presentation.description === undefined ? {} : { description: presentation.description }),
|
|
42
|
+
...(presentation.layout === undefined ? {} : { layout: presentation.layout }),
|
|
43
|
+
...(presentation.direction === undefined ? {} : { direction: presentation.direction }),
|
|
44
|
+
...(presentation.seed === undefined ? {} : { seed: presentation.seed }),
|
|
45
|
+
...(presentation.showLifecycle === undefined ? {} : { showLifecycle: presentation.showLifecycle }),
|
|
46
|
+
...(presentation.showEvidence === undefined ? {} : { showEvidence: presentation.showEvidence }),
|
|
47
|
+
...(presentation.showOwnership === undefined ? {} : { showOwnership: presentation.showOwnership }),
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
14
52
|
const claimValue = (claims, subject, predicate) => {
|
|
15
53
|
const object = claims.find((claim) => claim.subject === subject && claim.predicate === predicate)?.object;
|
|
16
54
|
return object !== undefined && 'value' in object ? object.value : undefined;
|
|
@@ -40,6 +78,14 @@ export function evaluateProjection(graph, projection, profileContext) {
|
|
|
40
78
|
return (presence.length === 0 ||
|
|
41
79
|
presence.some((state) => selectedStateIds.includes(state)));
|
|
42
80
|
};
|
|
81
|
+
const endpointExcluded = (id) => {
|
|
82
|
+
if (!participatesInSelectedState(id))
|
|
83
|
+
return true;
|
|
84
|
+
const status = claimValue(graph.claims, id, 'yarramate/lifecycle/status');
|
|
85
|
+
return (status !== undefined &&
|
|
86
|
+
projection.query.excludeStatuses?.includes(status) ===
|
|
87
|
+
true);
|
|
88
|
+
};
|
|
43
89
|
const initiallySelectedConceptIds = new Set(graph.subjects
|
|
44
90
|
.filter(({ type }) => type === 'concept')
|
|
45
91
|
.filter(({ id }) => {
|
|
@@ -62,6 +108,10 @@ export function evaluateProjection(graph, projection, profileContext) {
|
|
|
62
108
|
profileContext?.conceptKindLineages
|
|
63
109
|
.get(kind)
|
|
64
110
|
?.includes(selectedKind) === true)))) &&
|
|
111
|
+
(projection.query.layers === undefined ||
|
|
112
|
+
(kind !== undefined &&
|
|
113
|
+
profileContext?.conceptKindLayers.get(kind) !== undefined &&
|
|
114
|
+
projection.query.layers.includes(profileContext.conceptKindLayers.get(kind)))) &&
|
|
65
115
|
(projection.query.statuses === undefined ||
|
|
66
116
|
(status !== undefined &&
|
|
67
117
|
projection.query.statuses.includes(status))) &&
|
|
@@ -100,16 +150,6 @@ export function evaluateProjection(graph, projection, profileContext) {
|
|
|
100
150
|
}
|
|
101
151
|
const sourceSelected = initiallySelectedConceptIds.has(relationship.subject);
|
|
102
152
|
const targetSelected = initiallySelectedConceptIds.has(relationship.object.ref);
|
|
103
|
-
// excludeStatuses also vetoes connected expansion: an excluded
|
|
104
|
-
// concept is never pulled in as a neighbour, and edges touching
|
|
105
|
-
// one are dropped rather than left dangling.
|
|
106
|
-
const endpointExcluded = (id) => {
|
|
107
|
-
if (projection.query.excludeStatuses === undefined)
|
|
108
|
-
return false;
|
|
109
|
-
const endpointStatus = claimValue(graph.claims, id, 'yarramate/lifecycle/status');
|
|
110
|
-
return (endpointStatus !== undefined &&
|
|
111
|
-
projection.query.excludeStatuses.includes(endpointStatus));
|
|
112
|
-
};
|
|
113
153
|
if (endpointExcluded(relationship.subject) ||
|
|
114
154
|
endpointExcluded(relationship.object.ref)) {
|
|
115
155
|
continue;
|
|
@@ -168,6 +208,24 @@ export function evaluateProjection(graph, projection, profileContext) {
|
|
|
168
208
|
...(projection.presentation.description === undefined
|
|
169
209
|
? {}
|
|
170
210
|
: { description: projection.presentation.description }),
|
|
211
|
+
...(projection.presentation.layout === undefined
|
|
212
|
+
? {}
|
|
213
|
+
: { layout: projection.presentation.layout }),
|
|
214
|
+
...(projection.presentation.direction === undefined
|
|
215
|
+
? {}
|
|
216
|
+
: { direction: projection.presentation.direction }),
|
|
217
|
+
...(projection.presentation.seed === undefined
|
|
218
|
+
? {}
|
|
219
|
+
: { seed: projection.presentation.seed }),
|
|
220
|
+
...(projection.presentation.showLifecycle === undefined
|
|
221
|
+
? {}
|
|
222
|
+
: { showLifecycle: projection.presentation.showLifecycle }),
|
|
223
|
+
...(projection.presentation.showEvidence === undefined
|
|
224
|
+
? {}
|
|
225
|
+
: { showEvidence: projection.presentation.showEvidence }),
|
|
226
|
+
...(projection.presentation.showOwnership === undefined
|
|
227
|
+
? {}
|
|
228
|
+
: { showOwnership: projection.presentation.showOwnership }),
|
|
171
229
|
},
|
|
172
230
|
}),
|
|
173
231
|
documents: graph.documents.filter(({ id }) => selectedDocuments.has(id)),
|
package/package.json
CHANGED
|
@@ -80,6 +80,9 @@
|
|
|
80
80
|
},
|
|
81
81
|
"rigidity": {
|
|
82
82
|
"$ref": "#/$defs/rigidity"
|
|
83
|
+
},
|
|
84
|
+
"layer": {
|
|
85
|
+
"$ref": "#/$defs/layer"
|
|
83
86
|
}
|
|
84
87
|
}
|
|
85
88
|
},
|
|
@@ -115,6 +118,18 @@
|
|
|
115
118
|
}
|
|
116
119
|
}
|
|
117
120
|
}
|
|
118
|
-
}
|
|
121
|
+
},
|
|
122
|
+
"layer": {
|
|
123
|
+
"enum": [
|
|
124
|
+
"motivation",
|
|
125
|
+
"strategy",
|
|
126
|
+
"business",
|
|
127
|
+
"application",
|
|
128
|
+
"technology",
|
|
129
|
+
"physical",
|
|
130
|
+
"implementation",
|
|
131
|
+
"composite"
|
|
132
|
+
]
|
|
133
|
+
}
|
|
119
134
|
}
|
|
120
135
|
}
|
|
@@ -24,6 +24,25 @@
|
|
|
24
24
|
"description": {
|
|
25
25
|
"type": "string",
|
|
26
26
|
"minLength": 1
|
|
27
|
+
},
|
|
28
|
+
"layout": {
|
|
29
|
+
"enum": ["layered", "radial", "force"]
|
|
30
|
+
},
|
|
31
|
+
"direction": {
|
|
32
|
+
"enum": ["top-down", "left-right"]
|
|
33
|
+
},
|
|
34
|
+
"seed": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"minLength": 1
|
|
37
|
+
},
|
|
38
|
+
"showLifecycle": {
|
|
39
|
+
"type": "boolean"
|
|
40
|
+
},
|
|
41
|
+
"showEvidence": {
|
|
42
|
+
"type": "boolean"
|
|
43
|
+
},
|
|
44
|
+
"showOwnership": {
|
|
45
|
+
"type": "boolean"
|
|
27
46
|
}
|
|
28
47
|
}
|
|
29
48
|
},
|
|
@@ -42,6 +42,14 @@
|
|
|
42
42
|
"$ref": "#/$defs/qualifiedKind"
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
|
+
"layers": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"minItems": 1,
|
|
48
|
+
"uniqueItems": true,
|
|
49
|
+
"items": {
|
|
50
|
+
"$ref": "#/$defs/layer"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
45
53
|
"statuses": {
|
|
46
54
|
"type": "array",
|
|
47
55
|
"uniqueItems": true,
|
|
@@ -109,8 +117,36 @@
|
|
|
109
117
|
},
|
|
110
118
|
"description": {
|
|
111
119
|
"$ref": "#/$defs/nonEmptyText"
|
|
120
|
+
},
|
|
121
|
+
"layout": {
|
|
122
|
+
"enum": ["layered", "radial", "force"]
|
|
123
|
+
},
|
|
124
|
+
"direction": {
|
|
125
|
+
"enum": ["top-down", "left-right"]
|
|
126
|
+
},
|
|
127
|
+
"seed": {
|
|
128
|
+
"$ref": "#/$defs/nonEmptyText"
|
|
129
|
+
},
|
|
130
|
+
"showLifecycle": {
|
|
131
|
+
"type": "boolean"
|
|
132
|
+
},
|
|
133
|
+
"showEvidence": {
|
|
134
|
+
"type": "boolean"
|
|
135
|
+
},
|
|
136
|
+
"showOwnership": {
|
|
137
|
+
"type": "boolean"
|
|
112
138
|
}
|
|
113
|
-
}
|
|
139
|
+
},
|
|
140
|
+
"allOf": [
|
|
141
|
+
{
|
|
142
|
+
"if": {
|
|
143
|
+
"required": ["layout"]
|
|
144
|
+
},
|
|
145
|
+
"then": {
|
|
146
|
+
"required": ["seed"]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
]
|
|
114
150
|
}
|
|
115
151
|
},
|
|
116
152
|
"$defs": {
|
|
@@ -129,6 +165,18 @@
|
|
|
129
165
|
"nonEmptyText": {
|
|
130
166
|
"type": "string",
|
|
131
167
|
"minLength": 1
|
|
132
|
-
}
|
|
168
|
+
},
|
|
169
|
+
"layer": {
|
|
170
|
+
"enum": [
|
|
171
|
+
"motivation",
|
|
172
|
+
"strategy",
|
|
173
|
+
"business",
|
|
174
|
+
"application",
|
|
175
|
+
"technology",
|
|
176
|
+
"physical",
|
|
177
|
+
"implementation",
|
|
178
|
+
"composite"
|
|
179
|
+
]
|
|
180
|
+
}
|
|
133
181
|
}
|
|
134
182
|
}
|