@formicoidea/labre-framework-wardley 0.42.0 → 0.45.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/import.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { ConnectorMode, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model';
2
2
  import { WARDLEY_BACKGROUND } from './background.js';
3
3
  import { OWM_DEFAULT_MAP_HEIGHT, OWM_DEFAULT_MAP_WIDTH, OWM_LABEL_HEIGHT, OWM_LABEL_WIDTH, OWM_SCOPE, OWM_TAIL_ATTR, OWM_KEYWORDS, OWM_TITLE_ATTR, owmDefaultPlot, owmPointOf, WARDLEY_OWM_FORMAT_ID, } from './export.js';
4
- import { HANDLE_SIZE, LABEL_GAP, LABEL_FONT_SIZE, LINK_GREY, LINK_STROKE_WIDTH, MARKET_DOT_RING, MARKET_DOT_SIZE, MARKET_DOT_STROKE_WIDTH, MARKET_LINK_COLOR, MARKET_LINK_WIDTH, MARKET_SIZE, ECOSYSTEM_SIZE, NODE_FILL, NODE_SIZE, NODE_STROKE, NODE_STROKE_WIDTH, PIPELINE_FILL, PIPELINE_HEIGHT, WARDLEY_RED, } from './node/consts.js';
5
- import { WARDLEY_NODE_SIZE, wardleyNodeProps } from './presets.js';
4
+ import { HANDLE_SIZE, INERTIA_SIZE, LABEL_GAP, LABEL_FONT_SIZE, LINK_GREY, LINK_STROKE_WIDTH, MARKET_DOT_RING, MARKET_DOT_SIZE, MARKET_DOT_STROKE_WIDTH, MARKET_LINK_COLOR, MARKET_LINK_WIDTH, MARKET_SIZE, ECOSYSTEM_SIZE, NODE_FILL, NODE_SIZE, NODE_STROKE, NODE_STROKE_WIDTH, PIPELINE_FILL, PIPELINE_HEIGHT, WARDLEY_RED, } from './node/consts.js';
5
+ import { WARDLEY_NODE_SIZE, wardleyInertiaProps, wardleyNodeProps, } from './presets.js';
6
6
  import { WARDLEY_ROLE } from './roles.js';
7
7
  /**
8
8
  * The OWM import remarks whose wording is FIXED, as `[key, English]` pairs.
@@ -153,8 +153,6 @@ export const WARDLEY_OWM_IMPORT_REMARKS = {
153
153
  * this library does not itself write — the honest form of "a file we wrote",
154
154
  * since the format has no marker to claim one with.
155
155
  */
156
- /* ── The format, re-exported so both halves agree ─────────────────────── */
157
- export { WARDLEY_OWM_FORMAT_ID, OWM_SCOPE };
158
156
  /** The dialect this reader implements, and how a Labre-shaped file reads. */
159
157
  const OWM_DIALECT = 'DSL';
160
158
  const OWM_DIALECT_LABRE = 'DSL (Labre)';
@@ -226,8 +224,8 @@ function readName(raw) {
226
224
  * layout of our own, so an artefact this reader places without coordinates
227
225
  * lands where the tool that wrote the file would have drawn it.
228
226
  */
229
- export const OWM_DEFAULT_VISIBILITY = 0.9;
230
- export const OWM_DEFAULT_EVOLUTION = 0.1;
227
+ const OWM_DEFAULT_VISIBILITY = 0.9;
228
+ const OWM_DEFAULT_EVOLUTION = 0.1;
231
229
  /**
232
230
  * Read `[v, e]` the way `extractLocation` reads one — PER AXIS.
233
231
  *
@@ -578,6 +576,68 @@ export function importWardleyOwm(source, context = {}) {
578
576
  }
579
577
  }
580
578
  /* ── Laying it out ────────────────────────────────────────────────── */
579
+ // Where the document's residue rides: on the map, which is always first.
580
+ const mapPayload = {};
581
+ if (title !== undefined) {
582
+ mapPayload.attrs = { [OWM_SCOPE.document]: { [OWM_TITLE_ATTR]: title } };
583
+ }
584
+ if (carriedLines.length > 0) {
585
+ mapPayload.children = { [OWM_SCOPE.document]: carriedLines };
586
+ }
587
+ const elements = layoutWardleyStatements({
588
+ nodes: nodeStatements,
589
+ pipelines,
590
+ notes: noteStatements,
591
+ evolutions,
592
+ links,
593
+ inertias: [],
594
+ }, { mapPayload, onInvented: inventedNote });
595
+ /* ── The report ───────────────────────────────────────────────────── */
596
+ const mapped = (titledByFile ? 1 : 0) +
597
+ nodeStatements.length +
598
+ pipelines.length +
599
+ noteStatements.length +
600
+ evolutions.length +
601
+ links.length;
602
+ return {
603
+ elements,
604
+ report: {
605
+ mapped,
606
+ carried: carriedLines.length,
607
+ // Nothing. Every statement this format writes is a standalone sentence,
608
+ // so a carried one cannot contradict the drawing — which is what D5's
609
+ // quarantine is FOR. Stated here rather than left to be inferred from a
610
+ // zero: a format with no quarantine case is a finding about the format.
611
+ quarantined: 0,
612
+ notes,
613
+ sourceVersion: carriedLines.length === 0 && notes.length === 0
614
+ ? OWM_DIALECT_LABRE
615
+ : OWM_DIALECT,
616
+ },
617
+ };
618
+ }
619
+ /* ── Laying statements out ───────────────────────────────────────────── */
620
+ /**
621
+ * Statements as element props, on a new map at the reference size — the OWM
622
+ * reader's own layout, shared with the SVG reader (ADR 0032 §2.3) so the two
623
+ * paths draw the same elements.
624
+ *
625
+ * Every element that a later statement refers to carries its identity under
626
+ * `interchange.owm.id` (D3): the OWM reader hands that to the materializer
627
+ * as is, and the SVG reader turns it into a provisional local id and drops
628
+ * the payload, because a picture promises no round-trip.
629
+ *
630
+ * @param options.mapPayload what rides on the map element under `owm`, if
631
+ * anything.
632
+ * @param options.onInvented told of every position this layout made up.
633
+ */
634
+ export function layoutWardleyStatements(statements, options) {
635
+ const { nodes: nodeStatements, pipelines, notes: noteStatements, evolutions, links, inertias, } = statements;
636
+ const inventedNote = options.onInvented;
637
+ const mapPayload = options.mapPayload ?? {};
638
+ /** What a statement is referred to by: its id, or (OWM) its name. */
639
+ const identity = (statement) => statement.id ?? statement.name;
640
+ const declared = new Set(nodeStatements.map(identity));
581
641
  const plot = owmDefaultPlot();
582
642
  const elements = [];
583
643
  /** The place a name was declared at, for the statements that reference one. */
@@ -585,8 +645,8 @@ export function importWardleyOwm(source, context = {}) {
585
645
  for (const statement of nodeStatements) {
586
646
  // FIRST wins, matching the materializer's own rule for a duplicated name
587
647
  // and OWM's: a pipeline or an `evolve` naming it means the first one.
588
- if (!declaredAt.has(statement.name)) {
589
- declaredAt.set(statement.name, {
648
+ if (!declaredAt.has(identity(statement))) {
649
+ declaredAt.set(identity(statement), {
590
650
  visibility: statement.visibility,
591
651
  evolution: statement.evolution,
592
652
  });
@@ -604,14 +664,6 @@ export function importWardleyOwm(source, context = {}) {
604
664
  minted.add(candidate);
605
665
  return candidate;
606
666
  };
607
- /* The map itself, always first, and where the document's residue rides. */
608
- const mapPayload = {};
609
- if (title !== undefined) {
610
- mapPayload.attrs = { [OWM_SCOPE.document]: { [OWM_TITLE_ATTR]: title } };
611
- }
612
- if (carriedLines.length > 0) {
613
- mapPayload.children = { [OWM_SCOPE.document]: carriedLines };
614
- }
615
667
  elements.push({
616
668
  type: WARDLEY_BACKGROUND.type,
617
669
  role: WARDLEY_BACKGROUND.role,
@@ -624,18 +676,20 @@ export function importWardleyOwm(source, context = {}) {
624
676
  });
625
677
  for (const statement of nodeStatements) {
626
678
  const [cx, cy] = owmPointOf(plot, statement.visibility, statement.evolution);
627
- elements.push(...artefact(statement.keyword, statement.name, cx, cy, statement.tail, mintHandle));
679
+ elements.push(...artefact(statement.keyword, statement.name, identity(statement), cx, cy, statement.tail, mintHandle));
628
680
  }
629
681
  for (const pipeline of pipelines) {
630
- const at = declaredAt.get(pipeline.name);
631
- if (at === undefined) {
682
+ const standing = pipeline.top !== undefined;
683
+ const at = standing ? undefined : declaredAt.get(identity(pipeline));
684
+ if (!standing && at === undefined) {
632
685
  inventedNote('pipeline', pipeline.name, 'no component of this name is declared, so the pipeline was drawn halfway up the value chain. OWM takes a pipeline’s height from the component it belongs to.');
633
686
  }
634
- const visibility = at?.visibility ?? 0.5;
687
+ const visibility = pipeline.top ?? at?.visibility ?? 0.5;
635
688
  const [left] = owmPointOf(plot, visibility, pipeline.from);
636
689
  const [right, y] = owmPointOf(plot, visibility, pipeline.to);
637
- // Under the component it belongs to, the way OWM draws it.
638
- const top = y + NODE_SIZE;
690
+ // Under the component it belongs to, the way OWM draws it — or exactly
691
+ // where a picture drew its top edge.
692
+ const top = standing ? y : y + NODE_SIZE;
639
693
  const width = Math.max(right - left, 1);
640
694
  const centre = left + width / 2;
641
695
  elements.push({
@@ -651,7 +705,7 @@ export function importWardleyOwm(source, context = {}) {
651
705
  roughness: 0,
652
706
  radius: 0,
653
707
  xywh: `[${left},${top},${width},${PIPELINE_HEIGHT}]`,
654
- interchange: payload({ id: pipeline.name, tail: pipeline.tail }),
708
+ interchange: payload({ id: identity(pipeline), tail: pipeline.tail }),
655
709
  });
656
710
  elements.push({
657
711
  type: 'wardleyNode',
@@ -667,7 +721,7 @@ export function importWardleyOwm(source, context = {}) {
667
721
  radius: 0,
668
722
  xywh: `[${centre - HANDLE_SIZE / 2},${top - HANDLE_SIZE / 2},${HANDLE_SIZE},${HANDLE_SIZE}]`,
669
723
  interchange: payload({
670
- id: mintHandle(`${pipeline.name} handle`),
724
+ id: mintHandle(`${identity(pipeline)} handle`),
671
725
  element: 'pipeline',
672
726
  }),
673
727
  });
@@ -691,13 +745,13 @@ export function importWardleyOwm(source, context = {}) {
691
745
  /** The twin an `evolve` line draws, and the handle its arrow points at. */
692
746
  const twinHandles = [];
693
747
  for (const evolution of evolutions) {
694
- const at = declaredAt.get(evolution.name);
748
+ const at = declaredAt.get(identity(evolution));
695
749
  if (at === undefined) {
696
750
  inventedNote('evolve', evolution.name, 'no component of this name is declared, so its evolved twin was laid out halfway up the value chain. The file did not say where it sits.');
697
751
  }
698
752
  const visibility = at?.visibility ?? 0.5;
699
753
  const [cx, cy] = owmPointOf(plot, visibility, evolution.evolution);
700
- const handle = mintHandle(`evolve ${evolution.name}`);
754
+ const handle = mintHandle(`evolve ${identity(evolution)}`);
701
755
  twinHandles.push(handle);
702
756
  elements.push({
703
757
  type: 'wardleyNode',
@@ -734,7 +788,7 @@ export function importWardleyOwm(source, context = {}) {
734
788
  strokeWidth: LINK_STROKE_WIDTH,
735
789
  frontEndpointStyle: PointStyle.None,
736
790
  rearEndpointStyle: PointStyle.Triangle,
737
- source: { id: evolution.name },
791
+ source: { id: identity(evolution) },
738
792
  target: { id: twinHandles[index] },
739
793
  });
740
794
  });
@@ -755,29 +809,12 @@ export function importWardleyOwm(source, context = {}) {
755
809
  target: { id: link.to },
756
810
  });
757
811
  }
758
- /* ── The report ───────────────────────────────────────────────────── */
759
- const mapped = (titledByFile ? 1 : 0) +
760
- nodeStatements.length +
761
- pipelines.length +
762
- noteStatements.length +
763
- evolutions.length +
764
- links.length;
765
- return {
766
- elements,
767
- report: {
768
- mapped,
769
- carried: carriedLines.length,
770
- // Nothing. Every statement this format writes is a standalone sentence,
771
- // so a carried one cannot contradict the drawing — which is what D5's
772
- // quarantine is FOR. Stated here rather than left to be inferred from a
773
- // zero: a format with no quarantine case is a finding about the format.
774
- quarantined: 0,
775
- notes,
776
- sourceVersion: carriedLines.length === 0 && notes.length === 0
777
- ? OWM_DIALECT_LABRE
778
- : OWM_DIALECT,
779
- },
780
- };
812
+ for (const inertia of inertias) {
813
+ const [cx, cy] = owmPointOf(plot, inertia.visibility, inertia.evolution);
814
+ const { w, h } = INERTIA_SIZE;
815
+ elements.push(wardleyInertiaProps({ xywh: `[${cx - w / 2},${cy - h / 2},${w},${h}]` }));
816
+ }
817
+ return elements;
781
818
  }
782
819
  /* ── The pieces ───────────────────────────────────────────────────────── */
783
820
  /** The `interchange` value for an element, or `undefined` when it carries none. */
@@ -816,7 +853,7 @@ fontWeight = FontWeight.Regular) {
816
853
  };
817
854
  }
818
855
  /** The circle (or composite) one positioned statement draws, plus its name. */
819
- function artefact(keyword, name, cx, cy, tail, mintHandle) {
856
+ function artefact(keyword, name, id, cx, cy, tail, mintHandle) {
820
857
  // The two climate annotations are the only statements this reader draws as
821
858
  // something other than a circle: a fat polygon, at the canonical size the
822
859
  // palette gives one, with its name on the side its shaft is on. The presets
@@ -829,9 +866,14 @@ function artefact(keyword, name, cx, cy, tail, mintHandle) {
829
866
  ...wardleyNodeProps(kind, {
830
867
  xywh: `[${cx - w / 2},${cy - h / 2},${w},${h}]`,
831
868
  }),
832
- interchange: payload({ id: name, tail }),
869
+ interchange: payload({ id, tail }),
833
870
  };
834
871
  const rightwards = kind === 'accelerator';
872
+ // A picture may draw the arrow and no name (OnlineWardleyMaps does); a
873
+ // label with nothing in it would be an empty box nobody asked for. The DSL
874
+ // reader always names one, so this only ever drops a label for the SVG.
875
+ if (name.length === 0)
876
+ return [arrow];
835
877
  return [
836
878
  arrow,
837
879
  label(name, rightwards
@@ -863,7 +905,7 @@ function artefact(keyword, name, cx, cy, tail, mintHandle) {
863
905
  shapeStyle: ShapeStyle.General,
864
906
  roughness: 0,
865
907
  xywh: `[${cx - diameter / 2},${cy - diameter / 2},${diameter},${diameter}]`,
866
- interchange: payload({ id: name, tail }),
908
+ interchange: payload({ id, tail }),
867
909
  };
868
910
  const named = label(name, cx + diameter / 2 + LABEL_GAP, cy - OWM_LABEL_HEIGHT / 2, TextAlign.Left);
869
911
  if (keyword !== 'market')
@@ -880,7 +922,7 @@ function artefact(keyword, name, cx, cy, tail, mintHandle) {
880
922
  [ring * sin60, ring / 2],
881
923
  [-ring * sin60, ring / 2],
882
924
  ];
883
- const handles = vertices.map((_, index) => mintHandle(`${name} market ${index + 1}`));
925
+ const handles = vertices.map((_, index) => mintHandle(`${id} market ${index + 1}`));
884
926
  const dots = vertices.map(([dx, dy], index) => ({
885
927
  type: 'wardleyNode',
886
928
  kind: 'component',
package/dist/index.d.ts CHANGED
@@ -27,5 +27,6 @@ export { WARDLEY_BACKGROUND } from './background.js';
27
27
  */
28
28
  export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, type OwmPlot, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, type WardleyExportBoard, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
29
29
  export { importWardleyOwm } from './import.js';
30
+ export { importWardleySvg } from './svg-import.js';
30
31
  export { wardleyBoardOf, wardleyExportElementsOf, wardleyMapsSelected, } from './actions.js';
31
32
  export { WARDLEY_INTERCHANGE, WARDLEY_OWM_EXPORT, WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange.js';
package/dist/index.js CHANGED
@@ -39,6 +39,9 @@ export { WARDLEY_BACKGROUND } from './background.js';
39
39
  */
40
40
  export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
41
41
  export { importWardleyOwm } from './import.js';
42
+ // The SVG reader that recognises a map (ADR 0032), pure for the same reason:
43
+ // labre-mcp calls the very function the command does.
44
+ export { importWardleySvg } from './svg-import.js';
42
45
  // The half of the export that needs an editor, kept apart from the half that
43
46
  // does not — the same split C4's and BPMN's indexes make for the same reason:
44
47
  // what the selection scopes the file to lives here, the serializer next door.
@@ -9,7 +9,8 @@ import type { InterchangeCapability, InterchangeExportCapability, InterchangeFor
9
9
  * and the import is the row the ADR calls **the reference Wardley import**,
10
10
  * because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
11
11
  * diagram type is still experimental upstream. Then SVG IN, the visual-tier
12
- * FALLBACK, which promises recognition and nothing else.
12
+ * route for a picture, which recognises the map when it knows who drew it and
13
+ * sketches the rest (ADR 0032).
13
14
  *
14
15
  * The file is laid out as one section per FORMAT, each holding its format
15
16
  * object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
@@ -56,24 +57,18 @@ export declare const WARDLEY_OWM_IMPORT: InterchangeImportCapability;
56
57
  */
57
58
  export declare const WARDLEY_SVG_FORMAT: InterchangeFormat;
58
59
  /**
59
- * `wardley:svg:import` — an SVG as a sketch, best effort.
60
+ * `wardley:svg:import` — an SVG as the Wardley map it is a picture of, and
61
+ * whatever else it holds as a sketch (ADR 0032).
60
62
  *
61
- * **The heuristics statement and the known failure modes this capability owes
62
- * (ADR 0012, open question 2) are the module documentation of
63
- * `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** Written once
64
- * there because Wardley and BPMN wrap the SAME parser and therefore make the
65
- * same guesses — and because the ADR's question is about what a visual
66
- * capability is ALLOWED to guess, which for both of them is: geometry, and
67
- * nothing else. A circle is a circle; whether it is a component is the
68
- * author's sentence, not this reader's.
69
- *
70
- * What lands is an ADR 0007 level-1 sketch — plain shapes, brush strokes and
71
- * editable free text — which the author then PROMOTES onto a map. In
72
- * particular the two axes and the evolution bands are NOT recovered: a map's
73
- * coordinates are its meaning, and reading them off a picture would be
74
- * inventing a position and presenting it as read. {@link WARDLEY_OWM_IMPORT}
75
- * beside it is the route a user should be pointed at, exactly as P2 says —
76
- * this one is for the picture somebody sent you from a tool that writes no OWM.
63
+ * **The heuristics statement this capability owes (ADR 0012, open question 2)
64
+ * is the module documentation of `./svg-import.ts`**, beside the parser that
65
+ * makes the guesses: ADR 0032 superseded, for Wardley only, the rule that a
66
+ * visual capability guesses geometry and nothing else. A picture from a
67
+ * producer the reader recognises arrives as native Wardley elements; the rest
68
+ * of it — and the whole of a picture nobody recognises — arrives as the same
69
+ * level-1 sketch BPMN's reader draws (`parseSvgSketch`, which BPMN still
70
+ * declares). Still the visual tier: no payload, no round-trip, and
71
+ * {@link WARDLEY_OWM_IMPORT} beside it stays the reference Wardley import.
77
72
  */
78
73
  export declare const WARDLEY_SVG_IMPORT: InterchangeImportCapability;
79
74
  /** Everything Wardley registers, in one list the view extension hands over. */
@@ -1,6 +1,7 @@
1
- import { interchangeCapabilityId, parseSvgSketch, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
1
+ import { interchangeCapabilityId, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { exportWardleyOwmWithWarnings, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
3
3
  import { importWardleyOwm } from './import.js';
4
+ import { importWardleySvg } from './svg-import.js';
4
5
  /**
5
6
  * Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
6
7
  *
@@ -11,7 +12,8 @@ import { importWardleyOwm } from './import.js';
11
12
  * and the import is the row the ADR calls **the reference Wardley import**,
12
13
  * because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
13
14
  * diagram type is still experimental upstream. Then SVG IN, the visual-tier
14
- * FALLBACK, which promises recognition and nothing else.
15
+ * route for a picture, which recognises the map when it knows who drew it and
16
+ * sketches the rest (ADR 0032).
15
17
  *
16
18
  * The file is laid out as one section per FORMAT, each holding its format
17
19
  * object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
@@ -103,31 +105,25 @@ export const WARDLEY_SVG_FORMAT = {
103
105
  mime: SVG_SKETCH_MIME,
104
106
  };
105
107
  /**
106
- * `wardley:svg:import` — an SVG as a sketch, best effort.
108
+ * `wardley:svg:import` — an SVG as the Wardley map it is a picture of, and
109
+ * whatever else it holds as a sketch (ADR 0032).
107
110
  *
108
- * **The heuristics statement and the known failure modes this capability owes
109
- * (ADR 0012, open question 2) are the module documentation of
110
- * `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** Written once
111
- * there because Wardley and BPMN wrap the SAME parser and therefore make the
112
- * same guesses — and because the ADR's question is about what a visual
113
- * capability is ALLOWED to guess, which for both of them is: geometry, and
114
- * nothing else. A circle is a circle; whether it is a component is the
115
- * author's sentence, not this reader's.
116
- *
117
- * What lands is an ADR 0007 level-1 sketch — plain shapes, brush strokes and
118
- * editable free text — which the author then PROMOTES onto a map. In
119
- * particular the two axes and the evolution bands are NOT recovered: a map's
120
- * coordinates are its meaning, and reading them off a picture would be
121
- * inventing a position and presenting it as read. {@link WARDLEY_OWM_IMPORT}
122
- * beside it is the route a user should be pointed at, exactly as P2 says —
123
- * this one is for the picture somebody sent you from a tool that writes no OWM.
111
+ * **The heuristics statement this capability owes (ADR 0012, open question 2)
112
+ * is the module documentation of `./svg-import.ts`**, beside the parser that
113
+ * makes the guesses: ADR 0032 superseded, for Wardley only, the rule that a
114
+ * visual capability guesses geometry and nothing else. A picture from a
115
+ * producer the reader recognises arrives as native Wardley elements; the rest
116
+ * of it — and the whole of a picture nobody recognises — arrives as the same
117
+ * level-1 sketch BPMN's reader draws (`parseSvgSketch`, which BPMN still
118
+ * declares). Still the visual tier: no payload, no round-trip, and
119
+ * {@link WARDLEY_OWM_IMPORT} beside it stays the reference Wardley import.
124
120
  */
125
121
  export const WARDLEY_SVG_IMPORT = {
126
122
  id: interchangeCapabilityId('wardley', WARDLEY_SVG_FORMAT.id, 'import'),
127
123
  framework: 'wardley',
128
124
  format: WARDLEY_SVG_FORMAT,
129
125
  direction: 'import',
130
- run: parseSvgSketch,
126
+ run: importWardleySvg,
131
127
  };
132
128
  /* ── The list the view extension registers ────────────────────────────── */
133
129
  /** Everything Wardley registers, in one list the view extension hands over. */
@@ -11,6 +11,6 @@ import { type WardleyNodeElementModel } from '@formicoidea/labre-core/model';
11
11
  * the hollow center come from the base fill, so colors stay editable.
12
12
  */
13
13
  export declare const wardleyNode: ElementRenderer<WardleyNodeElementModel>;
14
- export declare const WardleyNodeRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
14
+ export declare const WardleyNodeRendererExtension: import("@formicoidea/labre-core/_pkgs/store").ExtensionType & {
15
15
  identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<WardleyNodeElementModel>>;
16
16
  };
package/dist/reading.js CHANGED
@@ -141,6 +141,10 @@ export const WARDLEY_READING = {
141
141
  background: WARDLEY_BACKGROUND,
142
142
  // Evolution runs along the plot's x axis; its four zones ARE the phases.
143
143
  axis: 'x',
144
+ // No `label` / `none`: "Evolution phase" is the engine's default wording
145
+ // (`READING_FRAME_DEFAULT_WORDING`), declared once in the surface package
146
+ // so a 0.43 host profile reads with it too. Restating it here would be a
147
+ // second declaration of the same two keys.
144
148
  },
145
149
  /**
146
150
  * The two record properties a reading may compare itself against.
package/dist/roles.js CHANGED
@@ -22,6 +22,7 @@ const DEFS = [
22
22
  id: WARDLEY_ROLE.component,
23
23
  kind: 'node',
24
24
  labelKey: 'com.labre.wardley.role.component',
25
+ labelFallback: 'Component',
25
26
  },
26
27
  // A user / need: a component with no need of its own, hence its own role
27
28
  // rather than a specialisation of `component`.
@@ -29,34 +30,40 @@ const DEFS = [
29
30
  id: WARDLEY_ROLE.anchor,
30
31
  kind: 'node',
31
32
  labelKey: 'com.labre.wardley.role.anchor',
33
+ labelFallback: 'Anchor',
32
34
  },
33
35
  // The pipeline body. Connections go through its handle, never the body.
34
36
  {
35
37
  id: WARDLEY_ROLE.pipeline,
36
38
  kind: 'node',
37
39
  labelKey: 'com.labre.wardley.role.pipeline',
40
+ labelFallback: 'Pipeline',
38
41
  },
39
42
  {
40
43
  id: WARDLEY_ROLE.handle,
41
44
  kind: 'node',
42
45
  labelKey: 'com.labre.wardley.role.handle',
46
+ labelFallback: 'Pipeline handle',
43
47
  },
44
48
  {
45
49
  id: WARDLEY_ROLE.market,
46
50
  parent: WARDLEY_ROLE.component,
47
51
  kind: 'node',
48
52
  labelKey: 'com.labre.wardley.role.market',
53
+ labelFallback: 'Market',
49
54
  },
50
55
  {
51
56
  id: WARDLEY_ROLE.ecosystem,
52
57
  parent: WARDLEY_ROLE.component,
53
58
  kind: 'node',
54
59
  labelKey: 'com.labre.wardley.role.ecosystem',
60
+ labelFallback: 'Ecosystem',
55
61
  },
56
62
  {
57
63
  id: WARDLEY_ROLE.method,
58
64
  kind: 'node',
59
65
  labelKey: 'com.labre.wardley.role.method',
66
+ labelFallback: 'Method',
60
67
  },
61
68
  /**
62
69
  * A Porter's-forces glyph: one of the five forces of external competition
@@ -148,12 +155,21 @@ const DEFS = [
148
155
  verbFallback: 'needs',
149
156
  gestureHintKey: 'com.labre.wardley.role.dependency.gesture',
150
157
  gestureHintFallback: 'Drag from the component that has the need to what it needs.',
151
- // The house primary, on THIS chip and no other (same recette). The value
152
- // chain is what a Wardley map is read along, and the PO asked for the
153
- // relation that carries it to be unmistakable — a decision about one
154
- // relation, so it is declared on that relation rather than on the
155
- // mechanism, and every other framework's reveal keeps the colour it had.
156
- chipColor: '#2563eb',
158
+ // No `chipColor`. This role used to declare one (PR #203), so that the
159
+ // relation carrying the value chain would be unmistakable — and the
160
+ // result, on one map, was two chips in two different blues: this one in
161
+ // the colour it asked for, `wardley:change-arrow` in the mechanism's
162
+ // default. Neither had been compared against the other, because the pin
163
+ // that watched this field only ever looked at Wardley.
164
+ //
165
+ // The chip is chrome — the tool talking about the drawing, not part of
166
+ // it — so it follows the theme's accent token like every other
167
+ // affordance, and both relations of a map now wear the same blue
168
+ // (`EDGE_DIRECTION_COLOR`, `gfx/connector`). `chipColor` stays on the
169
+ // role contract as the extension point it was meant to be: a framework
170
+ // MAY claim its own, and the cross-framework guard in
171
+ // `affine/all/src/__tests__/direction-chip-accent.unit.spec.ts` is what
172
+ // keeps a second accent from creeping back in unnoticed.
157
173
  },
158
174
  },
159
175
  // The map itself: the axes frame the other roles are positioned against.
@@ -163,6 +179,7 @@ const DEFS = [
163
179
  id: WARDLEY_ROLE.map,
164
180
  kind: 'node',
165
181
  labelKey: 'com.labre.wardley.role.map',
182
+ labelFallback: 'Wardley map',
166
183
  },
167
184
  // The change (evolution) arrow: "this is where it is going". An EDGE, and
168
185
  // deliberately not a specialisation of `dependency` — it says nothing about
@@ -191,6 +208,7 @@ const DEFS = [
191
208
  id: WARDLEY_ROLE.inertia,
192
209
  kind: 'node',
193
210
  labelKey: 'com.labre.wardley.role.inertia',
211
+ labelFallback: 'Inertia',
194
212
  },
195
213
  // The name written next to an artefact. A role of its own rather than a
196
214
  // property of the node it labels: on this canvas a label IS a separate free
@@ -203,6 +221,7 @@ const DEFS = [
203
221
  id: WARDLEY_ROLE.label,
204
222
  kind: 'text',
205
223
  labelKey: 'com.labre.wardley.role.label',
224
+ labelFallback: 'Label',
206
225
  },
207
226
  ];
208
227
  // Null prototype: this is a lookup table keyed by ids that may one day come
@@ -0,0 +1,2 @@
1
+ import type { InterchangeImportContext, InterchangeImportResult } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare function importWardleySvg(source: string, context?: InterchangeImportContext): InterchangeImportResult;