@formicoidea/labre-framework-wardley 0.50.0 → 0.51.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/actions.js CHANGED
@@ -9,7 +9,8 @@ import { Bound } from '@formicoidea/labre-core/global/gfx';
9
9
  import { GfxControllerIdentifier, } from '@formicoidea/labre-core/std/gfx';
10
10
  import { WARDLEY_BACKGROUND } from './background.js';
11
11
  import { WARDLEY_SVG_IMPORT } from './interchange.js';
12
- import { wardleyBoardFrom, wardleySafeFilename, } from './export.js';
12
+ import { wardleySafeFilename } from './export.js';
13
+ import { wardleyBoardFrom } from './export-board.js';
13
14
  import { WARDLEY_OWM_EXPORT, WARDLEY_OWM_IMPORT } from './interchange.js';
14
15
  import { INERTIA_SIZE, PORTER_DEFAULT_LETTER } from './node/consts.js';
15
16
  import { wardleyAreaBox, wardleyAreaProps, wardleyCanonicalBox, WARDLEY_EDGE_STYLE, wardleyHandleBox, wardleyHandleProps, wardleyInertiaProps, wardleyLabelBoxFor, wardleyLabelProps, wardleyMarketDotBoxes, wardleyMarketDotProps, wardleyMarketLinkPairs, wardleyMarketLinkProps, WARDLEY_NODE_LABEL, wardleyNodeLabelKey, wardleyNodeProps, wardleyPorterArrowProps, wardleyPorterArrows, wardleyPorterLetterProps, } from './presets.js';
package/dist/consts.js CHANGED
@@ -1,4 +1,4 @@
1
- import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/consts';
1
+ import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/headless';
2
2
  /**
3
3
  * Visual constants for the Wardley map background.
4
4
  *
@@ -0,0 +1,10 @@
1
+ import type { GfxPrimitiveElementModel } from '@formicoidea/labre-core/std/gfx';
2
+ import type { WardleyExportBoard } from './export.js';
3
+ /**
4
+ * The half of the OWM export that needs LIVE element models: picking the
5
+ * artefacts out of a surface by `instanceof`. Kept out of `export.ts` so the
6
+ * serializer and the OWM vocabulary the readers share stay editor-free — the
7
+ * headless `./interchange` entry imports `export.ts` and must not load an
8
+ * element class (ADR 0012, P3 as amended 2026-10-14).
9
+ */
10
+ export declare function wardleyBoardFrom(elements: readonly GfxPrimitiveElementModel[]): WardleyExportBoard;
@@ -0,0 +1,31 @@
1
+ import { ConnectorElementModel, TextElementModel, WardleyBackgroundElementModel, WardleyNodeElementModel, } from '@formicoidea/labre-core/model';
2
+ import { WARDLEY_ROLE } from './roles.js';
3
+ /**
4
+ * The half of the OWM export that needs LIVE element models: picking the
5
+ * artefacts out of a surface by `instanceof`. Kept out of `export.ts` so the
6
+ * serializer and the OWM vocabulary the readers share stay editor-free — the
7
+ * headless `./interchange` entry imports `export.ts` and must not load an
8
+ * element class (ADR 0012, P3 as amended 2026-10-14).
9
+ */
10
+ export function wardleyBoardFrom(elements) {
11
+ const maps = [];
12
+ const nodes = [];
13
+ const labels = [];
14
+ const notes = [];
15
+ const connectors = [];
16
+ for (const element of elements) {
17
+ if (element instanceof WardleyBackgroundElementModel)
18
+ maps.push(element);
19
+ else if (element instanceof WardleyNodeElementModel)
20
+ nodes.push(element);
21
+ else if (element instanceof ConnectorElementModel)
22
+ connectors.push(element);
23
+ else if (element instanceof TextElementModel) {
24
+ if (element.role === WARDLEY_ROLE.label)
25
+ labels.push(element);
26
+ else if (element.role === undefined)
27
+ notes.push(element);
28
+ }
29
+ }
30
+ return { maps, nodes, labels, notes, connectors };
31
+ }
package/dist/export.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { ConnectorElementModel, TextElementModel, WardleyBackgroundElementModel, WardleyNodeElementModel } from '@formicoidea/labre-core/model';
2
- import type { GfxPrimitiveElementModel } from '@formicoidea/labre-core/std/gfx';
1
+ import type { ConnectorElementModel, TextElementModel, WardleyBackgroundElementModel, WardleyNodeElementModel } from '@formicoidea/labre-core/model';
3
2
  /**
4
3
  * A Wardley map as an OnlineWardleyMaps (OWM) DSL document — models in, text
5
4
  * out (`docs/adr/0012`, P3).
@@ -170,7 +169,6 @@ export interface WardleyExportBoard {
170
169
  notes: TextElementModel[];
171
170
  connectors: ConnectorElementModel[];
172
171
  }
173
- export declare function wardleyBoardFrom(elements: readonly GfxPrimitiveElementModel[]): WardleyExportBoard;
174
172
  /**
175
173
  * A name a file system will accept, minus the extension: the shared
176
174
  * `safeFilename` with Wardley's fallback — `map`, because that is what an OWM
package/dist/export.js CHANGED
@@ -1,6 +1,5 @@
1
- import { backgroundPlot } from '@formicoidea/labre-core/blocks/surface';
2
- import { ConnectorElementModel, TextElementModel, WardleyBackgroundElementModel, WardleyNodeElementModel, } from '@formicoidea/labre-core/model';
3
- import { safeFilename } from '@formicoidea/labre-core/shared/utils';
1
+ import { backgroundPlot } from '@formicoidea/labre-core/interchange';
2
+ import { safeFilename } from '@formicoidea/labre-core/shared/headless';
4
3
  import { WARDLEY_BACKGROUND } from './background.js';
5
4
  import { LABEL_FONT_SIZE, LABEL_GAP } from './node/consts.js';
6
5
  import { WARDLEY_ROLE } from './roles.js';
@@ -243,28 +242,6 @@ export function owmCoordsOf(plot, x, y) {
243
242
  evolution: (x - plot.x0) / plot.width,
244
243
  };
245
244
  }
246
- export function wardleyBoardFrom(elements) {
247
- const maps = [];
248
- const nodes = [];
249
- const labels = [];
250
- const notes = [];
251
- const connectors = [];
252
- for (const element of elements) {
253
- if (element instanceof WardleyBackgroundElementModel)
254
- maps.push(element);
255
- else if (element instanceof WardleyNodeElementModel)
256
- nodes.push(element);
257
- else if (element instanceof ConnectorElementModel)
258
- connectors.push(element);
259
- else if (element instanceof TextElementModel) {
260
- if (element.role === WARDLEY_ROLE.label)
261
- labels.push(element);
262
- else if (element.role === undefined)
263
- notes.push(element);
264
- }
265
- }
266
- return { maps, nodes, labels, notes, connectors };
267
- }
268
245
  /**
269
246
  * A name a file system will accept, minus the extension: the shared
270
247
  * `safeFilename` with Wardley's fallback — `map`, because that is what an OWM
package/dist/import.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ConnectorMode, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model';
1
+ import { ConnectorMode, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextAlign, } from '@formicoidea/labre-core/model/headless';
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
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';
package/dist/index.d.ts CHANGED
@@ -25,7 +25,8 @@ export { WARDLEY_BACKGROUND } from './background.js';
25
25
  * SAME function, and no serialization logic for a Labre framework lives outside
26
26
  * this repo. `exportWardleyOwm` is what replaces labre-mcp's own serializer.
27
27
  */
