yarramate 0.23.0 → 1.0.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/README.md +13 -4
- package/catalogues/core-enrichment.yaml +79 -55
- package/dist/adapter-mapping.js +6 -1
- package/dist/adapters/likec4-cli.js +36 -7
- package/dist/adapters/visual/client.d.ts +2 -2
- package/dist/adapters/visual/client.js +79 -10
- package/dist/adapters/visual/protocol-contract.d.ts +124 -10
- package/dist/adapters/visual/protocol-contract.js +12 -1
- package/dist/adapters/visual/protocol.d.ts +63 -0
- package/dist/adapters/visual/protocol.js +96 -5
- package/dist/adapters/visual/session-server.d.ts +1 -6
- package/dist/adapters/visual/session-server.js +243 -143
- package/dist/adapters/visual/session-store.d.ts +9 -0
- package/dist/adapters/visual/session-store.js +14 -5
- package/dist/adapters/visual/view-identity.d.ts +135 -0
- package/dist/adapters/visual/view-identity.js +200 -0
- package/dist/adapters/visual/wire.d.ts +19 -4
- package/dist/adapters/visual/workspace-model.d.ts +116 -0
- package/dist/adapters/visual/workspace-model.js +212 -0
- package/dist/adapters/visual-cli.d.ts +1 -1
- package/dist/adapters/visual-cli.js +30 -21
- package/dist/apply-cli.d.ts +2 -0
- package/dist/apply-cli.js +83 -0
- package/dist/apply-command.d.ts +84 -3
- package/dist/apply-command.js +218 -109
- package/dist/archimate-relationships.generated.d.ts +22 -0
- package/dist/archimate-relationships.generated.js +156 -0
- package/dist/ask-command.js +18 -6
- package/dist/attestation-staleness.js +2 -2
- package/dist/changed.js +1 -1
- package/dist/check-command.js +13 -5
- package/dist/cli-support.d.ts +1 -1
- package/dist/cli-support.js +1 -1
- package/dist/cli.js +1 -1
- package/dist/compiler.d.ts +31 -3
- package/dist/compiler.js +321 -81
- package/dist/concept-drafting.d.ts +27 -0
- package/dist/concept-drafting.js +75 -0
- package/dist/core-contract.js +6 -1
- package/dist/deletion-drafting.d.ts +52 -0
- package/dist/deletion-drafting.js +100 -0
- package/dist/evidence.js +6 -1
- package/dist/graph-projection.d.ts +14 -0
- package/dist/graph-projection.js +4 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -1
- package/dist/interrogate-command.js +63 -17
- package/dist/kind-label.d.ts +4 -3
- package/dist/kind-label.js +4 -3
- package/dist/nesting.d.ts +15 -0
- package/dist/nesting.js +2 -0
- package/dist/notation/archimate.d.ts +1 -1
- package/dist/notation/archimate.js +108 -9
- package/dist/profile.d.ts +9 -12
- package/dist/profile.js +17 -26
- package/dist/projection.d.ts +62 -3
- package/dist/projection.js +127 -43
- package/dist/relationship-drafting.d.ts +51 -0
- package/dist/relationship-drafting.js +92 -0
- package/dist/relationship-matrix.d.ts +14 -0
- package/dist/relationship-matrix.js +74 -0
- package/dist/shipped-profile.d.ts +1 -1
- package/dist/shipped-profile.js +19 -5
- package/dist/source-store.d.ts +95 -0
- package/dist/source-store.js +170 -0
- package/dist/subject-references.js +1 -1
- package/dist/visual-app/assets/index-BLcpI8WN.js +394 -0
- package/dist/visual-app/assets/index-DLutIWES.css +1 -0
- package/dist/visual-app/index.html +2 -2
- package/dist/visual-app-lib/editor.d.ts +1 -0
- package/dist/visual-app-lib/editor.js +90968 -0
- package/dist/visual-app-lib/styles.css +2 -0
- package/dist/visual-app-lib/types/adapter-mapping.d.ts +40 -0
- package/dist/visual-app-lib/types/adapters/visual/protocol-contract.d.ts +455 -0
- package/dist/visual-app-lib/types/adapters/visual/view-identity.d.ts +135 -0
- package/dist/visual-app-lib/types/adapters/visual/wire.d.ts +141 -0
- package/dist/visual-app-lib/types/adapters/visual/workspace-model.d.ts +116 -0
- package/dist/visual-app-lib/types/apply-command.d.ts +93 -0
- package/dist/visual-app-lib/types/archimate-relationships.generated.d.ts +22 -0
- package/dist/visual-app-lib/types/brief.d.ts +5 -0
- package/dist/visual-app-lib/types/compiler.d.ts +155 -0
- package/dist/visual-app-lib/types/concept-drafting.d.ts +27 -0
- package/dist/visual-app-lib/types/deletion-drafting.d.ts +52 -0
- package/dist/visual-app-lib/types/evidence.d.ts +62 -0
- package/dist/visual-app-lib/types/graph-claims.d.ts +18 -0
- package/dist/visual-app-lib/types/graph-projection.d.ts +77 -0
- package/dist/visual-app-lib/types/kind-label.d.ts +9 -0
- package/dist/visual-app-lib/types/nesting.d.ts +15 -0
- package/dist/visual-app-lib/types/notation/archimate.d.ts +71 -0
- package/dist/visual-app-lib/types/operations.d.ts +157 -0
- package/dist/visual-app-lib/types/profile.d.ts +47 -0
- package/dist/visual-app-lib/types/projection.d.ts +113 -0
- package/dist/visual-app-lib/types/relationship-drafting.d.ts +51 -0
- package/dist/visual-app-lib/types/relationship-matrix.d.ts +14 -0
- package/dist/visual-app-lib/types/shipped-profile.d.ts +2 -0
- package/dist/visual-app-lib/types/source-document.d.ts +36 -0
- package/dist/visual-app-lib/types/source-store.d.ts +95 -0
- package/dist/visual-app-lib/types/subject-references.d.ts +92 -0
- package/dist/visual-app-lib/types/visual-app/App.d.ts +15 -0
- package/dist/visual-app-lib/types/visual-app/badges.d.ts +7 -0
- package/dist/visual-app-lib/types/visual-app/changeset-tray.d.ts +106 -0
- package/dist/visual-app-lib/types/visual-app/confirm-dialog.d.ts +14 -0
- package/dist/visual-app-lib/types/visual-app/connection-panel.d.ts +23 -0
- package/dist/visual-app-lib/types/visual-app/context-menu-model.d.ts +187 -0
- package/dist/visual-app-lib/types/visual-app/context-menu.d.ts +24 -0
- package/dist/visual-app-lib/types/visual-app/describe-query.d.ts +9 -0
- package/dist/visual-app-lib/types/visual-app/editor-host.d.ts +70 -0
- package/dist/visual-app-lib/types/visual-app/faults.d.ts +26 -0
- package/dist/visual-app-lib/types/visual-app/graph-canvas.d.ts +73 -0
- package/dist/visual-app-lib/types/visual-app/kind-icons.d.ts +3 -0
- package/dist/visual-app-lib/types/visual-app/local-host.d.ts +38 -0
- package/dist/visual-app-lib/types/visual-app/mount.d.ts +56 -0
- package/dist/visual-app-lib/types/visual-app/prompt-dialog.d.ts +24 -0
- package/dist/visual-app-lib/types/visual-app/query-fields.d.ts +69 -0
- package/dist/visual-app-lib/types/visual-app/query-panel.d.ts +142 -0
- package/dist/visual-app-lib/types/visual-app/quick-filter.d.ts +11 -0
- package/dist/visual-app-lib/types/visual-app/relationship-kind-options.d.ts +50 -0
- package/dist/visual-app-lib/types/visual-app/save-view.d.ts +86 -0
- package/dist/visual-app-lib/types/visual-app/section-stack.d.ts +59 -0
- package/dist/visual-app-lib/types/visual-app/session-client.d.ts +38 -0
- package/dist/visual-app-lib/types/visual-app/state.d.ts +328 -0
- package/dist/visual-app-lib/types/visual-app/subject-draft-panel.d.ts +22 -0
- package/dist/visual-app-lib/types/visual-app/subject-form.d.ts +42 -0
- package/dist/visual-app-lib/types/visual-app/view-tree-model.d.ts +122 -0
- package/dist/visual-app-lib/types/visual-app/view-tree.d.ts +32 -0
- package/dist/visual-app-lib/types/visual-app/workspace-state.d.ts +268 -0
- package/dist/visual-app-lib/types/workspace.d.ts +29 -0
- package/dist/workspace.js +7 -1
- package/docs/CONSUMING-YARRAMATE.md +51 -2
- package/package.json +9 -2
- package/schema/yarramate-adapter-mapping.schema.json +1 -1
- package/schema/yarramate-ask-result.schema.json +24 -3
- package/schema/yarramate-check-result.schema.json +9 -0
- package/schema/yarramate-diagnostic-result.schema.json +9 -0
- package/schema/yarramate-document.schema.json +6 -0
- package/schema/yarramate-evidence-report.schema.json +1 -1
- package/schema/yarramate-evidence.schema.json +1 -1
- package/schema/yarramate-graph-v2.schema.json +34 -9
- package/schema/yarramate-likec4-generated-project-v2.schema.json +1 -1
- package/schema/yarramate-likec4-generated-project.schema.json +1 -1
- package/schema/yarramate-likec4-project.schema.json +1 -1
- package/schema/yarramate-projection-result.schema.json +3 -7
- package/schema/yarramate-projection.schema.json +16 -16
- package/schema/yarramate-reconciliation-report.schema.json +2 -2
- package/schema/yarramate-rtm.schema.json +1 -1
- package/schema/yarramate-state-comparison.schema.json +1 -1
- package/schema/yarramate-visual-diagnostic-result.schema.json +9 -0
- package/schema/yarramate-visual-event.schema.json +40 -41
- package/schema/yarramate-visual-graph.schema.json +8 -0
- package/schema/yarramate-visual-handoff.schema.json +3 -3
- package/schema/yarramate-visual-session-descriptor.schema.json +6 -6
- package/schema/yarramate-visual-session-started.schema.json +10 -9
- package/schema/yarramate-visual-status.schema.json +3 -3
- package/skills/yarramate-architecture/SKILL.md +3 -3
- package/skills/yarramate-architecture/references/modelling-patterns.md +23 -44
- package/skills/yarramate-architecture/references/native-authoring.md +32 -49
- package/skills/yarramate-architecture/references/visual-conversations.md +13 -10
- package/dist/visual-app/assets/index-CRd1Khma.js +0 -354
- package/dist/visual-app/assets/index-tZSHlU-a.css +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import type { ProjectionDefinition, ProjectionQuery } from "../../projection.js";
|
|
2
|
+
/**
|
|
3
|
+
* How a saved view gets its id, its path, and its document.
|
|
4
|
+
*
|
|
5
|
+
* The browser composes a `write-view` operation now rather than asking the
|
|
6
|
+
* server to compose one at commit time (ADR 0103): a staged row has to name
|
|
7
|
+
* the document it will write before it is committed, because that is what the
|
|
8
|
+
* reviewer reads in the tray and what the digest pins against.
|
|
9
|
+
*
|
|
10
|
+
* So this lives where both sides can reach it. No React, no cytoscape, and
|
|
11
|
+
* nothing from `node:` — the browser bundle imports it for its value, and
|
|
12
|
+
* `visual-app-browser-safety.test.ts` is what holds that honest. Validation
|
|
13
|
+
* stays on the server, where the schema and its loader are: composing a
|
|
14
|
+
* projection is arithmetic, deciding it is acceptable is not.
|
|
15
|
+
*/
|
|
16
|
+
/** Where projections live when nothing says otherwise. */
|
|
17
|
+
export declare const DEFAULT_PROJECTION_DIRECTORY = ".yarramate/projections";
|
|
18
|
+
/**
|
|
19
|
+
* Turns a view title into a schema-valid projection id: lowercase,
|
|
20
|
+
* hyphen-separated, letter-led. A title with no letters or digits degrades
|
|
21
|
+
* to "view" rather than producing an id the schema would reject.
|
|
22
|
+
*/
|
|
23
|
+
export declare const slugify: (title: string) => string;
|
|
24
|
+
/** Appends a numeric suffix only when the base id collides with a known view. */
|
|
25
|
+
export declare const uniqueViewId: (base: string, taken: ReadonlySet<string>) => string;
|
|
26
|
+
/** The id a title should take, given the ids already in use. */
|
|
27
|
+
export declare const viewIdFrom: (title: string, taken: ReadonlySet<string>) => string;
|
|
28
|
+
/**
|
|
29
|
+
* Where a view's document goes: beside every other one.
|
|
30
|
+
*
|
|
31
|
+
* The directory no longer carries meaning. Folders are DECLARED in the
|
|
32
|
+
* projection now (ADR 0104), so a view files itself with a label and the path
|
|
33
|
+
* is only an address - which is what makes "New folder" a thing the editor can
|
|
34
|
+
* do at all. Writing into a subdirectory was the one motion that could put a
|
|
35
|
+
* projection where the manifest's patterns do not reach (`YMVS315`), and the
|
|
36
|
+
* editor no longer has a reason to try.
|
|
37
|
+
*/
|
|
38
|
+
export declare const projectionPathFor: (id: string) => string;
|
|
39
|
+
/**
|
|
40
|
+
* The projection document a saved view is, composed from what the form holds.
|
|
41
|
+
*
|
|
42
|
+
* `title` and `description` are presentation fields rather than top-level
|
|
43
|
+
* ones, which is where `ProjectionDefinition` puts them, and every other
|
|
44
|
+
* presentation field the active view declared is carried through — dropping
|
|
45
|
+
* one here is how overwriting a view silently loses its nesting or direction.
|
|
46
|
+
*/
|
|
47
|
+
/** The folder a saved view declares, or `""` for none. */
|
|
48
|
+
export declare const declaredFolder: (view: {
|
|
49
|
+
readonly presentation: ProjectionDefinition["presentation"];
|
|
50
|
+
}) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Retitling a view, as a staged write.
|
|
53
|
+
*
|
|
54
|
+
* The path and the id do NOT move. A projection's id decides its filename and
|
|
55
|
+
* also keys its layout sidecar (`.yarramate/visual-layout/<id>.yaml`), so a
|
|
56
|
+
* rename that carried the id along would silently orphan the positions the
|
|
57
|
+
* reviewer dragged. Renaming is a change to what the view is called; moving it
|
|
58
|
+
* is a different motion, and not one #246 asked for.
|
|
59
|
+
*
|
|
60
|
+
* Every other presentation field the view declared is carried through by
|
|
61
|
+
* `composeProjection`, so a rename cannot quietly drop a nesting vocabulary or
|
|
62
|
+
* a direction the canvas never showed.
|
|
63
|
+
*/
|
|
64
|
+
export declare const renameView: (view: SavedView, title: string) => {
|
|
65
|
+
readonly path: string;
|
|
66
|
+
readonly projection: ProjectionDefinition;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Copying a view into a new document beside it.
|
|
70
|
+
*
|
|
71
|
+
* The copy keeps the original's folder, because a duplicate the reviewer then
|
|
72
|
+
* has to move is a duplicate in the wrong place - and it comes along for free
|
|
73
|
+
* now that a folder is a declared field `composeProjection` carries with every
|
|
74
|
+
* other one. It does NOT inherit the layout sidecar: that is keyed by id, and
|
|
75
|
+
* a copy is a different view that lays itself out.
|
|
76
|
+
*/
|
|
77
|
+
export declare const duplicateView: (view: SavedView, taken: ReadonlySet<string>) => {
|
|
78
|
+
readonly path: string;
|
|
79
|
+
readonly projection: ProjectionDefinition;
|
|
80
|
+
};
|
|
81
|
+
/** What these need of a saved view, and nothing about how it is drawn. */
|
|
82
|
+
export interface SavedView {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
readonly title: string;
|
|
85
|
+
readonly description: string;
|
|
86
|
+
readonly query: ProjectionQuery;
|
|
87
|
+
readonly presentation: ProjectionDefinition["presentation"];
|
|
88
|
+
readonly path: string;
|
|
89
|
+
}
|
|
90
|
+
export declare const composeProjection: (input: {
|
|
91
|
+
readonly id: string;
|
|
92
|
+
readonly title: string;
|
|
93
|
+
readonly description: string;
|
|
94
|
+
readonly query: ProjectionQuery;
|
|
95
|
+
readonly presentation: ProjectionDefinition["presentation"];
|
|
96
|
+
}) => ProjectionDefinition;
|
|
97
|
+
/**
|
|
98
|
+
* Whether a view can be told which subjects it holds.
|
|
99
|
+
*
|
|
100
|
+
* Only a view that ENUMERATES `subjects:` can. A view that describes its
|
|
101
|
+
* subjects with facets — a layer, a kind, a state — already includes anything
|
|
102
|
+
* matching them and excludes anything that does not, so there is nothing for a
|
|
103
|
+
* membership edit to say to it: the subject is in or out by what it is, and
|
|
104
|
+
* saying otherwise means editing the query rather than a list (#255).
|
|
105
|
+
*/
|
|
106
|
+
export declare const enumeratesSubjects: (query: ProjectionQuery) => query is ProjectionQuery & {
|
|
107
|
+
readonly subjects: readonly string[];
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* The same view, holding one more subject or one fewer.
|
|
111
|
+
*
|
|
112
|
+
* `null` when there is nothing to stage: the view describes its subjects
|
|
113
|
+
* rather than listing them, or the list already says what was asked for.
|
|
114
|
+
* Returning the absence rather than an unchanged document is what keeps a
|
|
115
|
+
* no-op out of the changeset, where a row that writes a file back exactly as
|
|
116
|
+
* it was is a row the reviewer has to read and discard for nothing.
|
|
117
|
+
*/
|
|
118
|
+
export declare const withMembership: (projection: ProjectionDefinition, subjectId: string, membership: "add" | "remove") => ProjectionDefinition | null;
|
|
119
|
+
/**
|
|
120
|
+
* What a membership edit did to a view, as the tray reads it: `+id` for a
|
|
121
|
+
* subject this row adds, `-id` for one it drops, against the document the
|
|
122
|
+
* workspace holds. Empty when the row changed something else — a title, a
|
|
123
|
+
* query, a presentation flag — which the row says by other means.
|
|
124
|
+
*/
|
|
125
|
+
export declare const membershipDelta: (saved: ProjectionQuery, staged: ProjectionQuery) => readonly string[];
|
|
126
|
+
/**
|
|
127
|
+
* Two projection documents, compared by what they SAY rather than by how they
|
|
128
|
+
* are written.
|
|
129
|
+
*
|
|
130
|
+
* Key order is the author's: a document read back off YAML holds its fields in
|
|
131
|
+
* the order someone wrote them, and one composed here holds them in the order
|
|
132
|
+
* this file writes them. Comparing the two as text reports every view as
|
|
133
|
+
* changed the moment anything touches it.
|
|
134
|
+
*/
|
|
135
|
+
export declare const sameDocument: (left: ProjectionDefinition, right: ProjectionDefinition) => boolean;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a saved view gets its id, its path, and its document.
|
|
3
|
+
*
|
|
4
|
+
* The browser composes a `write-view` operation now rather than asking the
|
|
5
|
+
* server to compose one at commit time (ADR 0103): a staged row has to name
|
|
6
|
+
* the document it will write before it is committed, because that is what the
|
|
7
|
+
* reviewer reads in the tray and what the digest pins against.
|
|
8
|
+
*
|
|
9
|
+
* So this lives where both sides can reach it. No React, no cytoscape, and
|
|
10
|
+
* nothing from `node:` — the browser bundle imports it for its value, and
|
|
11
|
+
* `visual-app-browser-safety.test.ts` is what holds that honest. Validation
|
|
12
|
+
* stays on the server, where the schema and its loader are: composing a
|
|
13
|
+
* projection is arithmetic, deciding it is acceptable is not.
|
|
14
|
+
*/
|
|
15
|
+
/** Where projections live when nothing says otherwise. */
|
|
16
|
+
export const DEFAULT_PROJECTION_DIRECTORY = ".yarramate/projections";
|
|
17
|
+
/**
|
|
18
|
+
* Turns a view title into a schema-valid projection id: lowercase,
|
|
19
|
+
* hyphen-separated, letter-led. A title with no letters or digits degrades
|
|
20
|
+
* to "view" rather than producing an id the schema would reject.
|
|
21
|
+
*/
|
|
22
|
+
export const slugify = (title) => {
|
|
23
|
+
const cleaned = title
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
26
|
+
.replace(/^-+|-+$/g, "");
|
|
27
|
+
if (cleaned.length === 0)
|
|
28
|
+
return "view";
|
|
29
|
+
return /^[a-z]/.test(cleaned) ? cleaned : `view-${cleaned}`;
|
|
30
|
+
};
|
|
31
|
+
/** Appends a numeric suffix only when the base id collides with a known view. */
|
|
32
|
+
export const uniqueViewId = (base, taken) => {
|
|
33
|
+
if (!taken.has(base))
|
|
34
|
+
return base;
|
|
35
|
+
let suffix = 2;
|
|
36
|
+
while (taken.has(`${base}-${suffix}`))
|
|
37
|
+
suffix += 1;
|
|
38
|
+
return `${base}-${suffix}`;
|
|
39
|
+
};
|
|
40
|
+
/** The id a title should take, given the ids already in use. */
|
|
41
|
+
export const viewIdFrom = (title, taken) => uniqueViewId(slugify(title), taken);
|
|
42
|
+
/**
|
|
43
|
+
* Where a view's document goes: beside every other one.
|
|
44
|
+
*
|
|
45
|
+
* The directory no longer carries meaning. Folders are DECLARED in the
|
|
46
|
+
* projection now (ADR 0104), so a view files itself with a label and the path
|
|
47
|
+
* is only an address - which is what makes "New folder" a thing the editor can
|
|
48
|
+
* do at all. Writing into a subdirectory was the one motion that could put a
|
|
49
|
+
* projection where the manifest's patterns do not reach (`YMVS315`), and the
|
|
50
|
+
* editor no longer has a reason to try.
|
|
51
|
+
*/
|
|
52
|
+
export const projectionPathFor = (id) => `${DEFAULT_PROJECTION_DIRECTORY}/${id}.yaml`;
|
|
53
|
+
/**
|
|
54
|
+
* The projection document a saved view is, composed from what the form holds.
|
|
55
|
+
*
|
|
56
|
+
* `title` and `description` are presentation fields rather than top-level
|
|
57
|
+
* ones, which is where `ProjectionDefinition` puts them, and every other
|
|
58
|
+
* presentation field the active view declared is carried through — dropping
|
|
59
|
+
* one here is how overwriting a view silently loses its nesting or direction.
|
|
60
|
+
*/
|
|
61
|
+
/** The folder a saved view declares, or `""` for none. */
|
|
62
|
+
export const declaredFolder = (view) => view.presentation?.folder ?? "";
|
|
63
|
+
/**
|
|
64
|
+
* Retitling a view, as a staged write.
|
|
65
|
+
*
|
|
66
|
+
* The path and the id do NOT move. A projection's id decides its filename and
|
|
67
|
+
* also keys its layout sidecar (`.yarramate/visual-layout/<id>.yaml`), so a
|
|
68
|
+
* rename that carried the id along would silently orphan the positions the
|
|
69
|
+
* reviewer dragged. Renaming is a change to what the view is called; moving it
|
|
70
|
+
* is a different motion, and not one #246 asked for.
|
|
71
|
+
*
|
|
72
|
+
* Every other presentation field the view declared is carried through by
|
|
73
|
+
* `composeProjection`, so a rename cannot quietly drop a nesting vocabulary or
|
|
74
|
+
* a direction the canvas never showed.
|
|
75
|
+
*/
|
|
76
|
+
export const renameView = (view, title) => ({
|
|
77
|
+
path: view.path,
|
|
78
|
+
projection: composeProjection({
|
|
79
|
+
id: view.id,
|
|
80
|
+
title,
|
|
81
|
+
description: view.description,
|
|
82
|
+
query: view.query,
|
|
83
|
+
presentation: view.presentation,
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Copying a view into a new document beside it.
|
|
88
|
+
*
|
|
89
|
+
* The copy keeps the original's folder, because a duplicate the reviewer then
|
|
90
|
+
* has to move is a duplicate in the wrong place - and it comes along for free
|
|
91
|
+
* now that a folder is a declared field `composeProjection` carries with every
|
|
92
|
+
* other one. It does NOT inherit the layout sidecar: that is keyed by id, and
|
|
93
|
+
* a copy is a different view that lays itself out.
|
|
94
|
+
*/
|
|
95
|
+
export const duplicateView = (view, taken) => {
|
|
96
|
+
const title = `${view.title} copy`;
|
|
97
|
+
const id = viewIdFrom(title, taken);
|
|
98
|
+
return {
|
|
99
|
+
path: projectionPathFor(id),
|
|
100
|
+
projection: composeProjection({
|
|
101
|
+
id,
|
|
102
|
+
title,
|
|
103
|
+
description: view.description,
|
|
104
|
+
query: view.query,
|
|
105
|
+
presentation: view.presentation,
|
|
106
|
+
}),
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
export const composeProjection = (input) => ({
|
|
110
|
+
format: "yarramate/projection/v1",
|
|
111
|
+
id: input.id,
|
|
112
|
+
version: "1.0",
|
|
113
|
+
query: input.query,
|
|
114
|
+
presentation: {
|
|
115
|
+
...(input.presentation ?? {}),
|
|
116
|
+
title: input.title,
|
|
117
|
+
description: input.description,
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
/**
|
|
121
|
+
* Whether a view can be told which subjects it holds.
|
|
122
|
+
*
|
|
123
|
+
* Only a view that ENUMERATES `subjects:` can. A view that describes its
|
|
124
|
+
* subjects with facets — a layer, a kind, a state — already includes anything
|
|
125
|
+
* matching them and excludes anything that does not, so there is nothing for a
|
|
126
|
+
* membership edit to say to it: the subject is in or out by what it is, and
|
|
127
|
+
* saying otherwise means editing the query rather than a list (#255).
|
|
128
|
+
*/
|
|
129
|
+
export const enumeratesSubjects = (query) => query.subjects !== undefined;
|
|
130
|
+
/**
|
|
131
|
+
* The same view, holding one more subject or one fewer.
|
|
132
|
+
*
|
|
133
|
+
* `null` when there is nothing to stage: the view describes its subjects
|
|
134
|
+
* rather than listing them, or the list already says what was asked for.
|
|
135
|
+
* Returning the absence rather than an unchanged document is what keeps a
|
|
136
|
+
* no-op out of the changeset, where a row that writes a file back exactly as
|
|
137
|
+
* it was is a row the reviewer has to read and discard for nothing.
|
|
138
|
+
*/
|
|
139
|
+
export const withMembership = (projection, subjectId, membership) => {
|
|
140
|
+
if (!enumeratesSubjects(projection.query))
|
|
141
|
+
return null;
|
|
142
|
+
const subjects = projection.query.subjects;
|
|
143
|
+
const holds = subjects.includes(subjectId);
|
|
144
|
+
if (membership === "add" ? holds : !holds)
|
|
145
|
+
return null;
|
|
146
|
+
return {
|
|
147
|
+
...projection,
|
|
148
|
+
query: {
|
|
149
|
+
...projection.query,
|
|
150
|
+
subjects: membership === "add"
|
|
151
|
+
? // Appended rather than sorted in: the list is the author's, and
|
|
152
|
+
// reordering it would rewrite lines nobody touched.
|
|
153
|
+
[...subjects, subjectId]
|
|
154
|
+
: subjects.filter((id) => id !== subjectId),
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* What a membership edit did to a view, as the tray reads it: `+id` for a
|
|
160
|
+
* subject this row adds, `-id` for one it drops, against the document the
|
|
161
|
+
* workspace holds. Empty when the row changed something else — a title, a
|
|
162
|
+
* query, a presentation flag — which the row says by other means.
|
|
163
|
+
*/
|
|
164
|
+
export const membershipDelta = (saved, staged) => {
|
|
165
|
+
if (!enumeratesSubjects(saved) || !enumeratesSubjects(staged))
|
|
166
|
+
return [];
|
|
167
|
+
return [
|
|
168
|
+
...staged.subjects
|
|
169
|
+
.filter((id) => !saved.subjects.includes(id))
|
|
170
|
+
.map((id) => `+${id}`),
|
|
171
|
+
...saved.subjects
|
|
172
|
+
.filter((id) => !staged.subjects.includes(id))
|
|
173
|
+
.map((id) => `-${id}`),
|
|
174
|
+
];
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Two projection documents, compared by what they SAY rather than by how they
|
|
178
|
+
* are written.
|
|
179
|
+
*
|
|
180
|
+
* Key order is the author's: a document read back off YAML holds its fields in
|
|
181
|
+
* the order someone wrote them, and one composed here holds them in the order
|
|
182
|
+
* this file writes them. Comparing the two as text reports every view as
|
|
183
|
+
* changed the moment anything touches it.
|
|
184
|
+
*/
|
|
185
|
+
export const sameDocument = (left, right) => canonical(left) === canonical(right);
|
|
186
|
+
const canonical = (value) => {
|
|
187
|
+
if (Array.isArray(value)) {
|
|
188
|
+
// Order is meaningful inside a list - a subjects list is the author's own
|
|
189
|
+
// ordering - so only object keys are sorted.
|
|
190
|
+
return `[${value.map(canonical).join(",")}]`;
|
|
191
|
+
}
|
|
192
|
+
if (value !== null && typeof value === "object") {
|
|
193
|
+
return `{${Object.entries(value)
|
|
194
|
+
.filter(([, entry]) => entry !== undefined)
|
|
195
|
+
.sort(([a], [b]) => (a < b ? -1 : 1))
|
|
196
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${canonical(entry)}`)
|
|
197
|
+
.join(",")}}`;
|
|
198
|
+
}
|
|
199
|
+
return JSON.stringify(value) ?? "null";
|
|
200
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CanvasGraph } from '../../graph-projection.js';
|
|
2
|
-
import type { VISUAL_PROTOCOL_VERSION, VisualApplyResultPayload, VisualAuthority, VisualBrowserInput, VisualCapabilities, VisualChoicePresentPayload, VisualDiagnostic, VisualFilterResultPayload, VisualFreezeReason, VisualKindOption, VisualLayoutPositions, VisualLayoutSaveResultPayload, VisualResponse, VisualTerminationReason,
|
|
2
|
+
import type { VISUAL_PROTOCOL_VERSION, VisualApplyResultPayload, VisualAuthority, VisualBrowserInput, VisualCapabilities, VisualChoicePresentPayload, VisualDiagnostic, VisualFilterResultPayload, VisualFreezeReason, VisualKindOption, VisualLayoutPositions, VisualLayoutSaveResultPayload, VisualResponse, VisualTerminationReason, VisualViewSummary } from './protocol-contract.js';
|
|
3
3
|
/**
|
|
4
4
|
* Transport shapes the session server and the browser application both speak.
|
|
5
5
|
*
|
|
@@ -32,6 +32,17 @@ export interface VisualRenderedModel {
|
|
|
32
32
|
* can state what it rendered when it asks for a commit.
|
|
33
33
|
*/
|
|
34
34
|
readonly sourceDigests: Readonly<Record<string, string>>;
|
|
35
|
+
/**
|
|
36
|
+
* The sha256 of every projection this session knows about, keyed by
|
|
37
|
+
* manifest-relative path.
|
|
38
|
+
*
|
|
39
|
+
* Kept apart from `sourceDigests` rather than folded into it: that map means
|
|
40
|
+
* what the GRAPH was compiled from, which `YMVS112` requires a canonical
|
|
41
|
+
* model to state, and a projection is not part of it. A staged view
|
|
42
|
+
* operation pins against this one instead (ADR 0103), and a path absent from
|
|
43
|
+
* it is a projection the commit will create.
|
|
44
|
+
*/
|
|
45
|
+
readonly projectionDigests: Readonly<Record<string, string>>;
|
|
35
46
|
}
|
|
36
47
|
/**
|
|
37
48
|
* One line of the conversation, as plain text.
|
|
@@ -108,12 +119,16 @@ export type VisualServerFrame = {
|
|
|
108
119
|
} | {
|
|
109
120
|
readonly kind: 'model';
|
|
110
121
|
readonly model: VisualRenderedModel;
|
|
122
|
+
/**
|
|
123
|
+
* The saved views again, because a recompile moves what their queries
|
|
124
|
+
* match and the tree states those counts. Required rather than optional:
|
|
125
|
+
* a recompile that shipped a graph without them would leave every count
|
|
126
|
+
* beside it describing the model before the commit.
|
|
127
|
+
*/
|
|
128
|
+
readonly views: readonly VisualViewSummary[];
|
|
111
129
|
} | {
|
|
112
130
|
readonly kind: 'filter-result';
|
|
113
131
|
readonly result: VisualFilterResultPayload;
|
|
114
|
-
} | {
|
|
115
|
-
readonly kind: 'view-save-result';
|
|
116
|
-
readonly result: VisualViewSaveResultPayload;
|
|
117
132
|
} | {
|
|
118
133
|
readonly kind: 'apply-result';
|
|
119
134
|
readonly result: VisualApplyResultPayload;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Diagnostic } from "../../compiler.js";
|
|
2
|
+
import type { PendingWrite, SourceStore } from "../../source-store.js";
|
|
3
|
+
import type { ResolvedWorkspace } from "../../workspace.js";
|
|
4
|
+
import type { VisualDiagnostic, VisualViewOperation } from "./protocol-contract.js";
|
|
5
|
+
import type { ProjectionDefinition, ProjectionExclusion, ProjectionQuery } from "../../projection.js";
|
|
6
|
+
import type { ResolvedProfileContext, SemanticGraph } from "../../compiler.js";
|
|
7
|
+
import type { VisualKindOption, VisualViewSummary } from "./protocol-contract.js";
|
|
8
|
+
import type { VisualRenderedModel } from "./wire.js";
|
|
9
|
+
/**
|
|
10
|
+
* What a workspace looks like to the editor, however the editor is being run
|
|
11
|
+
* (#252).
|
|
12
|
+
*
|
|
13
|
+
* These were the session server's, and the session server is one host now: an
|
|
14
|
+
* embedder mounting the editor over its own store computes the same model, the
|
|
15
|
+
* same vocabulary and the same view counts, and two definitions of any of them
|
|
16
|
+
* would be two answers to the same question. So the arithmetic lives here and
|
|
17
|
+
* the orchestration - which bytes to read, which digests to pin, what a layout
|
|
18
|
+
* sidecar says - stays with whoever owns those.
|
|
19
|
+
*
|
|
20
|
+
* Browser-safe: no `node:`, no filesystem, no session. Everything is a pure
|
|
21
|
+
* function of a compile result.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* The kinds a browser may offer, each with the core kind it descends from.
|
|
25
|
+
*
|
|
26
|
+
* `[0]` is the nearest declared ancestor, the same reading
|
|
27
|
+
* `projectGraphForCanvas` gives an authored subject its `coreKindLabel`. A kind
|
|
28
|
+
* with no lineage IS a core kind and stands for itself. Without the core label
|
|
29
|
+
* an editor can read a palette but cannot judge it: the ArchiMate table is
|
|
30
|
+
* keyed on core kinds, so offering an extension kind unchecked puts a `YM404`
|
|
31
|
+
* one click away.
|
|
32
|
+
*/
|
|
33
|
+
export declare const kindOptionsOf: (lineages: ReadonlyMap<string, readonly string[]>) => readonly VisualKindOption[];
|
|
34
|
+
/**
|
|
35
|
+
* How many SUBJECTS a query matches, which is not the size of its match set.
|
|
36
|
+
*
|
|
37
|
+
* A `SemanticGraph`'s subjects are concepts and relationships together, so the
|
|
38
|
+
* match set returns both — right for narrowing a canvas that draws edges as
|
|
39
|
+
* well as nodes, and wrong for a number sitting beside a view called its
|
|
40
|
+
* subject count. A view over three components with two relationships between
|
|
41
|
+
* them would read as five, and the reviewer counting boxes would find three.
|
|
42
|
+
*/
|
|
43
|
+
export declare const conceptCountOf: (graph: SemanticGraph, query: ProjectionQuery, profileContext: ResolvedProfileContext) => number;
|
|
44
|
+
/**
|
|
45
|
+
* Rebuilds the shared editor workspace from one successful compile.
|
|
46
|
+
*
|
|
47
|
+
* The caller owns metadata which cannot be inferred from a graph (authority,
|
|
48
|
+
* source revisions, layouts, and initial view); this helper owns all derived
|
|
49
|
+
* canvas, vocabulary, and view-count arithmetic.
|
|
50
|
+
*/
|
|
51
|
+
export declare const renderedWorkspaceOf: (compiled: {
|
|
52
|
+
readonly graph: SemanticGraph;
|
|
53
|
+
readonly profileContext: ResolvedProfileContext;
|
|
54
|
+
}, views: readonly VisualViewSummary[], metadata: Omit<VisualRenderedModel, "graph" | "vocabulary">) => {
|
|
55
|
+
readonly model: VisualRenderedModel;
|
|
56
|
+
readonly views: readonly VisualViewSummary[];
|
|
57
|
+
};
|
|
58
|
+
/** Every subject a query draws, concepts and relationships alike. */
|
|
59
|
+
export declare const matchedIdsOf: (graph: SemanticGraph, query: ProjectionQuery, profileContext: ResolvedProfileContext) => readonly string[];
|
|
60
|
+
/** Every concept a query dropped, and the facet that dropped it (#248). */
|
|
61
|
+
export declare const exclusionsOf: (graph: SemanticGraph, query: ProjectionQuery, profileContext: ResolvedProfileContext) => readonly ProjectionExclusion[];
|
|
62
|
+
/**
|
|
63
|
+
* One saved view, as the rail reads it. `subjectCount` is the caller's,
|
|
64
|
+
* because counting needs a compiled graph and a session builds its first list
|
|
65
|
+
* before it has one.
|
|
66
|
+
*/
|
|
67
|
+
export declare const viewSummaryOf: (projection: ProjectionDefinition, path: string, subjectCount?: number) => VisualViewSummary;
|
|
68
|
+
/**
|
|
69
|
+
* Applies a landed view batch to a host-owned list.
|
|
70
|
+
*
|
|
71
|
+
* Writes are read back through the callback, so a malformed or otherwise
|
|
72
|
+
* unreadable landed document cannot become a fabricated summary.
|
|
73
|
+
*/
|
|
74
|
+
export declare const adoptLandedViews: (views: readonly VisualViewSummary[], operations: readonly VisualViewOperation[], readSummary: (path: string) => VisualViewSummary | undefined) => readonly VisualViewSummary[];
|
|
75
|
+
/**
|
|
76
|
+
* The document a diagnostic the runtime minted itself points at. Not a file:
|
|
77
|
+
* these are about the session rather than about anything the workspace holds.
|
|
78
|
+
*/
|
|
79
|
+
export declare const VISUAL_SERVER_DOCUMENT = "visual-session-server";
|
|
80
|
+
export declare const published: (diagnostics: readonly Diagnostic[], sources: readonly {
|
|
81
|
+
readonly path: string;
|
|
82
|
+
readonly source: string;
|
|
83
|
+
}[]) => readonly VisualDiagnostic[];
|
|
84
|
+
export declare const serverDiagnostic: (code: string, message: string, pointer?: string) => VisualDiagnostic;
|
|
85
|
+
/**
|
|
86
|
+
* Whether the workspace would load a projection written at this path.
|
|
87
|
+
*
|
|
88
|
+
* This is a DIRECTORY check, not a pattern match, and deliberately so: ADR
|
|
89
|
+
* 0100 recorded that the manifest's pattern dialect has never been named - it
|
|
90
|
+
* is whatever `globSync` happens to support, undocumented and untested past
|
|
91
|
+
* one wildcard - so a matcher written here would be inventing the dialect
|
|
92
|
+
* rather than honouring it. A directory that already holds a projection the
|
|
93
|
+
* manifest resolved is a directory the manifest demonstrably reaches.
|
|
94
|
+
*
|
|
95
|
+
* A workspace with no projections at all has nothing to demonstrate, so the
|
|
96
|
+
* default directory is allowed: refusing there would make the first view in a
|
|
97
|
+
* fresh workspace impossible to create.
|
|
98
|
+
*/
|
|
99
|
+
export declare const projectionDirectoryIsCovered: (path: string, workspace: ResolvedWorkspace) => boolean;
|
|
100
|
+
/**
|
|
101
|
+
* Turns staged view operations into pending writes, refusing before anything
|
|
102
|
+
* is written (ADR 0103).
|
|
103
|
+
*
|
|
104
|
+
* A `write-view` is validated through the same `loadProjection` the CLI's own
|
|
105
|
+
* projection writes go through, so a document the schema would reject never
|
|
106
|
+
* reaches the store. A `delete-view` names a revision, which is what makes a
|
|
107
|
+
* removal refusable rather than a silent success on a file someone else
|
|
108
|
+
* already changed.
|
|
109
|
+
*/
|
|
110
|
+
export declare const planViewWrites: (operations: readonly VisualViewOperation[], workspace: ResolvedWorkspace, store: SourceStore) => {
|
|
111
|
+
readonly ok: true;
|
|
112
|
+
readonly writes: readonly PendingWrite[];
|
|
113
|
+
} | {
|
|
114
|
+
readonly ok: false;
|
|
115
|
+
readonly diagnostics: readonly VisualDiagnostic[];
|
|
116
|
+
};
|