yarramate 0.21.0 → 0.22.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/visual-graph-entry.d.ts +1 -0
- package/dist/adapters/visual-graph-entry.js +1 -0
- package/dist/compiler.d.ts +1 -19
- package/dist/compiler.js +2 -35
- package/dist/graph-claims.d.ts +18 -0
- package/dist/graph-claims.js +35 -0
- package/dist/graph-projection.d.ts +4 -3
- package/dist/graph-projection.js +1 -1
- package/dist/notation/archimate.d.ts +71 -0
- package/dist/notation/archimate.js +183 -0
- package/dist/visual-app/assets/index-CRd1Khma.js +354 -0
- package/dist/visual-app/index.html +1 -1
- package/docs/CONSUMING-YARRAMATE.md +26 -1
- package/package.json +9 -1
- package/schema/yarramate-visual-graph.schema.json +27 -2
- package/dist/visual-app/assets/index-CAnZh3Hx.js +0 -354
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { projectGraphForCanvas, type CanvasGraph, type CanvasNode, type CanvasEdge, } from '../graph-projection.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { projectGraphForCanvas, } from '../graph-projection.js';
|
package/dist/compiler.d.ts
CHANGED
|
@@ -108,24 +108,7 @@ export type IncrementalCompilationResult = ({
|
|
|
108
108
|
readonly incremental: boolean;
|
|
109
109
|
readonly cache: CompilationCache;
|
|
110
110
|
};
|
|
111
|
-
export
|
|
112
|
-
export declare const attestationClaimValue: (attestation: {
|
|
113
|
-
readonly by: string;
|
|
114
|
-
readonly on: string;
|
|
115
|
-
readonly recordedBy?: string;
|
|
116
|
-
}) => string;
|
|
117
|
-
export interface AttestationClaimParts {
|
|
118
|
-
readonly by: string;
|
|
119
|
-
readonly on: string;
|
|
120
|
-
readonly recordedBy?: string;
|
|
121
|
-
}
|
|
122
|
-
export declare const parseAttestationClaimValue: (value: string) => AttestationClaimParts | undefined;
|
|
123
|
-
export interface ConstraintExpectsParts {
|
|
124
|
-
readonly provider: string;
|
|
125
|
-
readonly key: string;
|
|
126
|
-
readonly value: string;
|
|
127
|
-
}
|
|
128
|
-
export declare const parseConstraintExpectsValue: (value: string) => ConstraintExpectsParts | undefined;
|
|
111
|
+
export { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue, parseAttestationClaimValue, parseConstraintExpectsValue, type AttestationClaimParts, type ConstraintExpectsParts, } from './graph-claims.js';
|
|
129
112
|
interface ResolvedPosition {
|
|
130
113
|
readonly line: number;
|
|
131
114
|
readonly col: number;
|
|
@@ -142,4 +125,3 @@ export declare const compileWorkspaceWithProfileContext: (sources: readonly Work
|
|
|
142
125
|
* composed value per current source and drops sources that left the workspace.
|
|
143
126
|
*/
|
|
144
127
|
export declare const compileWorkspaceIncremental: (sources: readonly WorkspaceSource[], previous?: CompilationCache) => IncrementalCompilationResult;
|
|
145
|
-
export {};
|
package/dist/compiler.js
CHANGED
|
@@ -6,6 +6,7 @@ import documentSchema from '../schema/yarramate-document.schema.json' with { typ
|
|
|
6
6
|
};
|
|
7
7
|
import profileSchema from '../schema/yarramate-profile.schema.json' with { type: 'json'
|
|
8
8
|
};
|
|
9
|
+
import { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue } from './graph-claims.js';
|
|
9
10
|
const coreProfile = 'yarramate/core@0.1';
|
|
10
11
|
const require = createRequire(import.meta.url);
|
|
11
12
|
const ajv2020Module = require('ajv/dist/2020.js');
|
|
@@ -39,41 +40,7 @@ const presenceClaimId = (subject, state) => `${subject}~present-in-${Buffer.from
|
|
|
39
40
|
const aliasClaimId = (subject, alias) => `${subject}~alias-${Buffer.from(alias, 'utf8').toString('hex')}`;
|
|
40
41
|
const distinctFromClaimId = (subject, other) => `${subject}~distinct-from-${Buffer.from(other, 'utf8').toString('hex')}`;
|
|
41
42
|
const supersedesClaimId = (subject, predecessor) => `${subject}~supersedes-${Buffer.from(predecessor, 'utf8').toString('hex')}`;
|
|
42
|
-
export
|
|
43
|
-
// An attestation claim packs the authority, the date it was given, and
|
|
44
|
-
// the recorder when a machine held the pen. A reference carries no
|
|
45
|
-
// spaces and the date is fixed width, so the three parse back out of one
|
|
46
|
-
// value unambiguously wherever a reader needs them.
|
|
47
|
-
export const attestationClaimValue = (attestation) => attestation.recordedBy === undefined
|
|
48
|
-
? `${attestation.by} ${attestation.on}`
|
|
49
|
-
: `${attestation.by} ${attestation.on} ${attestation.recordedBy}`;
|
|
50
|
-
export const parseAttestationClaimValue = (value) => {
|
|
51
|
-
const match = /^(\S+) ([0-9]{4}-[0-9]{2}-[0-9]{2})(?: (.+))?$/.exec(value);
|
|
52
|
-
if (match === null)
|
|
53
|
-
return undefined;
|
|
54
|
-
const recordedBy = match[3];
|
|
55
|
-
return {
|
|
56
|
-
by: match[1],
|
|
57
|
-
on: match[2],
|
|
58
|
-
...(recordedBy === undefined ? {} : { recordedBy }),
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
// Mirrors the compiler's own write-side encoding (ADR 0075): provider and
|
|
62
|
-
// key admit no whitespace, so the first two spaces delimit them and
|
|
63
|
-
// everything after the second space is the expected value verbatim, spaces
|
|
64
|
-
// included. This is the sole authority for decoding the value written at
|
|
65
|
-
// the constraint's `expects` claim — reconciliation.ts delegates here
|
|
66
|
-
// rather than mirroring the regex itself.
|
|
67
|
-
export const parseConstraintExpectsValue = (value) => {
|
|
68
|
-
const match = /^(\S+) (\S+) ([\s\S]+)$/.exec(value);
|
|
69
|
-
if (match === null)
|
|
70
|
-
return undefined;
|
|
71
|
-
return {
|
|
72
|
-
provider: match[1],
|
|
73
|
-
key: match[2],
|
|
74
|
-
value: match[3],
|
|
75
|
-
};
|
|
76
|
-
};
|
|
43
|
+
export { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue, parseAttestationClaimValue, parseConstraintExpectsValue, } from './graph-claims.js';
|
|
77
44
|
const describeAspect = (aspect) => aspect.replace('-', ' ');
|
|
78
45
|
// Candidate order is the policy-matrix declaration order: the resolved kind
|
|
79
46
|
// map inserts core policies first, then extension kinds as declared.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const ATTESTATION_PREDICATE_PREFIX = "yarramate/attestation/";
|
|
2
|
+
export declare const attestationClaimValue: (attestation: {
|
|
3
|
+
readonly by: string;
|
|
4
|
+
readonly on: string;
|
|
5
|
+
readonly recordedBy?: string;
|
|
6
|
+
}) => string;
|
|
7
|
+
export interface AttestationClaimParts {
|
|
8
|
+
readonly by: string;
|
|
9
|
+
readonly on: string;
|
|
10
|
+
readonly recordedBy?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const parseAttestationClaimValue: (value: string) => AttestationClaimParts | undefined;
|
|
13
|
+
export interface ConstraintExpectsParts {
|
|
14
|
+
readonly provider: string;
|
|
15
|
+
readonly key: string;
|
|
16
|
+
readonly value: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const parseConstraintExpectsValue: (value: string) => ConstraintExpectsParts | undefined;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export const ATTESTATION_PREDICATE_PREFIX = 'yarramate/attestation/';
|
|
2
|
+
// An attestation claim packs the authority, the date it was given, and
|
|
3
|
+
// the recorder when a machine held the pen. A reference carries no
|
|
4
|
+
// spaces and the date is fixed width, so the three parse back out of one
|
|
5
|
+
// value unambiguously wherever a reader needs them.
|
|
6
|
+
export const attestationClaimValue = (attestation) => attestation.recordedBy === undefined
|
|
7
|
+
? `${attestation.by} ${attestation.on}`
|
|
8
|
+
: `${attestation.by} ${attestation.on} ${attestation.recordedBy}`;
|
|
9
|
+
export const parseAttestationClaimValue = (value) => {
|
|
10
|
+
const match = /^(\S+) ([0-9]{4}-[0-9]{2}-[0-9]{2})(?: (.+))?$/.exec(value);
|
|
11
|
+
if (match === null)
|
|
12
|
+
return undefined;
|
|
13
|
+
const recordedBy = match[3];
|
|
14
|
+
return {
|
|
15
|
+
by: match[1],
|
|
16
|
+
on: match[2],
|
|
17
|
+
...(recordedBy === undefined ? {} : { recordedBy }),
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
// Mirrors the compiler's own write-side encoding (ADR 0075): provider and
|
|
21
|
+
// key admit no whitespace, so the first two spaces delimit them and
|
|
22
|
+
// everything after the second space is the expected value verbatim, spaces
|
|
23
|
+
// included. This is the sole authority for decoding the value written at
|
|
24
|
+
// the constraint's `expects` claim — reconciliation.ts delegates here
|
|
25
|
+
// rather than mirroring the regex itself.
|
|
26
|
+
export const parseConstraintExpectsValue = (value) => {
|
|
27
|
+
const match = /^(\S+) (\S+) ([\s\S]+)$/.exec(value);
|
|
28
|
+
if (match === null)
|
|
29
|
+
return undefined;
|
|
30
|
+
return {
|
|
31
|
+
provider: match[1],
|
|
32
|
+
key: match[2],
|
|
33
|
+
value: match[3],
|
|
34
|
+
};
|
|
35
|
+
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ResolvedProfileContext, SemanticGraph } from './compiler.js';
|
|
2
|
+
import type { Aspect, Layer } from './profile.js';
|
|
2
3
|
export interface CanvasNode {
|
|
3
4
|
readonly id: string;
|
|
4
5
|
readonly localId: string;
|
|
5
6
|
readonly document: string;
|
|
6
7
|
readonly kind: string;
|
|
7
8
|
readonly kindLabel: string;
|
|
8
|
-
readonly layer:
|
|
9
|
-
readonly aspect:
|
|
9
|
+
readonly layer: Layer | null;
|
|
10
|
+
readonly aspect: Aspect | null;
|
|
10
11
|
readonly name: string;
|
|
11
12
|
readonly description: string | null;
|
|
12
13
|
readonly aka: readonly string[];
|
package/dist/graph-projection.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ATTESTATION_PREDICATE_PREFIX, parseAttestationClaimValue, parseConstraintExpectsValue, } from './
|
|
1
|
+
import { ATTESTATION_PREDICATE_PREFIX, parseAttestationClaimValue, parseConstraintExpectsValue, } from './graph-claims.js';
|
|
2
2
|
import { kindLabelOf } from './kind-label.js';
|
|
3
3
|
const CONCEPT_KIND_PREDICATE = 'yarramate/concept/kind';
|
|
4
4
|
const CONCEPT_NAME_PREDICATE = 'yarramate/concept/name';
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { layers, type Aspect, type Layer, type RelationshipKind } from '../profile.js';
|
|
2
|
+
export declare const ICON_SIZE = 14;
|
|
3
|
+
export declare const LAYER_COLORS: {
|
|
4
|
+
readonly motivation: {
|
|
5
|
+
readonly fill: '#CCCCFF';
|
|
6
|
+
readonly border: '#8F8FE0';
|
|
7
|
+
};
|
|
8
|
+
readonly strategy: {
|
|
9
|
+
readonly fill: '#F5DEAA';
|
|
10
|
+
readonly border: '#C9A355';
|
|
11
|
+
};
|
|
12
|
+
readonly business: {
|
|
13
|
+
readonly fill: '#FFFF99';
|
|
14
|
+
readonly border: '#C9C355';
|
|
15
|
+
};
|
|
16
|
+
readonly application: {
|
|
17
|
+
readonly fill: '#CCFFFF';
|
|
18
|
+
readonly border: '#4FB8B8';
|
|
19
|
+
};
|
|
20
|
+
readonly technology: {
|
|
21
|
+
readonly fill: '#CCFFCC';
|
|
22
|
+
readonly border: '#5FAE5F';
|
|
23
|
+
};
|
|
24
|
+
readonly implementation: {
|
|
25
|
+
readonly fill: '#FFE0E0';
|
|
26
|
+
readonly border: '#D89999';
|
|
27
|
+
};
|
|
28
|
+
readonly physical: {
|
|
29
|
+
readonly fill: '#F0F0F0';
|
|
30
|
+
readonly border: '#999999';
|
|
31
|
+
};
|
|
32
|
+
readonly composite: {
|
|
33
|
+
readonly fill: '#F0F0F0';
|
|
34
|
+
readonly border: '#999999';
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export interface ShapeMeta {
|
|
38
|
+
readonly shape: 'rectangle' | 'round-rectangle' | 'octagon';
|
|
39
|
+
/** Passive-structure's ArchiMate header-stripe convention. */
|
|
40
|
+
readonly accent?: 'top-band';
|
|
41
|
+
/** Composite (grouping/location/junction) convention. */
|
|
42
|
+
readonly borderStyle?: 'dashed';
|
|
43
|
+
}
|
|
44
|
+
export declare const ASPECT_SHAPES: Record<Aspect, ShapeMeta>;
|
|
45
|
+
export interface ConceptNotation extends ShapeMeta {
|
|
46
|
+
readonly id: string;
|
|
47
|
+
readonly notation: string;
|
|
48
|
+
readonly layer: Layer;
|
|
49
|
+
readonly aspect: Aspect;
|
|
50
|
+
readonly glyph: string | null;
|
|
51
|
+
readonly colors: {
|
|
52
|
+
readonly fill: string;
|
|
53
|
+
readonly border: string;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export declare const CONCEPT_NOTATION: readonly ConceptNotation[];
|
|
57
|
+
export declare function conceptNotationOf(kindLabel: string): ConceptNotation | null;
|
|
58
|
+
export declare function kindGlyphDataUriOf(kindLabel: string): string | null;
|
|
59
|
+
export interface ArrowNotation {
|
|
60
|
+
readonly shape: 'none' | 'diamond' | 'triangle' | 'circle' | 'vee';
|
|
61
|
+
readonly fill?: 'filled' | 'hollow';
|
|
62
|
+
}
|
|
63
|
+
export interface RelationshipNotation {
|
|
64
|
+
readonly id: RelationshipKind;
|
|
65
|
+
readonly lineStyle: 'solid' | 'dotted' | 'dashed';
|
|
66
|
+
readonly sourceArrow: ArrowNotation;
|
|
67
|
+
readonly targetArrow: ArrowNotation;
|
|
68
|
+
}
|
|
69
|
+
export declare const RELATIONSHIP_NOTATION: readonly RelationshipNotation[];
|
|
70
|
+
export declare function relationshipNotationOf(kindLabel: string): RelationshipNotation | null;
|
|
71
|
+
export { layers };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
// Single source of truth for ArchiMate-inspired rendering data: layer
|
|
2
|
+
// palette, aspect-driven shape tokens, per-concept-kind glyphs, and
|
|
3
|
+
// per-relationship-kind line/arrow styles. Pure data + lookups, no
|
|
4
|
+
// cytoscape/DOM dependency - the same zero-import discipline as
|
|
5
|
+
// `src/visual-app/kind-icons.ts` and `badges.ts`, so this module can be
|
|
6
|
+
// published standalone (`yarramate/notation/archimate`) and consumed by
|
|
7
|
+
// non-canvas renderers. Not wired into `graph-canvas.tsx` yet (Task 4
|
|
8
|
+
// switches the canvas to read from here instead of its own inline tables).
|
|
9
|
+
import { conceptKinds, layers, relationshipKinds } from '../profile.js';
|
|
10
|
+
export const ICON_SIZE = 14;
|
|
11
|
+
const INK = '#182228'; // --ink (src/visual-app/styles.css:12)
|
|
12
|
+
// The locked canvas layer palette (`graph-canvas.tsx`'s `LAYER_COLORS`
|
|
13
|
+
// selectors) - `physical` and `composite` deliberately share the same
|
|
14
|
+
// neutral grey since neither carries a distinct layer identity of its own.
|
|
15
|
+
export const LAYER_COLORS = {
|
|
16
|
+
motivation: { fill: '#CCCCFF', border: '#8F8FE0' },
|
|
17
|
+
strategy: { fill: '#F5DEAA', border: '#C9A355' },
|
|
18
|
+
business: { fill: '#FFFF99', border: '#C9C355' },
|
|
19
|
+
application: { fill: '#CCFFFF', border: '#4FB8B8' },
|
|
20
|
+
technology: { fill: '#CCFFCC', border: '#5FAE5F' },
|
|
21
|
+
implementation: { fill: '#FFE0E0', border: '#D89999' },
|
|
22
|
+
physical: { fill: '#F0F0F0', border: '#999999' },
|
|
23
|
+
composite: { fill: '#F0F0F0', border: '#999999' },
|
|
24
|
+
};
|
|
25
|
+
// Aspect -> shape/accent/borderStyle, mirroring `graph-canvas.tsx`'s
|
|
26
|
+
// `node[aspect = "…"]` selectors (Task 8/11 ArchiMate notation mode).
|
|
27
|
+
export const ASPECT_SHAPES = {
|
|
28
|
+
motivation: { shape: 'octagon' },
|
|
29
|
+
'active-structure': { shape: 'rectangle' },
|
|
30
|
+
behavior: { shape: 'round-rectangle' },
|
|
31
|
+
'passive-structure': { shape: 'rectangle', accent: 'top-band' },
|
|
32
|
+
composite: { shape: 'rectangle', borderStyle: 'dashed' },
|
|
33
|
+
};
|
|
34
|
+
function svg(body) {
|
|
35
|
+
return (`<svg xmlns="http://www.w3.org/2000/svg" width="${ICON_SIZE}" height="${ICON_SIZE}" ` +
|
|
36
|
+
`viewBox="0 0 ${ICON_SIZE} ${ICON_SIZE}">` +
|
|
37
|
+
`<g fill="none" stroke="${INK}" stroke-width="1" stroke-linecap="round" stroke-linejoin="round">${body}</g>` +
|
|
38
|
+
`</svg>`);
|
|
39
|
+
}
|
|
40
|
+
function toDataUri(svgMarkup) {
|
|
41
|
+
return `data:image/svg+xml;utf8,${encodeURIComponent(svgMarkup)}`;
|
|
42
|
+
}
|
|
43
|
+
// The 17 kinds the canvas already draws a glyph for (`src/visual-app/
|
|
44
|
+
// kind-icons.ts` `BASE_KIND_SVG`), copied verbatim. Every other core kind
|
|
45
|
+
// (e.g. `stakeholder`) has no glyph body and resolves to `null` below -
|
|
46
|
+
// that's an allowed gap, not a coverage failure: `CONCEPT_NOTATION` still
|
|
47
|
+
// carries a row for it, just with `glyph: null`.
|
|
48
|
+
const BASE_KIND_SVG = {
|
|
49
|
+
// Component: UML/ArchiMate component box with two connector notches on
|
|
50
|
+
// its left edge.
|
|
51
|
+
applicationComponent: '<rect x="3" y="2" width="9" height="10"/>' +
|
|
52
|
+
'<rect x="1" y="4" width="2.5" height="1.5"/>' +
|
|
53
|
+
'<rect x="1" y="8" width="2.5" height="1.5"/>',
|
|
54
|
+
// Function: rounded process box with a right-pointing chevron.
|
|
55
|
+
applicationFunction: '<rect x="2" y="3" width="10" height="8" rx="2"/><path d="M5.5 5 L8 7 L5.5 9"/>',
|
|
56
|
+
// Service: a pill/oval, ArchiMate's rounded-rectangle service shape.
|
|
57
|
+
applicationService: '<rect x="1.5" y="4" width="11" height="6" rx="3"/>',
|
|
58
|
+
// Artifact: a document with a folded top-right corner.
|
|
59
|
+
artifact: '<path d="M3 1.5 H9 L11 3.5 V12.5 H3 Z"/><path d="M9 1.5 V3.5 H11"/>',
|
|
60
|
+
// Actor: a stick figure - head, torso, arms, legs.
|
|
61
|
+
businessActor: '<circle cx="7" cy="3.5" r="1.8"/><path d="M7 5.3 V9 M4 7 H10 M7 9 L4.5 12.5 M7 9 L9.5 12.5"/>',
|
|
62
|
+
// Function: same process-box convention as applicationFunction, an
|
|
63
|
+
// upward chevron distinguishes the business layer.
|
|
64
|
+
businessFunction: '<rect x="2" y="3" width="10" height="8" rx="2"/><path d="M5 8 L7 5.5 L9 8"/>',
|
|
65
|
+
// Capability: a box with a compass-style arrow toward its top-right
|
|
66
|
+
// corner (capability-as-direction motif).
|
|
67
|
+
capability: '<rect x="2" y="2" width="10" height="10" rx="1"/><path d="M5 9 L9 5 M9 5 H6.5 M9 5 V7.5"/>',
|
|
68
|
+
// Data object: a record box with a header divider.
|
|
69
|
+
dataObject: '<rect x="2" y="2" width="10" height="10"/><path d="M2 5.5 H12"/>',
|
|
70
|
+
// Deliverable: a folded-corner document (like artifact) with a ribbon
|
|
71
|
+
// check-mark distinguishing it as a completed output.
|
|
72
|
+
deliverable: '<path d="M3 1.5 H8 L11 4.5 V12.5 H3 Z"/><path d="M8 1.5 V4.5 H11"/><path d="M5 9.5 L7 12.5 L9 9.5"/>',
|
|
73
|
+
// Driver: a steering-wheel motif - a circle with four radiating spokes.
|
|
74
|
+
driver: '<circle cx="7" cy="7" r="5"/><path d="M7 2 V5 M7 9 V12 M2 7 H5 M9 7 H12"/>',
|
|
75
|
+
// Goal: a target - two concentric circles.
|
|
76
|
+
goal: '<circle cx="7" cy="7" r="5"/><circle cx="7" cy="7" r="2.2"/>',
|
|
77
|
+
// Node: a 3D cuboid, ArchiMate's technology-node glyph.
|
|
78
|
+
node: '<path d="M2 5 L7 2.5 L12 5 L12 10 L7 12.5 L2 10 Z"/><path d="M2 5 L7 7.5 L12 5 M7 7.5 V12.5"/>',
|
|
79
|
+
// Plateau: a flat-topped trapezoid.
|
|
80
|
+
plateau: '<path d="M2 11 L4.5 4 H9.5 L12 11 Z"/><path d="M2 11 H12"/>',
|
|
81
|
+
// Representation: a document with a wavy bottom edge (curled paper).
|
|
82
|
+
representation: '<path d="M3 2 H11 V9 Q9.5 11 8 9.5 Q6.5 8 5 9.5 Q3.5 11 3 9 Z"/>',
|
|
83
|
+
// Requirement: a pointed banner/shield shape with a header divider.
|
|
84
|
+
requirement: '<path d="M3 2.5 H11 V9 L7 11.5 L3 9 Z"/><path d="M3 5 H11"/>',
|
|
85
|
+
// System software: a nested box, a smaller box docked inside the larger.
|
|
86
|
+
systemSoftware: '<rect x="2" y="2" width="10" height="10"/><rect x="4" y="4" width="4" height="3"/>',
|
|
87
|
+
// Function: same process convention again, technology layer gets a gear
|
|
88
|
+
// motif - a circle with radiating teeth.
|
|
89
|
+
technologyFunction: '<circle cx="7" cy="7" r="4"/>' +
|
|
90
|
+
'<path d="M7 2 V3.2 M7 10.8 V12 M2 7 H3.2 M10.8 7 H12 ' +
|
|
91
|
+
'M3.5 3.5 L4.3 4.3 M9.7 9.7 L10.5 10.5 M3.5 10.5 L4.3 9.7 M9.7 4.3 L10.5 3.5"/>',
|
|
92
|
+
};
|
|
93
|
+
// Built from `conceptKinds` (not enumerated by hand) so coverage cannot
|
|
94
|
+
// drift from the core vocabulary - a new kind added to `profile.ts` gets a
|
|
95
|
+
// notation row automatically, and a removed one disappears automatically.
|
|
96
|
+
export const CONCEPT_NOTATION = conceptKinds.map((kind) => ({
|
|
97
|
+
id: kind.id,
|
|
98
|
+
notation: kind.name,
|
|
99
|
+
layer: kind.layer,
|
|
100
|
+
aspect: kind.aspect,
|
|
101
|
+
...ASPECT_SHAPES[kind.aspect],
|
|
102
|
+
glyph: BASE_KIND_SVG[kind.id] ?? null,
|
|
103
|
+
colors: LAYER_COLORS[kind.layer],
|
|
104
|
+
}));
|
|
105
|
+
const CONCEPT_NOTATION_BY_ID = Object.fromEntries(CONCEPT_NOTATION.map((row) => [row.id, row]));
|
|
106
|
+
export function conceptNotationOf(kindLabel) {
|
|
107
|
+
return CONCEPT_NOTATION_BY_ID[kindLabel] ?? null;
|
|
108
|
+
}
|
|
109
|
+
export function kindGlyphDataUriOf(kindLabel) {
|
|
110
|
+
const glyph = CONCEPT_NOTATION_BY_ID[kindLabel]?.glyph;
|
|
111
|
+
return glyph == null ? null : toDataUri(svg(glyph));
|
|
112
|
+
}
|
|
113
|
+
// The 11 rows from `graph-canvas.tsx`'s ArchiMate edge selectors (Task 11).
|
|
114
|
+
const RELATIONSHIP_STYLE = {
|
|
115
|
+
composition: {
|
|
116
|
+
lineStyle: 'solid',
|
|
117
|
+
sourceArrow: { shape: 'diamond', fill: 'filled' },
|
|
118
|
+
targetArrow: { shape: 'none' },
|
|
119
|
+
},
|
|
120
|
+
aggregation: {
|
|
121
|
+
lineStyle: 'solid',
|
|
122
|
+
sourceArrow: { shape: 'diamond', fill: 'hollow' },
|
|
123
|
+
targetArrow: { shape: 'none' },
|
|
124
|
+
},
|
|
125
|
+
assignment: {
|
|
126
|
+
lineStyle: 'solid',
|
|
127
|
+
sourceArrow: { shape: 'circle', fill: 'filled' },
|
|
128
|
+
targetArrow: { shape: 'triangle', fill: 'filled' },
|
|
129
|
+
},
|
|
130
|
+
realization: {
|
|
131
|
+
lineStyle: 'dotted',
|
|
132
|
+
sourceArrow: { shape: 'none' },
|
|
133
|
+
targetArrow: { shape: 'triangle', fill: 'hollow' },
|
|
134
|
+
},
|
|
135
|
+
specialization: {
|
|
136
|
+
lineStyle: 'solid',
|
|
137
|
+
sourceArrow: { shape: 'none' },
|
|
138
|
+
targetArrow: { shape: 'triangle', fill: 'hollow' },
|
|
139
|
+
},
|
|
140
|
+
serving: {
|
|
141
|
+
lineStyle: 'solid',
|
|
142
|
+
sourceArrow: { shape: 'none' },
|
|
143
|
+
targetArrow: { shape: 'vee' },
|
|
144
|
+
},
|
|
145
|
+
access: {
|
|
146
|
+
lineStyle: 'dotted',
|
|
147
|
+
sourceArrow: { shape: 'none' },
|
|
148
|
+
targetArrow: { shape: 'vee' },
|
|
149
|
+
},
|
|
150
|
+
influence: {
|
|
151
|
+
lineStyle: 'dashed',
|
|
152
|
+
sourceArrow: { shape: 'none' },
|
|
153
|
+
targetArrow: { shape: 'vee' },
|
|
154
|
+
},
|
|
155
|
+
triggering: {
|
|
156
|
+
lineStyle: 'solid',
|
|
157
|
+
sourceArrow: { shape: 'none' },
|
|
158
|
+
targetArrow: { shape: 'triangle', fill: 'filled' },
|
|
159
|
+
},
|
|
160
|
+
flow: {
|
|
161
|
+
lineStyle: 'dashed',
|
|
162
|
+
sourceArrow: { shape: 'none' },
|
|
163
|
+
targetArrow: { shape: 'triangle', fill: 'filled' },
|
|
164
|
+
},
|
|
165
|
+
association: {
|
|
166
|
+
lineStyle: 'solid',
|
|
167
|
+
sourceArrow: { shape: 'none' },
|
|
168
|
+
targetArrow: { shape: 'none' },
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
// Built from `relationshipKinds` so coverage cannot drift, same discipline
|
|
172
|
+
// as `CONCEPT_NOTATION` above.
|
|
173
|
+
export const RELATIONSHIP_NOTATION = relationshipKinds.map((id) => ({
|
|
174
|
+
id,
|
|
175
|
+
...RELATIONSHIP_STYLE[id],
|
|
176
|
+
}));
|
|
177
|
+
const RELATIONSHIP_NOTATION_BY_ID = Object.fromEntries(RELATIONSHIP_NOTATION.map((row) => [row.id, row]));
|
|
178
|
+
export function relationshipNotationOf(kindLabel) {
|
|
179
|
+
return RELATIONSHIP_NOTATION_BY_ID[kindLabel] ?? null;
|
|
180
|
+
}
|
|
181
|
+
// `layers` is re-exported so consumers of this subpath don't need a second
|
|
182
|
+
// import from `../profile.js` just to iterate the palette.
|
|
183
|
+
export { layers };
|