28
- export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, type OwmPlot, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, type WardleyExportBoard, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
28
+ export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, type OwmPlot, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, type WardleyExportBoard, wardleySafeFilename, } from './export.js';
29
+ export { wardleyBoardFrom } from './export-board.js';
29
30
  export { importWardleyOwm } from './import.js';
30
31
  export { importWardleySvg } from './svg-import.js';
31
32
  export { wardleyBoardOf, wardleyExportElementsOf, wardleyMapsSelected, } from './actions.js';
package/dist/index.js CHANGED
@@ -37,7 +37,8 @@ export { WARDLEY_BACKGROUND } from './background.js';
37
37
  * SAME function, and no serialization logic for a Labre framework lives outside
38
38
  * this repo. `exportWardleyOwm` is what replaces labre-mcp's own serializer.
39
39
  */
40
- export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
40
+ export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, wardleySafeFilename, } from './export.js';
41
+ export { wardleyBoardFrom } from './export-board.js';
41
42
  export { importWardleyOwm } from './import.js';
42
43
  // The SVG reader that recognises a map (ADR 0032), pure for the same reason:
43
44
  // labre-mcp calls the very function the command does.
@@ -0,0 +1,64 @@
1
+ import type { InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/interchange';
2
+ /**
3
+ * `@labre/affine-gfx-wardley/interchange` — Wardley's formats and its two
4
+ * READERS, with no editor behind them (ADR 0012, P3 as amended 2026-10-14).
5
+ *
6
+ * What a server needs to read an `.owm` or an `.svg` as a map: the format
7
+ * declarations and the import capabilities, whose `run` is a pure function of
8
+ * text. The OWM EXPORT capability is not here: it picks the artefacts out of
9
+ * live element models (`wardleyBoardFrom`, by `instanceof`), which is the
10
+ * editor graph this entry exists to leave out. It stays in `interchange.ts`,
11
+ * which re-exports everything below. The serializer itself
12
+ * (`exportWardleyOwm`) is editor-free and stays on the package index.
13
+ *
14
+ * Held by `interchange-headless.unit.spec.ts` in `packages/affine/all`.
15
+ */
16
+ /**
17
+ * The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
18
+ * picture: a `[visibility, evolution]` pair IS a position on the value chain
19
+ * and on the evolution axis, so the whole preservation contract applies and the
20
+ * import needs no invented axis (P2, and D4's "a format that carries
21
+ * coordinates but no pixels").
22
+ *
23
+ * `text/plain`, because that is what a DSL is, and `.owm` first — it is the
24
+ * extension a download is given. `.wm` rides behind it: the same bytes are
25
+ * written under both in the wild, and a picker that refused one would refuse a
26
+ * valid map for the sake of a filename. What the file actually IS is decided by
27
+ * the reader.
28
+ *
29
+ * The two directions share the FORMAT object, deliberately. `owm` is the id
30
+ * under which foreign matter rides on an element (D2), so a reader and a writer
31
+ * that disagreed about it would write payloads the other could not find.
32
+ */
33
+ export declare const WARDLEY_OWM_EXTENSION = ".owm";
34
+ export declare const WARDLEY_OWM_MIME = "text/plain";
35
+ export declare const WARDLEY_OWM_FORMAT: InterchangeFormat;
36
+ /** `wardley:owm:import` — an `.owm` file as a map. */
37
+ export declare const WARDLEY_OWM_IMPORT: InterchangeImportCapability;
38
+ /**
39
+ * SVG. **Visual** — the file carries a rendering, not a model, so it makes
40
+ * exactly one promise: the picture arrives as editable elements.
41
+ *
42
+ * Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
43
+ * rejects "one capability per format, with the framework inferred from the
44
+ * file": a `.svg` is read by several frameworks, and deciding which one a
45
+ * picture is a picture OF is the guess this platform refuses everywhere else.
46
+ * The three constants are the parser package's, so the declarations cannot
47
+ * drift into filtering a picker on different extensions.
48
+ */
49
+ export declare const WARDLEY_SVG_FORMAT: InterchangeFormat;
50
+ /**
51
+ * `wardley:svg:import` — an SVG as the Wardley map it is a picture of, and
52
+ * whatever else it holds as a sketch (ADR 0032).
53
+ *
54
+ * **The heuristics statement this capability owes (ADR 0012, open question 2)
55
+ * is the module documentation of `./svg-import.ts`**, beside the parser that
56
+ * makes the guesses: ADR 0032 superseded, for Wardley only, the rule that a
57
+ * visual capability guesses geometry and nothing else. A picture from a
58
+ * producer the reader recognises arrives as native Wardley elements; the rest
59
+ * of it — and the whole of a picture nobody recognises — arrives as the same
60
+ * level-1 sketch BPMN's reader draws (`parseSvgSketch`, which BPMN still
61
+ * declares). Still the visual tier: no payload, no round-trip, and
62
+ * {@link WARDLEY_OWM_IMPORT} beside it stays the reference Wardley import.
63
+ */
64
+ export declare const WARDLEY_SVG_IMPORT: InterchangeImportCapability;
@@ -0,0 +1,91 @@
1
+ import { interchangeCapabilityId, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/interchange';
2
+ import { WARDLEY_OWM_FORMAT_ID } from './export.js';
3
+ import { importWardleyOwm } from './import.js';
4
+ import { importWardleySvg } from './svg-import.js';
5
+ /**
6
+ * `@labre/affine-gfx-wardley/interchange` — Wardley's formats and its two
7
+ * READERS, with no editor behind them (ADR 0012, P3 as amended 2026-10-14).
8
+ *
9
+ * What a server needs to read an `.owm` or an `.svg` as a map: the format
10
+ * declarations and the import capabilities, whose `run` is a pure function of
11
+ * text. The OWM EXPORT capability is not here: it picks the artefacts out of
12
+ * live element models (`wardleyBoardFrom`, by `instanceof`), which is the
13
+ * editor graph this entry exists to leave out. It stays in `interchange.ts`,
14
+ * which re-exports everything below. The serializer itself
15
+ * (`exportWardleyOwm`) is editor-free and stays on the package index.
16
+ *
17
+ * Held by `interchange-headless.unit.spec.ts` in `packages/affine/all`.
18
+ */
19
+ /* ── OWM (semantic) ───────────────────────────────────────────────────── */
20
+ /**
21
+ * The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
22
+ * picture: a `[visibility, evolution]` pair IS a position on the value chain
23
+ * and on the evolution axis, so the whole preservation contract applies and the
24
+ * import needs no invented axis (P2, and D4's "a format that carries
25
+ * coordinates but no pixels").
26
+ *
27
+ * `text/plain`, because that is what a DSL is, and `.owm` first — it is the
28
+ * extension a download is given. `.wm` rides behind it: the same bytes are
29
+ * written under both in the wild, and a picker that refused one would refuse a
30
+ * valid map for the sake of a filename. What the file actually IS is decided by
31
+ * the reader.
32
+ *
33
+ * The two directions share the FORMAT object, deliberately. `owm` is the id
34
+ * under which foreign matter rides on an element (D2), so a reader and a writer
35
+ * that disagreed about it would write payloads the other could not find.
36
+ */
37
+ export const WARDLEY_OWM_EXTENSION = '.owm';
38
+ export const WARDLEY_OWM_MIME = 'text/plain';
39
+ export const WARDLEY_OWM_FORMAT = {
40
+ id: WARDLEY_OWM_FORMAT_ID,
41
+ tier: 'semantic',
42
+ extensions: [WARDLEY_OWM_EXTENSION, '.wm'],
43
+ mime: WARDLEY_OWM_MIME,
44
+ };
45
+ /** `wardley:owm:import` — an `.owm` file as a map. */
46
+ export const WARDLEY_OWM_IMPORT = {
47
+ id: interchangeCapabilityId('wardley', WARDLEY_OWM_FORMAT.id, 'import'),
48
+ framework: 'wardley',
49
+ format: WARDLEY_OWM_FORMAT,
50
+ direction: 'import',
51
+ run: importWardleyOwm,
52
+ };
53
+ /* ── SVG (visual) ─────────────────────────────────────────────────────── */
54
+ /**
55
+ * SVG. **Visual** — the file carries a rendering, not a model, so it makes
56
+ * exactly one promise: the picture arrives as editable elements.
57
+ *
58
+ * Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
59
+ * rejects "one capability per format, with the framework inferred from the
60
+ * file": a `.svg` is read by several frameworks, and deciding which one a
61
+ * picture is a picture OF is the guess this platform refuses everywhere else.
62
+ * The three constants are the parser package's, so the declarations cannot
63
+ * drift into filtering a picker on different extensions.
64
+ */
65
+ export const WARDLEY_SVG_FORMAT = {
66
+ id: SVG_SKETCH_FORMAT_ID,
67
+ tier: 'visual',
68
+ extensions: [SVG_SKETCH_EXTENSION],
69
+ mime: SVG_SKETCH_MIME,
70
+ };
71
+ /**
72
+ * `wardley:svg:import` — an SVG as the Wardley map it is a picture of, and
73
+ * whatever else it holds as a sketch (ADR 0032).
74
+ *
75
+ * **The heuristics statement this capability owes (ADR 0012, open question 2)
76
+ * is the module documentation of `./svg-import.ts`**, beside the parser that
77
+ * makes the guesses: ADR 0032 superseded, for Wardley only, the rule that a
78
+ * visual capability guesses geometry and nothing else. A picture from a
79
+ * producer the reader recognises arrives as native Wardley elements; the rest
80
+ * of it — and the whole of a picture nobody recognises — arrives as the same
81
+ * level-1 sketch BPMN's reader draws (`parseSvgSketch`, which BPMN still
82
+ * declares). Still the visual tier: no payload, no round-trip, and
83
+ * {@link WARDLEY_OWM_IMPORT} beside it stays the reference Wardley import.
84
+ */
85
+ export const WARDLEY_SVG_IMPORT = {
86
+ id: interchangeCapabilityId('wardley', WARDLEY_SVG_FORMAT.id, 'import'),
87
+ framework: 'wardley',
88
+ format: WARDLEY_SVG_FORMAT,
89
+ direction: 'import',
90
+ run: importWardleySvg,
91
+ };
@@ -1,75 +1,6 @@
1
- import type { InterchangeCapability, InterchangeExportCapability, InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/blocks/surface';
2
- /**
3
- * Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
4
- *
5
- * Two formats and three rows. Both directions of the OWM DSL — the export is
6
- * the row the ADR records as **owed** (a Wardley serializer exists today in
7
- * labre-mcp, outside this repo, and is the one violation of P3 the ADR names;
8
- * it exists here now, so that repo becomes a caller and its copy is deleted),
9
- * and the import is the row the ADR calls **the reference Wardley import**,
10
- * because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
11
- * diagram type is still experimental upstream. Then SVG IN, the visual-tier
12
- * route for a picture, which recognises the map when it knows who drew it and
13
- * sketches the rest (ADR 0032).
14
- *
15
- * The file is laid out as one section per FORMAT, each holding its format
16
- * object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
17
- * collecting them. A format is added by adding a section, not by editing one.
18
- *
19
- * Everything here is pure. No half has ever had a `std` in sight, and this file
20
- * adds no editor to any of them: it picks the artefacts the writer speaks about
21
- * out of a surface's elements, and hands a reader's output straight back.
22
- */
23
- /**
24
- * The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
25
- * picture: a `[visibility, evolution]` pair IS a position on the value chain
26
- * and on the evolution axis, so the whole preservation contract applies and the
27
- * import needs no invented axis (P2, and D4's "a format that carries
28
- * coordinates but no pixels").
29
- *
30
- * `text/plain`, because that is what a DSL is, and `.owm` first — it is the
31
- * extension a download is given. `.wm` rides behind it: the same bytes are
32
- * written under both in the wild, and a picker that refused one would refuse a
33
- * valid map for the sake of a filename. What the file actually IS is decided by
34
- * the reader.
35
- *
36
- * The two directions share the FORMAT object, deliberately. `owm` is the id
37
- * under which foreign matter rides on an element (D2), so a reader and a writer
38
- * that disagreed about it would write payloads the other could not find.
39
- */
40
- export declare const WARDLEY_OWM_EXTENSION = ".owm";
41
- export declare const WARDLEY_OWM_MIME = "text/plain";
42
- export declare const WARDLEY_OWM_FORMAT: InterchangeFormat;
1
+ import type { InterchangeCapability, InterchangeExportCapability } from '@formicoidea/labre-core/blocks/surface';
2
+ export { WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange-headless.js';
43
3
  /** `wardley:owm:export` — the row that replaces labre-mcp's own serializer. */
44
4
  export declare const WARDLEY_OWM_EXPORT: InterchangeExportCapability;
45
- /** `wardley:owm:import` — an `.owm` file as a map. */
46
- export declare const WARDLEY_OWM_IMPORT: InterchangeImportCapability;
47
- /**
48
- * SVG. **Visual** — the file carries a rendering, not a model, so it makes
49
- * exactly one promise: the picture arrives as editable elements.
50
- *
51
- * Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
52
- * rejects "one capability per format, with the framework inferred from the
53
- * file": a `.svg` is read by several frameworks, and deciding which one a
54
- * picture is a picture OF is the guess this platform refuses everywhere else.
55
- * The three constants are the parser package's, so the declarations cannot
56
- * drift into filtering a picker on different extensions.
57
- */
58
- export declare const WARDLEY_SVG_FORMAT: InterchangeFormat;
59
- /**
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).
62
- *
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.
72
- */
73
- export declare const WARDLEY_SVG_IMPORT: InterchangeImportCapability;
74
5
  /** Everything Wardley registers, in one list the view extension hands over. */
75
6
  export declare const WARDLEY_INTERCHANGE: readonly InterchangeCapability[];
@@ -1,7 +1,8 @@
1
- import { interchangeCapabilityId, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
2
- import { exportWardleyOwmWithWarnings, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
3
- import { importWardleyOwm } from './import.js';
4
- import { importWardleySvg } from './svg-import.js';
1
+ import { interchangeCapabilityId } from '@formicoidea/labre-core/blocks/surface';
2
+ import { exportWardleyOwmWithWarnings, wardleySafeFilename } from './export.js';
3
+ import { wardleyBoardFrom } from './export-board.js';
4
+ import { WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_IMPORT, } from './interchange-headless.js';
5
+ export { WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange-headless.js';
5
6
  /**
6
7
  * Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
7
8
  *
@@ -15,40 +16,16 @@ import { importWardleySvg } from './svg-import.js';
15
16
  * route for a picture, which recognises the map when it knows who drew it and
16
17
  * sketches the rest (ADR 0032).
17
18
  *
18
- * The file is laid out as one section per FORMAT, each holding its format
19
- * object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
20
- * collecting them. A format is added by adding a section, not by editing one.
19
+ * The formats and the two import capabilities live in
20
+ * `interchange-headless.ts` (the package's editor-free `./interchange` entry)
21
+ * and are re-exported above; this file adds the export capability, which
22
+ * reads live element models, and {@link WARDLEY_INTERCHANGE} collecting them.
21
23
  *
22
24
  * Everything here is pure. No half has ever had a `std` in sight, and this file
23
25
  * adds no editor to any of them: it picks the artefacts the writer speaks about
24
26
  * out of a surface's elements, and hands a reader's output straight back.
25
27
  */
26
28
  /* ── OWM (semantic) ───────────────────────────────────────────────────── */
27
- /**
28
- * The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
29
- * picture: a `[visibility, evolution]` pair IS a position on the value chain
30
- * and on the evolution axis, so the whole preservation contract applies and the
31
- * import needs no invented axis (P2, and D4's "a format that carries
32
- * coordinates but no pixels").
33
- *
34
- * `text/plain`, because that is what a DSL is, and `.owm` first — it is the
35
- * extension a download is given. `.wm` rides behind it: the same bytes are
36
- * written under both in the wild, and a picker that refused one would refuse a
37
- * valid map for the sake of a filename. What the file actually IS is decided by
38
- * the reader.
39
- *
40
- * The two directions share the FORMAT object, deliberately. `owm` is the id
41
- * under which foreign matter rides on an element (D2), so a reader and a writer
42
- * that disagreed about it would write payloads the other could not find.
43
- */
44
- export const WARDLEY_OWM_EXTENSION = '.owm';
45
- export const WARDLEY_OWM_MIME = 'text/plain';
46
- export const WARDLEY_OWM_FORMAT = {
47
- id: WARDLEY_OWM_FORMAT_ID,
48
- tier: 'semantic',
49
- extensions: [WARDLEY_OWM_EXTENSION, '.wm'],
50
- mime: WARDLEY_OWM_MIME,
51
- };
52
29
  /**
53
30
  * The board as an OWM document.
54
31
  *
@@ -78,53 +55,6 @@ export const WARDLEY_OWM_EXPORT = {
78
55
  direction: 'export',
79
56
  run: runWardleyOwmExport,
80
57
  };
81
- /** `wardley:owm:import` — an `.owm` file as a map. */
82
- export const WARDLEY_OWM_IMPORT = {
83
- id: interchangeCapabilityId('wardley', WARDLEY_OWM_FORMAT.id, 'import'),
84
- framework: 'wardley',
85
- format: WARDLEY_OWM_FORMAT,
86
- direction: 'import',
87
- run: importWardleyOwm,
88
- };
89
- /* ── SVG (visual) ─────────────────────────────────────────────────────── */
90
- /**
91
- * SVG. **Visual** — the file carries a rendering, not a model, so it makes
92
- * exactly one promise: the picture arrives as editable elements.
93
- *
94
- * Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
95
- * rejects "one capability per format, with the framework inferred from the
96
- * file": a `.svg` is read by several frameworks, and deciding which one a
97
- * picture is a picture OF is the guess this platform refuses everywhere else.
98
- * The three constants are the parser package's, so the declarations cannot
99
- * drift into filtering a picker on different extensions.
100
- */
101
- export const WARDLEY_SVG_FORMAT = {
102
- id: SVG_SKETCH_FORMAT_ID,
103
- tier: 'visual',
104
- extensions: [SVG_SKETCH_EXTENSION],
105
- mime: SVG_SKETCH_MIME,
106
- };
107
- /**
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).
110
- *
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.
120
- */
121
- export const WARDLEY_SVG_IMPORT = {
122
- id: interchangeCapabilityId('wardley', WARDLEY_SVG_FORMAT.id, 'import'),
123
- framework: 'wardley',
124
- format: WARDLEY_SVG_FORMAT,
125
- direction: 'import',
126
- run: importWardleySvg,
127
- };
128
58
  /* ── The list the view extension registers ────────────────────────────── */
129
59
  /** Everything Wardley registers, in one list the view extension hands over. */
130
60
  export const WARDLEY_INTERCHANGE = [
@@ -1,4 +1,4 @@
1
- import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/consts';
1
+ import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/headless';
2
2
  /**
3
3
  * Visual constants for Wardley nodes (component + anchor) and the connector /
4
4
  * inertia presets created from the Wardley menu.
package/dist/presets.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { FontWeight, PointStyle, StrokeStyle, type WardleyNodeKind } from '@formicoidea/labre-core/model';
1
+ import { FontWeight, PointStyle, StrokeStyle } from '@formicoidea/labre-core/model/headless';
2
+ import type { WardleyNodeKind } from '@formicoidea/labre-core/model';
2
3
  /**
3
4
  * What a Wardley artefact IS, as props — the ONE description the creation sites
4
5
  * and the morph both read.
package/dist/presets.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ConnectorMode, DEFAULT_POLYGON_VERTICES, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextFitMode, } from '@formicoidea/labre-core/model';
1
+ import { ConnectorMode, DEFAULT_POLYGON_VERTICES, FontFamily, FontWeight, PointStyle, ShapeStyle, StrokeStyle, TextFitMode, } from '@formicoidea/labre-core/model/headless';
2
2
  import { Bound } from '@formicoidea/labre-core/global/gfx';
3
3
  import { ACCELERATOR_FILL, ACCELERATOR_LABEL, ACCELERATOR_SIZE, ACCELERATOR_STROKE_WIDTH, ACCELERATOR_VERTICES, AREA_FILL, AREA_POLYGON_SIZE, AREA_RECT_SIZE, AREA_STROKE, AREA_STROKE_WIDTH, DECELERATOR_LABEL, DECELERATOR_VERTICES, ECOSYSTEM_LABEL, ECOSYSTEM_SIZE, HANDLE_SIZE, INERTIA_COLOR, LABEL_DEFAULT, LABEL_FONT_SIZE, LABEL_GAP, LINK_GREY, LINK_STROKE_WIDTH, MARKET_DOT_RING, MARKET_DOT_SIZE, MARKET_DOT_STROKE_WIDTH, MARKET_LABEL, MARKET_LINK_COLOR, MARKET_LINK_WIDTH, MARKET_SIZE, METHOD_FILL, METHOD_LABEL, METHOD_SIZE, NODE_FILL, NODE_SIZE, NODE_STROKE, NODE_STROKE_WIDTH, PIPELINE_FILL, PIPELINE_HEIGHT, PIPELINE_LABEL, PIPELINE_WIDTH, PORTER_ARROW, PORTER_LETTER_FONT_SIZE, PORTER_SIZE, WARDLEY_RED, } from './node/consts.js';
4
4
  import { WARDLEY_ROLE } from './roles.js';
@@ -1,6 +1,6 @@
1
- import { sanitizeSvg, sketchSvgTree, SVG_SKETCH_EMPTY, SvgSketchNotebook, } from '@formicoidea/labre-core/blocks/surface';
2
- import { FontFamily, TextAlign } from '@formicoidea/labre-core/model';
3
- import { fillPlaceholders } from '@formicoidea/labre-core/shared/services';
1
+ import { sanitizeSvg, sketchSvgTree, SVG_SKETCH_EMPTY, SvgSketchNotebook, } from '@formicoidea/labre-core/interchange';
2
+ import { FontFamily, TextAlign } from '@formicoidea/labre-core/model/headless';
3
+ import { fillPlaceholders } from '@formicoidea/labre-core/shared/headless';
4
4
  import { OWM_DEFAULT_MAP_WIDTH, owmCoordsOf, owmDefaultPlot, WARDLEY_OWM_FORMAT_ID, } from './export.js';
5
5
  import { layoutWardleyStatements } from './import.js';
6
6
  import { NODE_STROKE } from './node/consts.js';
@@ -143,13 +143,13 @@ function extentPlot(drawn) {
143
143
  ];
144
144
  if (xs.length === 0)
145
145
  return { x0: 0, y0: 0, width: 1, height: 1 };
146
- const x0 = Math.min(...xs);
147
- const y0 = Math.min(...ys);
146
+ const x0 = xs.reduce((a, b) => Math.min(a, b), Infinity);
147
+ const y0 = ys.reduce((a, b) => Math.min(a, b), Infinity);
148
148
  return {
149
149
  x0,
150
150
  y0,
151
- width: Math.max(Math.max(...xs) - x0, 1),
152
- height: Math.max(Math.max(...ys) - y0, 1),
151
+ width: Math.max(xs.reduce((a, b) => Math.max(a, b), -Infinity) - x0, 1),
152
+ height: Math.max(ys.reduce((a, b) => Math.max(a, b), -Infinity) - y0, 1),
153
153
  };
154
154
  }
155
155
  /**
@@ -1,3 +1,4 @@
1
+ import type { XmlElement } from '@formicoidea/labre-core/interchange';
1
2
  import type { InterchangeNote } from '@formicoidea/labre-core/blocks/surface';
2
3
  import type { OwmPlot } from './export.js';
3
4
  import type { WardleyNodeKeyword } from './import.js';
@@ -63,7 +64,7 @@ export interface DrawnWardleyMap {
63
64
  y: number;
64
65
  }[];
65
66
  /** Every node the recogniser turned into the above; the sketch skips them. */
66
- consumed: Set<Element>;
67
+ consumed: Set<XmlElement>;
67
68
  /** What the recogniser has to say about the file (dangling ends, bad numbers). */
68
69
  remarks: InterchangeNote[];
69
70
  }
@@ -77,7 +78,7 @@ export interface DrawnWardleyMap {
77
78
  */
78
79
  export declare function startDrawnMap(head: Pick<DrawnWardleyMap, 'producer'> & Partial<Pick<DrawnWardleyMap, 'plot'>>): {
79
80
  drawn: DrawnWardleyMap;
80
- consume: (element: Element | undefined) => void;
81
+ consume: (element: XmlElement | undefined) => void;
81
82
  };
82
83
  /**
83
84
  * Every element carrying an `id`, first wins — the index a producer's markers
@@ -86,13 +87,13 @@ export declare function startDrawnMap(head: Pick<DrawnWardleyMap, 'producer'> &
86
87
  * A `Map`, never an object: a hostile file's `__proto__` or `constructor` is a
87
88
  * key like any other here, and can never reach a prototype (ADR 0032 §7).
88
89
  */
89
- export declare function idIndex(root: Element): Map<string, Element>;
90
+ export declare function idIndex(root: XmlElement): Map<string, XmlElement>;
90
91
  /**
91
92
  * A text's words, collapsed the way the sketch collapses a label — one span
92
93
  * per line joined by a space, so a name a producer wrapped over two `<tspan>`s
93
94
  * reads as the name and not as two words glued together.
94
95
  */
95
- export declare function textOf(element: Element | undefined): string;
96
+ export declare function textOf(element: XmlElement | undefined): string;
96
97
  /**
97
98
  * Where an element's own user-space origin lands, or `undefined` when the
98
99
  * file does not give it as numbers.
@@ -103,6 +104,6 @@ export declare function textOf(element: Element | undefined): string;
103
104
  * whose own `transform` is anything but a translate of finite numbers is
104
105
  * refused here, and the caller sends it to the sketch with a remark.
105
106
  */
106
- export declare function originOf(element: Element): [number, number] | undefined;
107
+ export declare function originOf(element: XmlElement): [number, number] | undefined;
107
108
  /** A finite number off an attribute, or `undefined`. */
108
- export declare function finiteAttr(element: Element, name: string): number | undefined;
109
+ export declare function finiteAttr(element: XmlElement, name: string): number | undefined;
package/dist/svg-read.js CHANGED
@@ -1,4 +1,4 @@
1
- import { svgFrameOf } from '@formicoidea/labre-core/blocks/surface';
1
+ import { svgFrameOf } from '@formicoidea/labre-core/interchange';
2
2
  /**
3
3
  * A recogniser's answer before it has read anything, and the one way it marks
4
4
  * an element as turned into a native one (so the sketch skips it).
@@ -1,2 +1,3 @@
1
+ import type { XmlElement } from '@formicoidea/labre-core/interchange';
1
2
  import { type DrawnWardleyMap } from './svg-read.js';
2
- export declare function recogniseLabreExport(root: Element): DrawnWardleyMap | undefined;
3
+ export declare function recogniseLabreExport(root: XmlElement): DrawnWardleyMap | undefined;
@@ -1,4 +1,4 @@
1
- import { BOARD_SVG_MARKER_VERSION } from '@formicoidea/labre-core/blocks/surface';
1
+ import { BOARD_SVG_MARKER_VERSION } from '@formicoidea/labre-core/interchange';
2
2
  import { matchLabels, owmPlotOf } from './export.js';
3
3
  import { WARDLEY_ROLE, WARDLEY_ROLES } from './roles.js';
4
4
  import { startDrawnMap } from './svg-read.js';
@@ -1,2 +1,3 @@
1
+ import type { XmlElement } from '@formicoidea/labre-core/interchange';
1
2
  import { type DrawnWardleyMap } from './svg-read.js';
2
- export declare function recogniseOnlineWardleyMaps(root: Element): DrawnWardleyMap | undefined;
3
+ export declare function recogniseOnlineWardleyMaps(root: XmlElement): DrawnWardleyMap | undefined;
@@ -1,4 +1,4 @@
1
- import { svgFrameOf } from '@formicoidea/labre-core/blocks/surface';
1
+ import { svgFrameOf } from '@formicoidea/labre-core/interchange';
2
2
  import { finiteAttr, idIndex, originOf, startDrawnMap, textOf, } from './svg-read.js';
3
3
  import { WARDLEY_SVG_IMPORT_REMARKS } from './svg-remarks.js';
4
4
  /**
@@ -1,2 +1,3 @@
1
+ import type { XmlElement } from '@formicoidea/labre-core/interchange';
1
2
  import { type DrawnWardleyMap } from './svg-read.js';
2
- export declare function recogniseWardleyMapRenderer(root: Element): DrawnWardleyMap | undefined;
3
+ export declare function recogniseWardleyMapRenderer(root: XmlElement): DrawnWardleyMap | undefined;
@@ -1,4 +1,4 @@
1
- import { svgFrameOf } from '@formicoidea/labre-core/blocks/surface';
1
+ import { svgFrameOf } from '@formicoidea/labre-core/interchange';
2
2
  import { finiteAttr, startDrawnMap, textOf, } from './svg-read.js';
3
3
  import { WARDLEY_SVG_IMPORT_REMARKS } from './svg-remarks.js';
4
4
  /**
@@ -1,2 +1,3 @@
1
+ import type { XmlElement } from '@formicoidea/labre-core/interchange';
1
2
  import { type DrawnWardleyMap } from './svg-read.js';
2
- export declare function recogniseByShape(root: Element): DrawnWardleyMap | undefined;
3
+ export declare function recogniseByShape(root: XmlElement): DrawnWardleyMap | undefined;
@@ -1,4 +1,4 @@
1
- import { svgFrameOf } from '@formicoidea/labre-core/blocks/surface';
1
+ import { svgFrameOf } from '@formicoidea/labre-core/interchange';
2
2
  import { finiteAttr, startDrawnMap, textOf, } from './svg-read.js';
3
3
  /**
4
4
  * An SVG no producer marked, read by shape (ADR 0032 §4.4, §5) — the last
@@ -150,12 +150,30 @@ export function recogniseByShape(root) {
150
150
  },
151
151
  ];
152
152
  });
153
+ // The first `<tspan>` under each `<text>`, found in one pass: a
154
+ // `querySelector` per text rebuilt its subtree each time, O(texts × depth) on
155
+ // nested texts (counter-review of 49aa247ce). Spans come in document order,
156
+ // so the first to reach an ancestor is its first; an ancestor already
157
+ // reached has had every ancestor of its own reached too.
158
+ const firstSpan = new Map();
159
+ const reached = new Set();
160
+ for (const span of root.querySelectorAll('tspan')) {
161
+ for (let at = span.parentElement; at && !reached.has(at); at = at.parentElement) {
162
+ reached.add(at);
163
+ if (at.localName === 'text')
164
+ firstSpan.set(at, span);
165
+ }
166
+ }
153
167
  const texts = Array.from(root.querySelectorAll('text')).flatMap(element => {
154
- const span = element.querySelector('tspan');
168
+ const span = firstSpan.get(element);
155
169
  const x = finiteAttr(element, 'x') ?? (span ? finiteAttr(span, 'x') : undefined);
156
170
  const y = finiteAttr(element, 'y') ?? (span ? finiteAttr(span, 'y') : undefined);
171
+ if (x === undefined || y === undefined)
172
+ return [];
173
+ // After the position: a text's content is its whole subtree, and a text
174
+ // with no position is never read.
157
175
  const name = textOf(element);
158
- if (x === undefined || y === undefined || name.length === 0)
176
+ if (name.length === 0)
159
177
  return [];
160
178
  const frame = svgFrameOf(element);
161
179
  return [
@@ -175,8 +193,10 @@ export function recogniseByShape(root) {
175
193
  if (xs.length === 0)
176
194
  return undefined;
177
195
  const extent = {
178
- w: Math.max(...xs) - Math.min(...xs),
179
- h: Math.max(...ys) - Math.min(...ys),
196
+ w: xs.reduce((a, b) => Math.max(a, b), -Infinity) -
197
+ xs.reduce((a, b) => Math.min(a, b), Infinity),
198
+ h: ys.reduce((a, b) => Math.max(a, b), -Infinity) -
199
+ ys.reduce((a, b) => Math.min(a, b), Infinity),
180
200
  };
181
201
  const found = axesOf(segments, extent);
182
202
  if (!found)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formicoidea/labre-framework-wardley",
3
3
  "description": "Labre wardley framework for @formicoidea/labre-core.",
4
- "version": "0.50.0",
4
+ "version": "0.51.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "author": "lajola",
@@ -25,13 +25,17 @@
25
25
  "./commands-manifest": {
26
26
  "types": "./dist/commands-manifest.d.ts",
27
27
  "import": "./dist/commands-manifest.js"
28
+ },
29
+ "./interchange": {
30
+ "types": "./dist/interchange-headless.d.ts",
31
+ "import": "./dist/interchange-headless.js"
28
32
  }
29
33
  },
30
34
  "files": [
31
35
  "dist"
32
36
  ],
33
37
  "dependencies": {
34
- "@formicoidea/labre-core": "0.50.0",
38
+ "@formicoidea/labre-core": "0.51.0",
35
39
  "lit": "^3.2.0"
36
40
  }
37
41
  }