@memoarchitect/tools 0.4.6 → 0.6.1
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 +8 -5
- package/package.json +3 -3
- package/packages/tools/lib/bin/memo.js +3 -5
- package/packages/tools/lib/bin/memo.js.map +1 -1
- package/packages/tools/lib/browser/index.d.ts +2 -0
- package/packages/tools/lib/browser/index.d.ts.map +1 -1
- package/packages/tools/lib/browser/index.js +2 -0
- package/packages/tools/lib/browser/index.js.map +1 -1
- package/packages/tools/lib/commands/create-package.js +1 -1
- package/packages/tools/lib/commands/dev.d.ts.map +1 -1
- package/packages/tools/lib/commands/dev.js +40 -5
- package/packages/tools/lib/commands/dev.js.map +1 -1
- package/packages/tools/lib/commands/init.d.ts +7 -4
- package/packages/tools/lib/commands/init.d.ts.map +1 -1
- package/packages/tools/lib/commands/init.js +30 -37
- package/packages/tools/lib/commands/init.js.map +1 -1
- package/packages/tools/lib/commands/install.js +1 -1
- package/packages/tools/lib/commands/ontology.js +1 -1
- package/packages/tools/lib/commands/ontology.js.map +1 -1
- package/packages/tools/lib/dhf/document-registry.js +5 -5
- package/packages/tools/lib/dhf/document-registry.js.map +1 -1
- package/packages/tools/lib/dhf/template-engine.js +3 -3
- package/packages/tools/lib/dhf/template-engine.js.map +1 -1
- package/packages/tools/lib/importer/cameo-importer.d.ts.map +1 -1
- package/packages/tools/lib/importer/cameo-importer.js +5 -2
- package/packages/tools/lib/importer/cameo-importer.js.map +1 -1
- package/packages/tools/lib/importer/ea-importer.d.ts +1 -1
- package/packages/tools/lib/importer/ea-importer.d.ts.map +1 -1
- package/packages/tools/lib/importer/ea-importer.js +6 -4
- package/packages/tools/lib/importer/ea-importer.js.map +1 -1
- package/packages/tools/lib/index.d.ts +2 -0
- package/packages/tools/lib/index.d.ts.map +1 -1
- package/packages/tools/lib/index.js +2 -0
- package/packages/tools/lib/index.js.map +1 -1
- package/packages/tools/lib/language/generated/ast.d.ts +409 -42
- package/packages/tools/lib/language/generated/ast.d.ts.map +1 -1
- package/packages/tools/lib/language/generated/ast.js +318 -12
- package/packages/tools/lib/language/generated/ast.js.map +1 -1
- package/packages/tools/lib/language/generated/grammar.d.ts.map +1 -1
- package/packages/tools/lib/language/generated/grammar.js +1732 -513
- package/packages/tools/lib/language/generated/grammar.js.map +1 -1
- package/packages/tools/lib/model/builder.d.ts.map +1 -1
- package/packages/tools/lib/model/builder.js +38 -14
- package/packages/tools/lib/model/builder.js.map +1 -1
- package/packages/tools/lib/model/config.d.ts +11 -1
- package/packages/tools/lib/model/config.d.ts.map +1 -1
- package/packages/tools/lib/model/kind-registry.d.ts +11 -0
- package/packages/tools/lib/model/kind-registry.d.ts.map +1 -1
- package/packages/tools/lib/model/kind-registry.js +33 -7
- package/packages/tools/lib/model/kind-registry.js.map +1 -1
- package/packages/tools/lib/model/layer-resolver.d.ts +10 -0
- package/packages/tools/lib/model/layer-resolver.d.ts.map +1 -1
- package/packages/tools/lib/model/layer-resolver.js +49 -0
- package/packages/tools/lib/model/layer-resolver.js.map +1 -1
- package/packages/tools/lib/model/manifest.d.ts +2 -2
- package/packages/tools/lib/model/manifest.d.ts.map +1 -1
- package/packages/tools/lib/model/manifest.js +3 -2
- package/packages/tools/lib/model/manifest.js.map +1 -1
- package/packages/tools/lib/model/ontology-loader.d.ts +2 -0
- package/packages/tools/lib/model/ontology-loader.d.ts.map +1 -1
- package/packages/tools/lib/model/ontology-loader.js +92 -28
- package/packages/tools/lib/model/ontology-loader.js.map +1 -1
- package/packages/tools/lib/model/parser-utils.d.ts +9 -0
- package/packages/tools/lib/model/parser-utils.d.ts.map +1 -1
- package/packages/tools/lib/model/parser-utils.js +24 -0
- package/packages/tools/lib/model/parser-utils.js.map +1 -1
- package/packages/tools/lib/model/paths.d.ts +0 -2
- package/packages/tools/lib/model/paths.d.ts.map +1 -1
- package/packages/tools/lib/model/paths.js +0 -2
- package/packages/tools/lib/model/paths.js.map +1 -1
- package/packages/tools/lib/model/relationship-legality.d.ts +266 -0
- package/packages/tools/lib/model/relationship-legality.d.ts.map +1 -0
- package/packages/tools/lib/model/relationship-legality.js +391 -0
- package/packages/tools/lib/model/relationship-legality.js.map +1 -0
- package/packages/tools/lib/model/relationship-registry.d.ts +38 -4
- package/packages/tools/lib/model/relationship-registry.d.ts.map +1 -1
- package/packages/tools/lib/model/relationship-registry.js +109 -1
- package/packages/tools/lib/model/relationship-registry.js.map +1 -1
- package/packages/tools/lib/model/semantic.d.ts +42 -0
- package/packages/tools/lib/model/semantic.d.ts.map +1 -1
- package/packages/tools/lib/model/semantic.js +3 -0
- package/packages/tools/lib/model/semantic.js.map +1 -1
- package/packages/tools/lib/model/short-id.js +1 -1
- package/packages/tools/lib/model/short-id.js.map +1 -1
- package/packages/tools/lib/model/source-affinity.d.ts +21 -0
- package/packages/tools/lib/model/source-affinity.d.ts.map +1 -0
- package/packages/tools/lib/model/source-affinity.js +42 -0
- package/packages/tools/lib/model/source-affinity.js.map +1 -0
- package/packages/tools/lib/model/source-graph.d.ts +30 -0
- package/packages/tools/lib/model/source-graph.d.ts.map +1 -0
- package/packages/tools/lib/model/source-graph.js +154 -0
- package/packages/tools/lib/model/source-graph.js.map +1 -0
- package/packages/tools/lib/model/view-kinds.d.ts.map +1 -1
- package/packages/tools/lib/model/view-kinds.js +1 -0
- package/packages/tools/lib/model/view-kinds.js.map +1 -1
- package/packages/tools/lib/operations/project-snapshot.d.ts.map +1 -1
- package/packages/tools/lib/operations/project-snapshot.js +2 -15
- package/packages/tools/lib/operations/project-snapshot.js.map +1 -1
- package/packages/tools/lib/protocol/messages.d.ts +92 -8
- package/packages/tools/lib/protocol/messages.d.ts.map +1 -1
- package/packages/tools/lib/server/dev-server.d.ts +16 -0
- package/packages/tools/lib/server/dev-server.d.ts.map +1 -1
- package/packages/tools/lib/server/dev-server.js +190 -16
- package/packages/tools/lib/server/dev-server.js.map +1 -1
- package/packages/tools/lib/server/file-watcher.d.ts +21 -2
- package/packages/tools/lib/server/file-watcher.d.ts.map +1 -1
- package/packages/tools/lib/server/file-watcher.js +55 -23
- package/packages/tools/lib/server/file-watcher.js.map +1 -1
- package/packages/tools/lib/server/persistor.d.ts +0 -13
- package/packages/tools/lib/server/persistor.d.ts.map +1 -1
- package/packages/tools/lib/server/persistor.js +3 -31
- package/packages/tools/lib/server/persistor.js.map +1 -1
- package/packages/tools/lib/server/relationship-writer.d.ts +104 -0
- package/packages/tools/lib/server/relationship-writer.d.ts.map +1 -0
- package/packages/tools/lib/server/relationship-writer.js +402 -0
- package/packages/tools/lib/server/relationship-writer.js.map +1 -0
- package/packages/tools/lib/server/view-layout-store.d.ts +14 -1
- package/packages/tools/lib/server/view-layout-store.d.ts.map +1 -1
- package/packages/tools/lib/server/view-layout-store.js +63 -11
- package/packages/tools/lib/server/view-layout-store.js.map +1 -1
- package/packages/tools/src/grammar/memo-sysml.langium +102 -18
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
// ─── Relationship Writer ──────────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Persists model relationships as typed SysML connection usages, and removes
|
|
4
|
+
// them again. A relationship is a semantic model fact, so it is always written
|
|
5
|
+
// into project SysML — never into a diagram, layout sidecar, or UI state.
|
|
6
|
+
//
|
|
7
|
+
// Editing is CST-aware: the file is parsed, the edit is applied by source
|
|
8
|
+
// offset so comments and unrelated declarations survive untouched, the result
|
|
9
|
+
// is reparsed and validated, and only then does it atomically replace the file.
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
12
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
13
|
+
import { parseText } from '../model/parser-utils.js';
|
|
14
|
+
import { isConnectionUsage, isPackageDeclaration, } from '../language/generated/ast.js';
|
|
15
|
+
// Project-layout conventions, not ontology semantics — these describe where a
|
|
16
|
+
// MEMO project keeps its files, so they are overridable per project rather than
|
|
17
|
+
// fixed in the engine.
|
|
18
|
+
/** Default file used when the project has no better home for a relationship. */
|
|
19
|
+
export const CANONICAL_RELATIONSHIP_FILE = 'model/relationships.sysml';
|
|
20
|
+
/** Directory segments holding view/presentation SysML — never a relationship home. */
|
|
21
|
+
export const DEFAULT_PRESENTATION_DIRS = ['views'];
|
|
22
|
+
/** Filenames a package uses to collect its relationships. */
|
|
23
|
+
export const DEFAULT_RELATIONSHIP_FILE_PATTERN = /relationships?\.sysml$/i;
|
|
24
|
+
// ─── Path guards ────────────────────────────────────────────────────────────
|
|
25
|
+
/**
|
|
26
|
+
* Whether a project-relative path is a legal home for a model relationship.
|
|
27
|
+
*
|
|
28
|
+
* Rejects anything outside the project, non-.sysml files, installed ontology
|
|
29
|
+
* content, and the diagram presentation section. Symlinks are resolved before
|
|
30
|
+
* the containment check so an in-tree link cannot escape the project.
|
|
31
|
+
*/
|
|
32
|
+
export function isWritableRelationshipFile(relativePath, options) {
|
|
33
|
+
if (!relativePath || !relativePath.endsWith('.sysml'))
|
|
34
|
+
return false;
|
|
35
|
+
const projectRoot = realpathSync(resolve(options.projectRoot));
|
|
36
|
+
const requested = resolve(projectRoot, relativePath);
|
|
37
|
+
// Resolve symlinks for files that already exist; a new file is judged by
|
|
38
|
+
// the real path of the closest existing ancestor directory.
|
|
39
|
+
let real = requested;
|
|
40
|
+
if (existsSync(requested)) {
|
|
41
|
+
real = realpathSync(requested);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
let dir = dirname(requested);
|
|
45
|
+
while (!existsSync(dir) && dirname(dir) !== dir)
|
|
46
|
+
dir = dirname(dir);
|
|
47
|
+
real = join(realpathSync(dir), relative(dir, requested));
|
|
48
|
+
}
|
|
49
|
+
const rel = relative(projectRoot, real);
|
|
50
|
+
if (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel))
|
|
51
|
+
return false;
|
|
52
|
+
// Installed ontology and library content is read-only.
|
|
53
|
+
const segments = rel.split(sep);
|
|
54
|
+
if (segments.includes('node_modules'))
|
|
55
|
+
return false;
|
|
56
|
+
for (const root of options.ontologyRoots ?? []) {
|
|
57
|
+
const ontologyReal = existsSync(root) ? realpathSync(root) : resolve(root);
|
|
58
|
+
const fromOntology = relative(ontologyReal, real);
|
|
59
|
+
if (fromOntology && !fromOntology.startsWith('..') && !isAbsolute(fromOntology))
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
// A relationship is a model fact, not presentation — keep it out of views/.
|
|
63
|
+
const presentationDirs = options.presentationDirs ?? DEFAULT_PRESENTATION_DIRS;
|
|
64
|
+
if (segments.some(segment => presentationDirs.includes(segment)))
|
|
65
|
+
return false;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
// ─── Ownership policy ───────────────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Choose the file that will own a new relationship, deterministically:
|
|
71
|
+
*
|
|
72
|
+
* 1. the file the request explicitly asked for
|
|
73
|
+
* 2. the designated relationship file of the active model package
|
|
74
|
+
* 3. an existing relationships file in the nearest common package of both
|
|
75
|
+
* endpoints, else the source element's own file within that package
|
|
76
|
+
* 4. the configured canonical relationship file, when it already exists
|
|
77
|
+
* 5. the canonical file, created only because nothing above was suitable
|
|
78
|
+
*
|
|
79
|
+
* Every candidate passes isWritableRelationshipFile before it is considered.
|
|
80
|
+
*/
|
|
81
|
+
export function resolveRelationshipPlacement(request, model, options) {
|
|
82
|
+
const accept = (file) => isWritableRelationshipFile(file, options);
|
|
83
|
+
const exists = (file) => existsSync(resolve(options.projectRoot, file));
|
|
84
|
+
// 1 — explicit request.
|
|
85
|
+
if (request.owningFile && accept(request.owningFile)) {
|
|
86
|
+
return { file: request.owningFile, reason: 'requested', willCreate: !exists(request.owningFile) };
|
|
87
|
+
}
|
|
88
|
+
const source = model.elements[request.sourceId];
|
|
89
|
+
const target = model.elements[request.targetId];
|
|
90
|
+
// 2 — the active package's designated relationship file.
|
|
91
|
+
const designated = options.designatedFiles ?? {};
|
|
92
|
+
for (const pkg of [source?.package, target?.package]) {
|
|
93
|
+
const file = pkg ? designated[pkg] : undefined;
|
|
94
|
+
if (file && accept(file)) {
|
|
95
|
+
return { file, reason: 'designated-package-file', willCreate: !exists(file) };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// 3 — nearest writable common project package for both endpoints.
|
|
99
|
+
if (source?.file && target?.file) {
|
|
100
|
+
const commonDir = commonDirectory(source.file, target.file);
|
|
101
|
+
const existingRelFile = findRelationshipFileIn(commonDir, options);
|
|
102
|
+
if (existingRelFile && accept(existingRelFile)) {
|
|
103
|
+
return { file: existingRelFile, reason: 'common-package-file', willCreate: false };
|
|
104
|
+
}
|
|
105
|
+
// The source element's own file, when it sits in that common package.
|
|
106
|
+
if (withinDirectory(source.file, commonDir) && accept(source.file) && exists(source.file)) {
|
|
107
|
+
return { file: source.file, reason: 'source-element-file', willCreate: false };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// 4/5 — the canonical file, created only as a last resort.
|
|
111
|
+
const canonical = options.canonicalFile ?? CANONICAL_RELATIONSHIP_FILE;
|
|
112
|
+
return {
|
|
113
|
+
file: canonical,
|
|
114
|
+
reason: exists(canonical) ? 'canonical-file' : 'canonical-file-created',
|
|
115
|
+
willCreate: !exists(canonical),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/** Deepest directory containing both project-relative files. */
|
|
119
|
+
function commonDirectory(fileA, fileB) {
|
|
120
|
+
const a = dirname(fileA).split(/[\\/]/);
|
|
121
|
+
const b = dirname(fileB).split(/[\\/]/);
|
|
122
|
+
const common = [];
|
|
123
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
124
|
+
if (a[i] !== b[i])
|
|
125
|
+
break;
|
|
126
|
+
common.push(a[i]);
|
|
127
|
+
}
|
|
128
|
+
return common.join(sep);
|
|
129
|
+
}
|
|
130
|
+
/** True when a project-relative file sits in or under a directory. */
|
|
131
|
+
function withinDirectory(file, dir) {
|
|
132
|
+
if (!dir)
|
|
133
|
+
return true;
|
|
134
|
+
const normalized = dirname(file).split(/[\\/]/).join(sep);
|
|
135
|
+
return normalized === dir || normalized.startsWith(dir + sep);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* An existing relationships-named .sysml directly in a directory. Convention
|
|
139
|
+
* over configuration: a package that already collects its links in one file
|
|
140
|
+
* keeps collecting them there.
|
|
141
|
+
*/
|
|
142
|
+
function findRelationshipFileIn(dir, options) {
|
|
143
|
+
const absoluteDir = resolve(options.projectRoot, dir);
|
|
144
|
+
if (!existsSync(absoluteDir))
|
|
145
|
+
return undefined;
|
|
146
|
+
let entries;
|
|
147
|
+
try {
|
|
148
|
+
const pattern = options.relationshipFilePattern ?? DEFAULT_RELATIONSHIP_FILE_PATTERN;
|
|
149
|
+
entries = readdirSync(absoluteDir, { withFileTypes: true })
|
|
150
|
+
.filter(e => e.isFile() && pattern.test(e.name))
|
|
151
|
+
.map(e => e.name)
|
|
152
|
+
.sort();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
if (entries.length === 0)
|
|
158
|
+
return undefined;
|
|
159
|
+
return dir ? `${dir}${sep}${entries[0]}` : entries[0];
|
|
160
|
+
}
|
|
161
|
+
// ─── ID generation ──────────────────────────────────────────────────────────
|
|
162
|
+
/**
|
|
163
|
+
* A stable, explicit relationship ID. Named connection usages are what make a
|
|
164
|
+
* relationship addressable for inspection, deletion, and deep links, so every
|
|
165
|
+
* authored relationship gets one.
|
|
166
|
+
*/
|
|
167
|
+
export function generateRelationshipId(type, sourceId, targetId, taken) {
|
|
168
|
+
const sanitize = (value) => value.replace(/[^A-Za-z0-9_]/g, '_');
|
|
169
|
+
const base = `rel_${sanitize(type)}_${sanitize(sourceId)}_${sanitize(targetId)}`;
|
|
170
|
+
const used = new Set(taken);
|
|
171
|
+
if (!used.has(base))
|
|
172
|
+
return base;
|
|
173
|
+
let n = 2;
|
|
174
|
+
while (used.has(`${base}_${n}`))
|
|
175
|
+
n++;
|
|
176
|
+
return `${base}_${n}`;
|
|
177
|
+
}
|
|
178
|
+
/** Render the typed connection usage for a relationship. */
|
|
179
|
+
export function generateRelationshipDeclaration(id, definition, sourceId, targetId) {
|
|
180
|
+
return `connection ${id} : ${definition.sysmlName} connect ` +
|
|
181
|
+
`${definition.sourceEnd.name} ::> ${sourceId} to ` +
|
|
182
|
+
`${definition.targetEnd.name} ::> ${targetId};`;
|
|
183
|
+
}
|
|
184
|
+
// ─── Create ─────────────────────────────────────────────────────────────────
|
|
185
|
+
/**
|
|
186
|
+
* Write a relationship into project SysML.
|
|
187
|
+
*
|
|
188
|
+
* The declaration is inserted inside the target package by source offset, the
|
|
189
|
+
* whole updated file is reparsed, and the write is abandoned if the result does
|
|
190
|
+
* not parse or does not contain the new connection.
|
|
191
|
+
*/
|
|
192
|
+
export async function writeRelationship(request, definition, model, options) {
|
|
193
|
+
const placement = resolveRelationshipPlacement(request, model, options);
|
|
194
|
+
if (!isWritableRelationshipFile(placement.file, options)) {
|
|
195
|
+
return { success: false, error: `No writable project file can own this relationship (${placement.file})` };
|
|
196
|
+
}
|
|
197
|
+
const absolutePath = resolve(options.projectRoot, placement.file);
|
|
198
|
+
const relationshipId = generateRelationshipId(definition.name, request.sourceId, request.targetId, model.relationships.map(rel => rel.id));
|
|
199
|
+
const declaration = generateRelationshipDeclaration(relationshipId, definition, request.sourceId, request.targetId);
|
|
200
|
+
let updated;
|
|
201
|
+
if (!existsSync(absolutePath)) {
|
|
202
|
+
updated = newRelationshipFile(placement.file, declaration);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
const original = readFileSync(absolutePath, 'utf8');
|
|
206
|
+
const inserted = await insertIntoPackage(original, declaration);
|
|
207
|
+
if (!inserted.ok)
|
|
208
|
+
return { success: false, error: inserted.error };
|
|
209
|
+
updated = inserted.text;
|
|
210
|
+
}
|
|
211
|
+
// Parse-before-commit: a file that does not parse never reaches disk.
|
|
212
|
+
const { document, errors } = await parseText(updated);
|
|
213
|
+
if (errors.length > 0) {
|
|
214
|
+
return {
|
|
215
|
+
success: false,
|
|
216
|
+
error: `The updated source did not parse (${errors[0].message}); the file was left unchanged`,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const written = findConnectionUsage(document.parseResult.value, relationshipId);
|
|
220
|
+
if (!written) {
|
|
221
|
+
return {
|
|
222
|
+
success: false,
|
|
223
|
+
error: 'The relationship was not present after reparsing; the file was left unchanged',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
atomicWrite(absolutePath, updated);
|
|
228
|
+
}
|
|
229
|
+
catch (e) {
|
|
230
|
+
return { success: false, error: `Could not write ${placement.file}: ${String(e)}` };
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
success: true,
|
|
234
|
+
sourceFile: placement.file,
|
|
235
|
+
relationshipId,
|
|
236
|
+
declaration,
|
|
237
|
+
placementReason: placement.reason,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/** Body of a freshly created relationship file. */
|
|
241
|
+
function newRelationshipFile(relativePath, declaration) {
|
|
242
|
+
const packageName = relativePath
|
|
243
|
+
.replace(/\.sysml$/, '')
|
|
244
|
+
.replace(/[^A-Za-z0-9]+/g, '_')
|
|
245
|
+
.replace(/^_+|_+$/g, '') || 'relationships';
|
|
246
|
+
return `package ${packageName} {\n ${declaration}\n}\n`;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Insert a declaration as the last member of the file's final top-level
|
|
250
|
+
* package, matching the indentation of the members already there. Everything
|
|
251
|
+
* else in the file — comments, imports, unrelated declarations — is untouched
|
|
252
|
+
* because only this one offset is edited.
|
|
253
|
+
*/
|
|
254
|
+
async function insertIntoPackage(source, declaration) {
|
|
255
|
+
const { document, errors } = await parseText(source);
|
|
256
|
+
if (errors.length > 0) {
|
|
257
|
+
return { ok: false, error: `The target file does not parse (${errors[0].message})` };
|
|
258
|
+
}
|
|
259
|
+
const model = document.parseResult.value;
|
|
260
|
+
const packages = (model.members ?? []).filter(isPackageDeclaration);
|
|
261
|
+
if (packages.length === 0) {
|
|
262
|
+
return { ok: false, error: 'The target file declares no package to own the relationship' };
|
|
263
|
+
}
|
|
264
|
+
const target = packages[packages.length - 1];
|
|
265
|
+
const cst = target.$cstNode;
|
|
266
|
+
if (!cst)
|
|
267
|
+
return { ok: false, error: 'The target package has no source range' };
|
|
268
|
+
// The package's own closing brace is the last '}' in its source range.
|
|
269
|
+
const packageEnd = cst.offset + cst.length;
|
|
270
|
+
const closingBrace = source.lastIndexOf('}', packageEnd - 1);
|
|
271
|
+
if (closingBrace < 0)
|
|
272
|
+
return { ok: false, error: 'The target package is not brace-delimited' };
|
|
273
|
+
const indent = memberIndent(source, target, closingBrace);
|
|
274
|
+
// Keep the existing content up to the closing brace exactly as written, then
|
|
275
|
+
// add the declaration on its own line just before it.
|
|
276
|
+
const before = source.slice(0, closingBrace);
|
|
277
|
+
const after = source.slice(closingBrace);
|
|
278
|
+
const separator = before.endsWith('\n') ? '' : '\n';
|
|
279
|
+
return { ok: true, text: `${before}${separator}${indent}${declaration}\n${after}` };
|
|
280
|
+
}
|
|
281
|
+
/** Indentation used by the package's existing members, defaulting to 4 spaces. */
|
|
282
|
+
function memberIndent(source, pkg, closingBrace) {
|
|
283
|
+
const firstMember = (pkg.members ?? [])[0];
|
|
284
|
+
const offset = firstMember?.$cstNode?.offset;
|
|
285
|
+
if (typeof offset === 'number') {
|
|
286
|
+
const lineStart = source.lastIndexOf('\n', offset - 1) + 1;
|
|
287
|
+
const lead = source.slice(lineStart, offset);
|
|
288
|
+
if (/^[ \t]*$/.test(lead))
|
|
289
|
+
return lead;
|
|
290
|
+
}
|
|
291
|
+
// Fall back to one level in from the closing brace's own indentation.
|
|
292
|
+
const braceLineStart = source.lastIndexOf('\n', closingBrace - 1) + 1;
|
|
293
|
+
const braceIndent = source.slice(braceLineStart, closingBrace);
|
|
294
|
+
return /^[ \t]*$/.test(braceIndent) ? braceIndent + ' ' : ' ';
|
|
295
|
+
}
|
|
296
|
+
// ─── Delete ─────────────────────────────────────────────────────────────────
|
|
297
|
+
/**
|
|
298
|
+
* Remove exactly one connection usage from its owning file.
|
|
299
|
+
*
|
|
300
|
+
* Only the declaration's own source range is cut — together with the whitespace
|
|
301
|
+
* on its line — so neighbouring comments and declarations are preserved. Both
|
|
302
|
+
* endpoint elements are left completely untouched.
|
|
303
|
+
*/
|
|
304
|
+
export async function removeRelationship(relationship, options) {
|
|
305
|
+
if (!relationship.named) {
|
|
306
|
+
return {
|
|
307
|
+
success: false,
|
|
308
|
+
error: `Relationship "${relationship.id}" is an anonymous connection and cannot be addressed for deletion. ` +
|
|
309
|
+
'Give it a name in SysML first.',
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
if (!relationship.file || !isWritableRelationshipFile(relationship.file, options)) {
|
|
313
|
+
return { success: false, error: `${relationship.file || 'The source file'} is not a writable project file` };
|
|
314
|
+
}
|
|
315
|
+
const absolutePath = resolve(options.projectRoot, relationship.file);
|
|
316
|
+
if (!existsSync(absolutePath)) {
|
|
317
|
+
return { success: false, error: `${relationship.file} no longer exists` };
|
|
318
|
+
}
|
|
319
|
+
const source = readFileSync(absolutePath, 'utf8');
|
|
320
|
+
const { document, errors } = await parseText(source);
|
|
321
|
+
if (errors.length > 0) {
|
|
322
|
+
return { success: false, error: `${relationship.file} does not parse (${errors[0].message})` };
|
|
323
|
+
}
|
|
324
|
+
const usage = findConnectionUsage(document.parseResult.value, relationship.id);
|
|
325
|
+
const cst = usage?.$cstNode;
|
|
326
|
+
if (!usage || !cst) {
|
|
327
|
+
return { success: false, error: `Relationship "${relationship.id}" was not found in ${relationship.file}` };
|
|
328
|
+
}
|
|
329
|
+
// Widen the cut to the whole line when the declaration is alone on it, so
|
|
330
|
+
// deletion leaves no blank indented remnant.
|
|
331
|
+
let start = cst.offset;
|
|
332
|
+
let end = cst.offset + cst.length;
|
|
333
|
+
const lineStart = source.lastIndexOf('\n', start - 1) + 1;
|
|
334
|
+
if (/^[ \t]*$/.test(source.slice(lineStart, start)))
|
|
335
|
+
start = lineStart;
|
|
336
|
+
const lineEnd = source.indexOf('\n', end);
|
|
337
|
+
if (lineEnd >= 0 && /^[ \t]*$/.test(source.slice(end, lineEnd)))
|
|
338
|
+
end = lineEnd + 1;
|
|
339
|
+
const removedDeclaration = source.slice(cst.offset, cst.offset + cst.length);
|
|
340
|
+
const updated = source.slice(0, start) + source.slice(end);
|
|
341
|
+
// Parse-before-commit, exactly as on the create path.
|
|
342
|
+
const reparsed = await parseText(updated);
|
|
343
|
+
if (reparsed.errors.length > 0) {
|
|
344
|
+
return {
|
|
345
|
+
success: false,
|
|
346
|
+
error: `Removing the relationship left invalid source (${reparsed.errors[0].message}); ` +
|
|
347
|
+
'the file was left unchanged',
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
if (findConnectionUsage(reparsed.document.parseResult.value, relationship.id)) {
|
|
351
|
+
return { success: false, error: 'The relationship was still present after removal; the file was left unchanged' };
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
atomicWrite(absolutePath, updated);
|
|
355
|
+
}
|
|
356
|
+
catch (e) {
|
|
357
|
+
return { success: false, error: `Could not write ${relationship.file}: ${String(e)}` };
|
|
358
|
+
}
|
|
359
|
+
return { success: true, sourceFile: relationship.file, removedDeclaration };
|
|
360
|
+
}
|
|
361
|
+
// ─── Shared helpers ─────────────────────────────────────────────────────────
|
|
362
|
+
/** Depth-first search for a named connection usage anywhere in the document. */
|
|
363
|
+
function findConnectionUsage(model, name) {
|
|
364
|
+
const stack = [...(model.members ?? [])];
|
|
365
|
+
while (stack.length > 0) {
|
|
366
|
+
const node = stack.pop();
|
|
367
|
+
if (!node || typeof node !== 'object')
|
|
368
|
+
continue;
|
|
369
|
+
if (isConnectionUsage(node) && node.name === name)
|
|
370
|
+
return node;
|
|
371
|
+
if (Array.isArray(node.members))
|
|
372
|
+
stack.push(...node.members);
|
|
373
|
+
if (Array.isArray(node.body))
|
|
374
|
+
stack.push(...node.body);
|
|
375
|
+
}
|
|
376
|
+
return undefined;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Replace a file's contents atomically: write a sibling temp file, then rename
|
|
380
|
+
* over the target. A crash mid-write leaves the original intact rather than a
|
|
381
|
+
* half-written model file.
|
|
382
|
+
*/
|
|
383
|
+
function atomicWrite(absolutePath, contents) {
|
|
384
|
+
const dir = dirname(absolutePath);
|
|
385
|
+
if (!existsSync(dir))
|
|
386
|
+
mkdirSync(dir, { recursive: true });
|
|
387
|
+
const tempPath = `${absolutePath}.${process.pid}.tmp`;
|
|
388
|
+
try {
|
|
389
|
+
writeFileSync(tempPath, contents, 'utf8');
|
|
390
|
+
renameSync(tempPath, absolutePath);
|
|
391
|
+
}
|
|
392
|
+
catch (e) {
|
|
393
|
+
if (existsSync(tempPath)) {
|
|
394
|
+
try {
|
|
395
|
+
unlinkSync(tempPath);
|
|
396
|
+
}
|
|
397
|
+
catch { /* best effort cleanup */ }
|
|
398
|
+
}
|
|
399
|
+
throw e;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
//# sourceMappingURL=relationship-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relationship-writer.js","sourceRoot":"","sources":["../../src/server/relationship-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,19 @@ export declare const VIEW_LAYOUT_EXTENSION = ".viewlayout";
|
|
|
3
3
|
/** Companion location beside the SysML file that defines the view. */
|
|
4
4
|
export declare function viewLayoutPath(projectRoot: string, diagram: DiagramDTO): string;
|
|
5
5
|
export declare function loadViewLayout(projectRoot: string, diagram: DiagramDTO): DiagramLayout | null;
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Whether a layout says anything the model does not already say: a moved node,
|
|
8
|
+
* a routed connector, or a canvas setting the user changed. A companion exists
|
|
9
|
+
* to record overrides, so a layout that holds none is not worth a file — the
|
|
10
|
+
* view renders identically without it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function isDefaultViewLayout(layout: DiagramLayout): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Persist a diagram's overrides beside its SysML source. Returns the companion
|
|
15
|
+
* path, or null when there was nothing to persist — a layout that carries no
|
|
16
|
+
* override drops its entry instead, and the companion is removed once it holds
|
|
17
|
+
* no entries at all, so a purely visual toggle never dirties the project.
|
|
18
|
+
*/
|
|
19
|
+
export declare function saveViewLayout(projectRoot: string, diagram: DiagramDTO, layout: DiagramLayout): string | null;
|
|
7
20
|
export declare function loadViewLayouts(projectRoot: string, diagrams: DiagramDTO[]): Record<string, DiagramLayout>;
|
|
8
21
|
//# sourceMappingURL=view-layout-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-layout-store.d.ts","sourceRoot":"","sources":["../../src/server/view-layout-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEtE,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAUnD,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAO/E;AAMD,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI,CAgB7F;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"view-layout-store.d.ts","sourceRoot":"","sources":["../../src/server/view-layout-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEtE,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAUnD,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,MAAM,CAO/E;AAMD,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI,CAgB7F;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAalE;AAeD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CA+B7G;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAO1G"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { basename, dirname, resolve } from 'node:path';
|
|
3
3
|
import { parse, stringify } from 'yaml';
|
|
4
4
|
export const VIEW_LAYOUT_EXTENSION = '.viewlayout';
|
|
@@ -39,20 +39,72 @@ export function loadViewLayout(projectRoot, diagram) {
|
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Whether a layout says anything the model does not already say: a moved node,
|
|
44
|
+
* a routed connector, or a canvas setting the user changed. A companion exists
|
|
45
|
+
* to record overrides, so a layout that holds none is not worth a file — the
|
|
46
|
+
* view renders identically without it.
|
|
47
|
+
*/
|
|
48
|
+
export function isDefaultViewLayout(layout) {
|
|
49
|
+
if (Object.keys(layout.nodes ?? {}).length > 0)
|
|
50
|
+
return false;
|
|
51
|
+
if (Object.keys(layout.edges ?? {}).length > 0)
|
|
52
|
+
return false;
|
|
53
|
+
const canvas = layout.canvas;
|
|
54
|
+
if (!canvas)
|
|
55
|
+
return true;
|
|
56
|
+
// Automatic layout and still connectors are the defaults; every other
|
|
57
|
+
// canvas field is unset until the user sets it.
|
|
58
|
+
return canvas.autoLayout !== false
|
|
59
|
+
&& canvas.flowAnimation !== true
|
|
60
|
+
&& canvas.zoom === undefined
|
|
61
|
+
&& canvas.pan === undefined
|
|
62
|
+
&& canvas.grid === undefined
|
|
63
|
+
&& canvas.snap === undefined;
|
|
64
|
+
}
|
|
65
|
+
/** Existing companion entries, keyed by diagram id; empty for a new file. */
|
|
66
|
+
function readViewLayouts(path) {
|
|
67
|
+
if (!existsSync(path))
|
|
68
|
+
return {};
|
|
69
|
+
try {
|
|
70
|
+
const existing = parse(readFileSync(path, 'utf8'));
|
|
71
|
+
if (existing.format === 'memo.viewlayout/v1' || existing.format === 'memo.sysmlview/v2')
|
|
72
|
+
return existing.layouts ?? {};
|
|
73
|
+
if (existing.diagramId && existing.layout)
|
|
74
|
+
return { [existing.diagramId]: existing.layout };
|
|
75
|
+
}
|
|
76
|
+
catch { /* replace malformed companion */ }
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Persist a diagram's overrides beside its SysML source. Returns the companion
|
|
81
|
+
* path, or null when there was nothing to persist — a layout that carries no
|
|
82
|
+
* override drops its entry instead, and the companion is removed once it holds
|
|
83
|
+
* no entries at all, so a purely visual toggle never dirties the project.
|
|
84
|
+
*/
|
|
42
85
|
export function saveViewLayout(projectRoot, diagram, layout) {
|
|
43
86
|
const path = viewLayoutPath(projectRoot, diagram);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
existingLayouts = existing.layouts ?? {};
|
|
51
|
-
else if (existing.diagramId && existing.layout)
|
|
52
|
-
existingLayouts = { [existing.diagramId]: existing.layout };
|
|
87
|
+
const existingLayouts = readViewLayouts(path);
|
|
88
|
+
if (isDefaultViewLayout(layout)) {
|
|
89
|
+
if (!(diagram.id in existingLayouts)) {
|
|
90
|
+
if (existsSync(path) && Object.keys(existingLayouts).length === 0)
|
|
91
|
+
rmSync(path, { force: true });
|
|
92
|
+
return null;
|
|
53
93
|
}
|
|
54
|
-
|
|
94
|
+
const remaining = { ...existingLayouts };
|
|
95
|
+
delete remaining[diagram.id];
|
|
96
|
+
if (Object.keys(remaining).length === 0) {
|
|
97
|
+
rmSync(path, { force: true });
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
writeFileSync(path, stringify({
|
|
101
|
+
format: 'memo.viewlayout/v1',
|
|
102
|
+
...(diagram.sourceFile ? { viewSource: diagram.sourceFile } : {}),
|
|
103
|
+
layouts: remaining,
|
|
104
|
+
}), 'utf8');
|
|
105
|
+
return path;
|
|
55
106
|
}
|
|
107
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
56
108
|
const artifact = {
|
|
57
109
|
format: 'memo.viewlayout/v1',
|
|
58
110
|
...(diagram.sourceFile ? { viewSource: diagram.sourceFile } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-layout-store.js","sourceRoot":"","sources":["../../src/server/view-layout-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"view-layout-store.js","sourceRoot":"","sources":["../../src/server/view-layout-store.ts"],"names":[],"mappings":"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"}
|