@tdsoft-tech/aikit 0.1.20 → 0.1.30
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/LICENSE +63 -0
- package/README.md +348 -0
- package/dist/cli.js +246 -189
- package/dist/cli.js.map +1 -1
- package/dist/index.js +246 -189
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +246 -189
- package/dist/mcp-server.js.map +1 -1
- package/dist/tools/drawio-convert/convert-to-drawio.d.ts +300 -0
- package/dist/tools/drawio-convert/convert-to-drawio.js +264 -0
- package/dist/tools/drawio-convert/convert-to-drawio.js.map +1 -0
- package/dist/tools/drawio-convert/convert-to-mermaid.d.ts +249 -0
- package/dist/tools/drawio-convert/convert-to-mermaid.js +216 -0
- package/dist/tools/drawio-convert/convert-to-mermaid.js.map +1 -0
- package/dist/tools/drawio-convert/diagram-utils.d.ts +270 -0
- package/dist/tools/drawio-convert/diagram-utils.js +180 -0
- package/dist/tools/drawio-convert/diagram-utils.js.map +1 -0
- package/dist/tools/drawio-convert/open-diagram.d.ts +118 -0
- package/dist/tools/drawio-convert/open-diagram.js +88 -0
- package/dist/tools/drawio-convert/open-diagram.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Diagram Utilities
|
|
6
|
+
*
|
|
7
|
+
* Shared utilities for drawio-convert modules
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Resolve diagram path from user input
|
|
13
|
+
* @param {string} input - Diagram name or file path
|
|
14
|
+
* @param {'drawio' | 'mermaid'} type - Target file type
|
|
15
|
+
* @param {string} projectRoot - Project root directory
|
|
16
|
+
* @returns {string} Absolute path to diagram file
|
|
17
|
+
*/
|
|
18
|
+
function resolveDiagramPath(input, type, projectRoot) {
|
|
19
|
+
// 1. Absolute path - use as-is
|
|
20
|
+
if (path.isAbsolute(input)) {
|
|
21
|
+
return input;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 2. Relative path or contains directory separators
|
|
25
|
+
if (input.includes('/') || input.includes('\\')) {
|
|
26
|
+
return path.resolve(projectRoot, input);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 3. Just a name - use standard location
|
|
30
|
+
if (type === 'drawio') {
|
|
31
|
+
return path.join(projectRoot, '.aikit/assets/drawio', `${input}.drawio`);
|
|
32
|
+
} else {
|
|
33
|
+
return path.join(projectRoot, 'mermaid', `${input}.mmd`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Find paired diagram file (drawio ↔ mermaid)
|
|
39
|
+
* @param {string} filePath - Path to current file
|
|
40
|
+
* @param {string} projectRoot - Project root directory
|
|
41
|
+
* @returns {string|null} Path to paired file or null
|
|
42
|
+
*/
|
|
43
|
+
function findPairedDiagram(filePath, projectRoot) {
|
|
44
|
+
const ext = path.extname(filePath);
|
|
45
|
+
const basename = path.basename(filePath, ext);
|
|
46
|
+
|
|
47
|
+
if (ext === '.drawio') {
|
|
48
|
+
// Look for corresponding .mmd file
|
|
49
|
+
const possiblePaths = [
|
|
50
|
+
path.join(projectRoot, 'mermaid', `${basename}.mmd`),
|
|
51
|
+
path.join(path.dirname(filePath), `${basename}.mmd`),
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const p of possiblePaths) {
|
|
55
|
+
if (fs.existsSync(p)) {
|
|
56
|
+
return p;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else if (ext === '.mmd') {
|
|
60
|
+
// Look for corresponding .drawio file
|
|
61
|
+
const possiblePaths = [
|
|
62
|
+
path.join(projectRoot, '.aikit/assets/drawio', `${basename}.drawio`),
|
|
63
|
+
path.join(path.dirname(filePath), `${basename}.drawio`),
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
for (const p of possiblePaths) {
|
|
67
|
+
if (fs.existsSync(p)) {
|
|
68
|
+
return p;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Validate Mermaid syntax (basic validation)
|
|
78
|
+
* @param {string} code - Mermaid code
|
|
79
|
+
* @returns {Object} { valid, errors }
|
|
80
|
+
*/
|
|
81
|
+
function validateMermaidSyntax(code) {
|
|
82
|
+
const errors = [];
|
|
83
|
+
const lines = code.split('\n');
|
|
84
|
+
|
|
85
|
+
// Check for graph declaration
|
|
86
|
+
if (!lines[0]?.match(/graph\s+(TD|LR|TB|RL|BT)/i)) {
|
|
87
|
+
errors.push({
|
|
88
|
+
line: 1,
|
|
89
|
+
message: 'Missing or invalid graph declaration. Should start with "graph TD" or "graph LR"',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check for common syntax errors
|
|
94
|
+
lines.forEach((line, index) => {
|
|
95
|
+
const lineNum = index + 1;
|
|
96
|
+
const trimmed = line.trim();
|
|
97
|
+
|
|
98
|
+
// Skip comments and empty lines
|
|
99
|
+
if (!trimmed || trimmed.startsWith('%') || trimmed.startsWith('//') || trimmed.startsWith('style')) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Check for malformed edge labels (missing closing |)
|
|
104
|
+
if (trimmed.includes('|') && !trimmed.match(/\|[^|]*\|/)) {
|
|
105
|
+
const match = trimmed.match(/\|[^|]*/);
|
|
106
|
+
if (match) {
|
|
107
|
+
errors.push({
|
|
108
|
+
line: lineNum,
|
|
109
|
+
message: `Unclosed edge label. Use |text| syntax. Found: "${match[0]}"`,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Check for malformed edge syntax (--> with extra characters)
|
|
115
|
+
if (trimmed.match(/--[^>\s]/)) {
|
|
116
|
+
errors.push({
|
|
117
|
+
line: lineNum,
|
|
118
|
+
message: 'Invalid edge syntax. Use --> for edges, not -- > or other variations',
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
valid: errors.length === 0,
|
|
125
|
+
errors,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Validate Draw.io XML (basic validation)
|
|
131
|
+
* @param {string} xml - Draw.io XML content
|
|
132
|
+
* @returns {Object} { valid, errors }
|
|
133
|
+
*/
|
|
134
|
+
function validateDrawioXML(xml) {
|
|
135
|
+
const errors = [];
|
|
136
|
+
|
|
137
|
+
// Check for required XML tags
|
|
138
|
+
if (!xml.includes('<mxfile')) {
|
|
139
|
+
errors.push({
|
|
140
|
+
message: 'Missing <mxfile> tag. Not a valid Draw.io file',
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!xml.includes('<mxGraphModel')) {
|
|
145
|
+
errors.push({
|
|
146
|
+
message: 'Missing <mxGraphModel> tag. Not a valid Draw.io file',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!xml.includes('<root>')) {
|
|
151
|
+
errors.push({
|
|
152
|
+
message: 'Missing <root> tag. Not a valid Draw.io file',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Check for XML declaration
|
|
157
|
+
if (!xml.startsWith('<?xml')) {
|
|
158
|
+
errors.push({
|
|
159
|
+
message: 'Missing XML declaration. File should start with <?xml version="1.0"',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
valid: errors.length === 0,
|
|
165
|
+
errors,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get list of all diagrams in the project
|
|
171
|
+
* @param {string} projectRoot - Project root directory
|
|
172
|
+
* @returns {Array} List of diagram objects
|
|
173
|
+
*/
|
|
174
|
+
function getDiagramList(projectRoot) {
|
|
175
|
+
const diagrams = [];
|
|
176
|
+
const mermaidDir = path.join(projectRoot, 'mermaid');
|
|
177
|
+
const drawioDir = path.join(projectRoot, '.aikit/assets/drawio');
|
|
178
|
+
|
|
179
|
+
// Scan mermaid directory
|
|
180
|
+
if (fs.existsSync(mermaidDir)) {
|
|
181
|
+
const mmdFiles = fs.readdirSync(mermaidDir)
|
|
182
|
+
.filter(f => f.endsWith('.mmd'))
|
|
183
|
+
.map(f => {
|
|
184
|
+
const name = path.basename(f, '.mmd');
|
|
185
|
+
const mmdPath = path.join(mermaidDir, f);
|
|
186
|
+
const drawioPath = path.join(drawioDir, `${name}.drawio`);
|
|
187
|
+
|
|
188
|
+
return {
|
|
189
|
+
name,
|
|
190
|
+
mermaid: mmdPath,
|
|
191
|
+
drawio: fs.existsSync(drawioPath) ? drawioPath : null,
|
|
192
|
+
hasMermaid: true,
|
|
193
|
+
hasDrawio: fs.existsSync(drawioPath),
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
diagrams.push(...mmdFiles);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Scan drawio directory for files without mermaid counterpart
|
|
201
|
+
if (fs.existsSync(drawioDir)) {
|
|
202
|
+
const drawioFiles = fs.readdirSync(drawioDir)
|
|
203
|
+
.filter(f => f.endsWith('.drawio'))
|
|
204
|
+
.map(f => {
|
|
205
|
+
const name = path.basename(f, '.drawio');
|
|
206
|
+
const drawioPath = path.join(drawioDir, f);
|
|
207
|
+
const mmdPath = path.join(mermaidDir, `${name}.mmd`);
|
|
208
|
+
|
|
209
|
+
// Skip if already in list
|
|
210
|
+
if (diagrams.some(d => d.name === name)) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
name,
|
|
216
|
+
mermaid: fs.existsSync(mmdPath) ? mmdPath : null,
|
|
217
|
+
drawio: drawioPath,
|
|
218
|
+
hasMermaid: fs.existsSync(mmdPath),
|
|
219
|
+
hasDrawio: true,
|
|
220
|
+
};
|
|
221
|
+
})
|
|
222
|
+
.filter(d => d !== null);
|
|
223
|
+
|
|
224
|
+
diagrams.push(...drawioFiles);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return diagrams;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Format conversion stats for display
|
|
232
|
+
* @param {Object} stats - Conversion stats
|
|
233
|
+
* @returns {string} Formatted stats string
|
|
234
|
+
*/
|
|
235
|
+
function formatConversionStats(stats) {
|
|
236
|
+
const parts = [];
|
|
237
|
+
|
|
238
|
+
if (stats.nodes !== undefined) {
|
|
239
|
+
parts.push(`${stats.nodes} node${stats.nodes !== 1 ? 's' : ''}`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (stats.edges !== undefined) {
|
|
243
|
+
parts.push(`${stats.edges} edge${stats.edges !== 1 ? 's' : ''}`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (stats.direction) {
|
|
247
|
+
parts.push(`direction: ${stats.direction}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return parts.join(', ');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Ensure required directories exist
|
|
255
|
+
* @param {string} projectRoot - Project root directory
|
|
256
|
+
*/
|
|
257
|
+
function ensureDiagramDirectories(projectRoot) {
|
|
258
|
+
const dirs = [
|
|
259
|
+
path.join(projectRoot, 'mermaid'),
|
|
260
|
+
path.join(projectRoot, '.aikit/assets/drawio'),
|
|
261
|
+
];
|
|
262
|
+
|
|
263
|
+
dirs.forEach(dir => {
|
|
264
|
+
if (!fs.existsSync(dir)) {
|
|
265
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export { ensureDiagramDirectories, findPairedDiagram, formatConversionStats, getDiagramList, resolveDiagramPath, validateDrawioXML, validateMermaidSyntax };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/tools/drawio-convert/diagram-utils.js
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
function resolveDiagramPath(input, type, projectRoot) {
|
|
7
|
+
if (path.isAbsolute(input)) {
|
|
8
|
+
return input;
|
|
9
|
+
}
|
|
10
|
+
if (input.includes("/") || input.includes("\\")) {
|
|
11
|
+
return path.resolve(projectRoot, input);
|
|
12
|
+
}
|
|
13
|
+
if (type === "drawio") {
|
|
14
|
+
return path.join(projectRoot, ".aikit/assets/drawio", `${input}.drawio`);
|
|
15
|
+
} else {
|
|
16
|
+
return path.join(projectRoot, "mermaid", `${input}.mmd`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function findPairedDiagram(filePath, projectRoot) {
|
|
20
|
+
const ext = path.extname(filePath);
|
|
21
|
+
const basename = path.basename(filePath, ext);
|
|
22
|
+
if (ext === ".drawio") {
|
|
23
|
+
const possiblePaths = [
|
|
24
|
+
path.join(projectRoot, "mermaid", `${basename}.mmd`),
|
|
25
|
+
path.join(path.dirname(filePath), `${basename}.mmd`)
|
|
26
|
+
];
|
|
27
|
+
for (const p of possiblePaths) {
|
|
28
|
+
if (fs.existsSync(p)) {
|
|
29
|
+
return p;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
} else if (ext === ".mmd") {
|
|
33
|
+
const possiblePaths = [
|
|
34
|
+
path.join(projectRoot, ".aikit/assets/drawio", `${basename}.drawio`),
|
|
35
|
+
path.join(path.dirname(filePath), `${basename}.drawio`)
|
|
36
|
+
];
|
|
37
|
+
for (const p of possiblePaths) {
|
|
38
|
+
if (fs.existsSync(p)) {
|
|
39
|
+
return p;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function validateMermaidSyntax(code) {
|
|
46
|
+
const errors = [];
|
|
47
|
+
const lines = code.split("\n");
|
|
48
|
+
if (!lines[0]?.match(/graph\s+(TD|LR|TB|RL|BT)/i)) {
|
|
49
|
+
errors.push({
|
|
50
|
+
line: 1,
|
|
51
|
+
message: 'Missing or invalid graph declaration. Should start with "graph TD" or "graph LR"'
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
lines.forEach((line, index) => {
|
|
55
|
+
const lineNum = index + 1;
|
|
56
|
+
const trimmed = line.trim();
|
|
57
|
+
if (!trimmed || trimmed.startsWith("%") || trimmed.startsWith("//") || trimmed.startsWith("style")) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (trimmed.includes("|") && !trimmed.match(/\|[^|]*\|/)) {
|
|
61
|
+
const match = trimmed.match(/\|[^|]*/);
|
|
62
|
+
if (match) {
|
|
63
|
+
errors.push({
|
|
64
|
+
line: lineNum,
|
|
65
|
+
message: `Unclosed edge label. Use |text| syntax. Found: "${match[0]}"`
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (trimmed.match(/--[^>\s]/)) {
|
|
70
|
+
errors.push({
|
|
71
|
+
line: lineNum,
|
|
72
|
+
message: "Invalid edge syntax. Use --> for edges, not -- > or other variations"
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
valid: errors.length === 0,
|
|
78
|
+
errors
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function validateDrawioXML(xml) {
|
|
82
|
+
const errors = [];
|
|
83
|
+
if (!xml.includes("<mxfile")) {
|
|
84
|
+
errors.push({
|
|
85
|
+
message: "Missing <mxfile> tag. Not a valid Draw.io file"
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (!xml.includes("<mxGraphModel")) {
|
|
89
|
+
errors.push({
|
|
90
|
+
message: "Missing <mxGraphModel> tag. Not a valid Draw.io file"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (!xml.includes("<root>")) {
|
|
94
|
+
errors.push({
|
|
95
|
+
message: "Missing <root> tag. Not a valid Draw.io file"
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (!xml.startsWith("<?xml")) {
|
|
99
|
+
errors.push({
|
|
100
|
+
message: 'Missing XML declaration. File should start with <?xml version="1.0"'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
valid: errors.length === 0,
|
|
105
|
+
errors
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function getDiagramList(projectRoot) {
|
|
109
|
+
const diagrams = [];
|
|
110
|
+
const mermaidDir = path.join(projectRoot, "mermaid");
|
|
111
|
+
const drawioDir = path.join(projectRoot, ".aikit/assets/drawio");
|
|
112
|
+
if (fs.existsSync(mermaidDir)) {
|
|
113
|
+
const mmdFiles = fs.readdirSync(mermaidDir).filter((f) => f.endsWith(".mmd")).map((f) => {
|
|
114
|
+
const name = path.basename(f, ".mmd");
|
|
115
|
+
const mmdPath = path.join(mermaidDir, f);
|
|
116
|
+
const drawioPath = path.join(drawioDir, `${name}.drawio`);
|
|
117
|
+
return {
|
|
118
|
+
name,
|
|
119
|
+
mermaid: mmdPath,
|
|
120
|
+
drawio: fs.existsSync(drawioPath) ? drawioPath : null,
|
|
121
|
+
hasMermaid: true,
|
|
122
|
+
hasDrawio: fs.existsSync(drawioPath)
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
diagrams.push(...mmdFiles);
|
|
126
|
+
}
|
|
127
|
+
if (fs.existsSync(drawioDir)) {
|
|
128
|
+
const drawioFiles = fs.readdirSync(drawioDir).filter((f) => f.endsWith(".drawio")).map((f) => {
|
|
129
|
+
const name = path.basename(f, ".drawio");
|
|
130
|
+
const drawioPath = path.join(drawioDir, f);
|
|
131
|
+
const mmdPath = path.join(mermaidDir, `${name}.mmd`);
|
|
132
|
+
if (diagrams.some((d) => d.name === name)) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
name,
|
|
137
|
+
mermaid: fs.existsSync(mmdPath) ? mmdPath : null,
|
|
138
|
+
drawio: drawioPath,
|
|
139
|
+
hasMermaid: fs.existsSync(mmdPath),
|
|
140
|
+
hasDrawio: true
|
|
141
|
+
};
|
|
142
|
+
}).filter((d) => d !== null);
|
|
143
|
+
diagrams.push(...drawioFiles);
|
|
144
|
+
}
|
|
145
|
+
return diagrams;
|
|
146
|
+
}
|
|
147
|
+
function formatConversionStats(stats) {
|
|
148
|
+
const parts = [];
|
|
149
|
+
if (stats.nodes !== void 0) {
|
|
150
|
+
parts.push(`${stats.nodes} node${stats.nodes !== 1 ? "s" : ""}`);
|
|
151
|
+
}
|
|
152
|
+
if (stats.edges !== void 0) {
|
|
153
|
+
parts.push(`${stats.edges} edge${stats.edges !== 1 ? "s" : ""}`);
|
|
154
|
+
}
|
|
155
|
+
if (stats.direction) {
|
|
156
|
+
parts.push(`direction: ${stats.direction}`);
|
|
157
|
+
}
|
|
158
|
+
return parts.join(", ");
|
|
159
|
+
}
|
|
160
|
+
function ensureDiagramDirectories(projectRoot) {
|
|
161
|
+
const dirs = [
|
|
162
|
+
path.join(projectRoot, "mermaid"),
|
|
163
|
+
path.join(projectRoot, ".aikit/assets/drawio")
|
|
164
|
+
];
|
|
165
|
+
dirs.forEach((dir) => {
|
|
166
|
+
if (!fs.existsSync(dir)) {
|
|
167
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
export {
|
|
172
|
+
ensureDiagramDirectories,
|
|
173
|
+
findPairedDiagram,
|
|
174
|
+
formatConversionStats,
|
|
175
|
+
getDiagramList,
|
|
176
|
+
resolveDiagramPath,
|
|
177
|
+
validateDrawioXML,
|
|
178
|
+
validateMermaidSyntax
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=diagram-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/tools/drawio-convert/diagram-utils.js"],"sourcesContent":["/**\n * Diagram Utilities\n *\n * Shared utilities for drawio-convert modules\n */\n\nimport fs from 'fs';\nimport path from 'path';\n\n/**\n * Resolve diagram path from user input\n * @param {string} input - Diagram name or file path\n * @param {'drawio' | 'mermaid'} type - Target file type\n * @param {string} projectRoot - Project root directory\n * @returns {string} Absolute path to diagram file\n */\nexport function resolveDiagramPath(input, type, projectRoot) {\n // 1. Absolute path - use as-is\n if (path.isAbsolute(input)) {\n return input;\n }\n\n // 2. Relative path or contains directory separators\n if (input.includes('/') || input.includes('\\\\')) {\n return path.resolve(projectRoot, input);\n }\n\n // 3. Just a name - use standard location\n if (type === 'drawio') {\n return path.join(projectRoot, '.aikit/assets/drawio', `${input}.drawio`);\n } else {\n return path.join(projectRoot, 'mermaid', `${input}.mmd`);\n }\n}\n\n/**\n * Find paired diagram file (drawio ↔ mermaid)\n * @param {string} filePath - Path to current file\n * @param {string} projectRoot - Project root directory\n * @returns {string|null} Path to paired file or null\n */\nexport function findPairedDiagram(filePath, projectRoot) {\n const ext = path.extname(filePath);\n const basename = path.basename(filePath, ext);\n\n if (ext === '.drawio') {\n // Look for corresponding .mmd file\n const possiblePaths = [\n path.join(projectRoot, 'mermaid', `${basename}.mmd`),\n path.join(path.dirname(filePath), `${basename}.mmd`),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p)) {\n return p;\n }\n }\n } else if (ext === '.mmd') {\n // Look for corresponding .drawio file\n const possiblePaths = [\n path.join(projectRoot, '.aikit/assets/drawio', `${basename}.drawio`),\n path.join(path.dirname(filePath), `${basename}.drawio`),\n ];\n\n for (const p of possiblePaths) {\n if (fs.existsSync(p)) {\n return p;\n }\n }\n }\n\n return null;\n}\n\n/**\n * Validate Mermaid syntax (basic validation)\n * @param {string} code - Mermaid code\n * @returns {Object} { valid, errors }\n */\nexport function validateMermaidSyntax(code) {\n const errors = [];\n const lines = code.split('\\n');\n\n // Check for graph declaration\n if (!lines[0]?.match(/graph\\s+(TD|LR|TB|RL|BT)/i)) {\n errors.push({\n line: 1,\n message: 'Missing or invalid graph declaration. Should start with \"graph TD\" or \"graph LR\"',\n });\n }\n\n // Check for common syntax errors\n lines.forEach((line, index) => {\n const lineNum = index + 1;\n const trimmed = line.trim();\n\n // Skip comments and empty lines\n if (!trimmed || trimmed.startsWith('%') || trimmed.startsWith('//') || trimmed.startsWith('style')) {\n return;\n }\n\n // Check for malformed edge labels (missing closing |)\n if (trimmed.includes('|') && !trimmed.match(/\\|[^|]*\\|/)) {\n const match = trimmed.match(/\\|[^|]*/);\n if (match) {\n errors.push({\n line: lineNum,\n message: `Unclosed edge label. Use |text| syntax. Found: \"${match[0]}\"`,\n });\n }\n }\n\n // Check for malformed edge syntax (--> with extra characters)\n if (trimmed.match(/--[^>\\s]/)) {\n errors.push({\n line: lineNum,\n message: 'Invalid edge syntax. Use --> for edges, not -- > or other variations',\n });\n }\n });\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Validate Draw.io XML (basic validation)\n * @param {string} xml - Draw.io XML content\n * @returns {Object} { valid, errors }\n */\nexport function validateDrawioXML(xml) {\n const errors = [];\n\n // Check for required XML tags\n if (!xml.includes('<mxfile')) {\n errors.push({\n message: 'Missing <mxfile> tag. Not a valid Draw.io file',\n });\n }\n\n if (!xml.includes('<mxGraphModel')) {\n errors.push({\n message: 'Missing <mxGraphModel> tag. Not a valid Draw.io file',\n });\n }\n\n if (!xml.includes('<root>')) {\n errors.push({\n message: 'Missing <root> tag. Not a valid Draw.io file',\n });\n }\n\n // Check for XML declaration\n if (!xml.startsWith('<?xml')) {\n errors.push({\n message: 'Missing XML declaration. File should start with <?xml version=\"1.0\"',\n });\n }\n\n return {\n valid: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Get list of all diagrams in the project\n * @param {string} projectRoot - Project root directory\n * @returns {Array} List of diagram objects\n */\nexport function getDiagramList(projectRoot) {\n const diagrams = [];\n const mermaidDir = path.join(projectRoot, 'mermaid');\n const drawioDir = path.join(projectRoot, '.aikit/assets/drawio');\n\n // Scan mermaid directory\n if (fs.existsSync(mermaidDir)) {\n const mmdFiles = fs.readdirSync(mermaidDir)\n .filter(f => f.endsWith('.mmd'))\n .map(f => {\n const name = path.basename(f, '.mmd');\n const mmdPath = path.join(mermaidDir, f);\n const drawioPath = path.join(drawioDir, `${name}.drawio`);\n\n return {\n name,\n mermaid: mmdPath,\n drawio: fs.existsSync(drawioPath) ? drawioPath : null,\n hasMermaid: true,\n hasDrawio: fs.existsSync(drawioPath),\n };\n });\n\n diagrams.push(...mmdFiles);\n }\n\n // Scan drawio directory for files without mermaid counterpart\n if (fs.existsSync(drawioDir)) {\n const drawioFiles = fs.readdirSync(drawioDir)\n .filter(f => f.endsWith('.drawio'))\n .map(f => {\n const name = path.basename(f, '.drawio');\n const drawioPath = path.join(drawioDir, f);\n const mmdPath = path.join(mermaidDir, `${name}.mmd`);\n\n // Skip if already in list\n if (diagrams.some(d => d.name === name)) {\n return null;\n }\n\n return {\n name,\n mermaid: fs.existsSync(mmdPath) ? mmdPath : null,\n drawio: drawioPath,\n hasMermaid: fs.existsSync(mmdPath),\n hasDrawio: true,\n };\n })\n .filter(d => d !== null);\n\n diagrams.push(...drawioFiles);\n }\n\n return diagrams;\n}\n\n/**\n * Format conversion stats for display\n * @param {Object} stats - Conversion stats\n * @returns {string} Formatted stats string\n */\nexport function formatConversionStats(stats) {\n const parts = [];\n\n if (stats.nodes !== undefined) {\n parts.push(`${stats.nodes} node${stats.nodes !== 1 ? 's' : ''}`);\n }\n\n if (stats.edges !== undefined) {\n parts.push(`${stats.edges} edge${stats.edges !== 1 ? 's' : ''}`);\n }\n\n if (stats.direction) {\n parts.push(`direction: ${stats.direction}`);\n }\n\n return parts.join(', ');\n}\n\n/**\n * Ensure required directories exist\n * @param {string} projectRoot - Project root directory\n */\nexport function ensureDiagramDirectories(projectRoot) {\n const dirs = [\n path.join(projectRoot, 'mermaid'),\n path.join(projectRoot, '.aikit/assets/drawio'),\n ];\n\n dirs.forEach(dir => {\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n });\n}\n"],"mappings":";;;AAMA,OAAO,QAAQ;AACf,OAAO,UAAU;AASV,SAAS,mBAAmB,OAAO,MAAM,aAAa;AAE3D,MAAI,KAAK,WAAW,KAAK,GAAG;AAC1B,WAAO;AAAA,EACT;AAGA,MAAI,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,IAAI,GAAG;AAC/C,WAAO,KAAK,QAAQ,aAAa,KAAK;AAAA,EACxC;AAGA,MAAI,SAAS,UAAU;AACrB,WAAO,KAAK,KAAK,aAAa,wBAAwB,GAAG,KAAK,SAAS;AAAA,EACzE,OAAO;AACL,WAAO,KAAK,KAAK,aAAa,WAAW,GAAG,KAAK,MAAM;AAAA,EACzD;AACF;AAQO,SAAS,kBAAkB,UAAU,aAAa;AACvD,QAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,QAAM,WAAW,KAAK,SAAS,UAAU,GAAG;AAE5C,MAAI,QAAQ,WAAW;AAErB,UAAM,gBAAgB;AAAA,MACpB,KAAK,KAAK,aAAa,WAAW,GAAG,QAAQ,MAAM;AAAA,MACnD,KAAK,KAAK,KAAK,QAAQ,QAAQ,GAAG,GAAG,QAAQ,MAAM;AAAA,IACrD;AAEA,eAAW,KAAK,eAAe;AAC7B,UAAI,GAAG,WAAW,CAAC,GAAG;AACpB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF,WAAW,QAAQ,QAAQ;AAEzB,UAAM,gBAAgB;AAAA,MACpB,KAAK,KAAK,aAAa,wBAAwB,GAAG,QAAQ,SAAS;AAAA,MACnE,KAAK,KAAK,KAAK,QAAQ,QAAQ,GAAG,GAAG,QAAQ,SAAS;AAAA,IACxD;AAEA,eAAW,KAAK,eAAe;AAC7B,UAAI,GAAG,WAAW,CAAC,GAAG;AACpB,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,sBAAsB,MAAM;AAC1C,QAAM,SAAS,CAAC;AAChB,QAAM,QAAQ,KAAK,MAAM,IAAI;AAG7B,MAAI,CAAC,MAAM,CAAC,GAAG,MAAM,2BAA2B,GAAG;AACjD,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,QAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,UAAM,UAAU,QAAQ;AACxB,UAAM,UAAU,KAAK,KAAK;AAG1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,IAAI,KAAK,QAAQ,WAAW,OAAO,GAAG;AAClG;AAAA,IACF;AAGA,QAAI,QAAQ,SAAS,GAAG,KAAK,CAAC,QAAQ,MAAM,WAAW,GAAG;AACxD,YAAM,QAAQ,QAAQ,MAAM,SAAS;AACrC,UAAI,OAAO;AACT,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,mDAAmD,MAAM,CAAC,CAAC;AAAA,QACtE,CAAC;AAAA,MACH;AAAA,IACF;AAGA,QAAI,QAAQ,MAAM,UAAU,GAAG;AAC7B,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACF;AACF;AAOO,SAAS,kBAAkB,KAAK;AACrC,QAAM,SAAS,CAAC;AAGhB,MAAI,CAAC,IAAI,SAAS,SAAS,GAAG;AAC5B,WAAO,KAAK;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,IAAI,SAAS,eAAe,GAAG;AAClC,WAAO,KAAK;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,IAAI,SAAS,QAAQ,GAAG;AAC3B,WAAO,KAAK;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAGA,MAAI,CAAC,IAAI,WAAW,OAAO,GAAG;AAC5B,WAAO,KAAK;AAAA,MACV,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,EACF;AACF;AAOO,SAAS,eAAe,aAAa;AAC1C,QAAM,WAAW,CAAC;AAClB,QAAM,aAAa,KAAK,KAAK,aAAa,SAAS;AACnD,QAAM,YAAY,KAAK,KAAK,aAAa,sBAAsB;AAG/D,MAAI,GAAG,WAAW,UAAU,GAAG;AAC7B,UAAM,WAAW,GAAG,YAAY,UAAU,EACvC,OAAO,OAAK,EAAE,SAAS,MAAM,CAAC,EAC9B,IAAI,OAAK;AACR,YAAM,OAAO,KAAK,SAAS,GAAG,MAAM;AACpC,YAAM,UAAU,KAAK,KAAK,YAAY,CAAC;AACvC,YAAM,aAAa,KAAK,KAAK,WAAW,GAAG,IAAI,SAAS;AAExD,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT,QAAQ,GAAG,WAAW,UAAU,IAAI,aAAa;AAAA,QACjD,YAAY;AAAA,QACZ,WAAW,GAAG,WAAW,UAAU;AAAA,MACrC;AAAA,IACF,CAAC;AAEH,aAAS,KAAK,GAAG,QAAQ;AAAA,EAC3B;AAGA,MAAI,GAAG,WAAW,SAAS,GAAG;AAC5B,UAAM,cAAc,GAAG,YAAY,SAAS,EACzC,OAAO,OAAK,EAAE,SAAS,SAAS,CAAC,EACjC,IAAI,OAAK;AACR,YAAM,OAAO,KAAK,SAAS,GAAG,SAAS;AACvC,YAAM,aAAa,KAAK,KAAK,WAAW,CAAC;AACzC,YAAM,UAAU,KAAK,KAAK,YAAY,GAAG,IAAI,MAAM;AAGnD,UAAI,SAAS,KAAK,OAAK,EAAE,SAAS,IAAI,GAAG;AACvC,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,QACL;AAAA,QACA,SAAS,GAAG,WAAW,OAAO,IAAI,UAAU;AAAA,QAC5C,QAAQ;AAAA,QACR,YAAY,GAAG,WAAW,OAAO;AAAA,QACjC,WAAW;AAAA,MACb;AAAA,IACF,CAAC,EACA,OAAO,OAAK,MAAM,IAAI;AAEzB,aAAS,KAAK,GAAG,WAAW;AAAA,EAC9B;AAEA,SAAO;AACT;AAOO,SAAS,sBAAsB,OAAO;AAC3C,QAAM,QAAQ,CAAC;AAEf,MAAI,MAAM,UAAU,QAAW;AAC7B,UAAM,KAAK,GAAG,MAAM,KAAK,QAAQ,MAAM,UAAU,IAAI,MAAM,EAAE,EAAE;AAAA,EACjE;AAEA,MAAI,MAAM,UAAU,QAAW;AAC7B,UAAM,KAAK,GAAG,MAAM,KAAK,QAAQ,MAAM,UAAU,IAAI,MAAM,EAAE,EAAE;AAAA,EACjE;AAEA,MAAI,MAAM,WAAW;AACnB,UAAM,KAAK,cAAc,MAAM,SAAS,EAAE;AAAA,EAC5C;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAMO,SAAS,yBAAyB,aAAa;AACpD,QAAM,OAAO;AAAA,IACX,KAAK,KAAK,aAAa,SAAS;AAAA,IAChC,KAAK,KAAK,aAAa,sBAAsB;AAAA,EAC/C;AAEA,OAAK,QAAQ,SAAO;AAClB,QAAI,CAAC,GAAG,WAAW,GAAG,GAAG;AACvB,SAAG,UAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAAA,IACvC;AAAA,EACF,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Open Diagram in Draw.io Application
|
|
6
|
+
*
|
|
7
|
+
* Cross-platform utility to open diagrams in Draw.io desktop app or web app
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Open diagram in Draw.io application
|
|
13
|
+
* @param {string} drawioPath - Absolute path to .drawio file
|
|
14
|
+
* @returns {Object} { success, message, openedWith }
|
|
15
|
+
*/
|
|
16
|
+
function openDiagram(drawioPath) {
|
|
17
|
+
// 1. Validate file exists
|
|
18
|
+
if (!fs.existsSync(drawioPath)) {
|
|
19
|
+
return {
|
|
20
|
+
success: false,
|
|
21
|
+
message: `File not found: ${drawioPath}`,
|
|
22
|
+
openedWith: null,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const platform = process.platform;
|
|
27
|
+
let command;
|
|
28
|
+
|
|
29
|
+
// 2. Build platform-specific command
|
|
30
|
+
try {
|
|
31
|
+
if (platform === 'darwin') {
|
|
32
|
+
// macOS
|
|
33
|
+
command = `open -a "Draw.io" "${drawioPath}"`;
|
|
34
|
+
} else if (platform === 'linux') {
|
|
35
|
+
// Linux - try Draw.io desktop first, fallback to xdg-open
|
|
36
|
+
try {
|
|
37
|
+
// Check if Draw.io is installed
|
|
38
|
+
execSync('which drawio', { stdio: 'ignore' });
|
|
39
|
+
command = `drawio "${drawioPath}"`;
|
|
40
|
+
} catch {
|
|
41
|
+
// Draw.io not found, use xdg-open
|
|
42
|
+
command = `xdg-open "${drawioPath}"`;
|
|
43
|
+
}
|
|
44
|
+
} else if (platform === 'win32') {
|
|
45
|
+
// Windows
|
|
46
|
+
command = `start "" "${drawioPath}"`;
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 3. Try to open desktop app
|
|
52
|
+
execSync(command, { stdio: 'ignore' });
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
success: true,
|
|
56
|
+
message: `Opened in Draw.io desktop app`,
|
|
57
|
+
openedWith: 'desktop',
|
|
58
|
+
};
|
|
59
|
+
} catch (err) {
|
|
60
|
+
// Desktop app failed, fallback to web app
|
|
61
|
+
try {
|
|
62
|
+
const webUrl = `https://app.diagrams.net/?splash=0&local=1#${encodeURIComponent(drawioPath)}`;
|
|
63
|
+
|
|
64
|
+
if (platform === 'darwin') {
|
|
65
|
+
execSync(`open "${webUrl}"`, { stdio: 'ignore' });
|
|
66
|
+
} else if (platform === 'linux') {
|
|
67
|
+
execSync(`xdg-open "${webUrl}"`, { stdio: 'ignore' });
|
|
68
|
+
} else if (platform === 'win32') {
|
|
69
|
+
execSync(`start "" "${webUrl}"`, { stdio: 'ignore', shell: true });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
success: true,
|
|
74
|
+
message: `Opened in Draw.io web app (desktop app not found)`,
|
|
75
|
+
openedWith: 'web',
|
|
76
|
+
};
|
|
77
|
+
} catch (webErr) {
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
message: `Failed to open Draw.io: ${webErr.message}`,
|
|
81
|
+
openedWith: null,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Check if Draw.io desktop app is installed
|
|
89
|
+
* @returns {boolean} True if installed
|
|
90
|
+
*/
|
|
91
|
+
function isDrawioInstalled() {
|
|
92
|
+
const platform = process.platform;
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
if (platform === 'darwin') {
|
|
96
|
+
// Check macOS Applications folder
|
|
97
|
+
execSync('ls /Applications/Draw.io.app 2>/dev/null', { stdio: 'ignore' });
|
|
98
|
+
return true;
|
|
99
|
+
} else if (platform === 'linux') {
|
|
100
|
+
// Check Linux
|
|
101
|
+
execSync('which drawio', { stdio: 'ignore' });
|
|
102
|
+
return true;
|
|
103
|
+
} else if (platform === 'win32') {
|
|
104
|
+
// Check Windows (check common install locations)
|
|
105
|
+
const paths = [
|
|
106
|
+
'C:\\Program Files\\Draw.io\\drawio.exe',
|
|
107
|
+
'C:\\Program Files (x86)\\Draw.io\\drawio.exe',
|
|
108
|
+
process.env.LOCALAPPDATA + '\\Programs\\Draw.io\\drawio.exe',
|
|
109
|
+
];
|
|
110
|
+
return paths.some(p => fs.existsSync(p));
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
} catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { isDrawioInstalled, openDiagram };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/tools/drawio-convert/open-diagram.js
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
function openDiagram(drawioPath) {
|
|
7
|
+
if (!fs.existsSync(drawioPath)) {
|
|
8
|
+
return {
|
|
9
|
+
success: false,
|
|
10
|
+
message: `File not found: ${drawioPath}`,
|
|
11
|
+
openedWith: null
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const platform = process.platform;
|
|
15
|
+
let command;
|
|
16
|
+
let openedWith = "desktop";
|
|
17
|
+
try {
|
|
18
|
+
if (platform === "darwin") {
|
|
19
|
+
command = `open -a "Draw.io" "${drawioPath}"`;
|
|
20
|
+
} else if (platform === "linux") {
|
|
21
|
+
try {
|
|
22
|
+
execSync("which drawio", { stdio: "ignore" });
|
|
23
|
+
command = `drawio "${drawioPath}"`;
|
|
24
|
+
} catch {
|
|
25
|
+
command = `xdg-open "${drawioPath}"`;
|
|
26
|
+
}
|
|
27
|
+
} else if (platform === "win32") {
|
|
28
|
+
command = `start "" "${drawioPath}"`;
|
|
29
|
+
} else {
|
|
30
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
31
|
+
}
|
|
32
|
+
execSync(command, { stdio: "ignore" });
|
|
33
|
+
return {
|
|
34
|
+
success: true,
|
|
35
|
+
message: `Opened in Draw.io desktop app`,
|
|
36
|
+
openedWith: "desktop"
|
|
37
|
+
};
|
|
38
|
+
} catch (err) {
|
|
39
|
+
try {
|
|
40
|
+
const webUrl = `https://app.diagrams.net/?splash=0&local=1#${encodeURIComponent(drawioPath)}`;
|
|
41
|
+
if (platform === "darwin") {
|
|
42
|
+
execSync(`open "${webUrl}"`, { stdio: "ignore" });
|
|
43
|
+
} else if (platform === "linux") {
|
|
44
|
+
execSync(`xdg-open "${webUrl}"`, { stdio: "ignore" });
|
|
45
|
+
} else if (platform === "win32") {
|
|
46
|
+
execSync(`start "" "${webUrl}"`, { stdio: "ignore", shell: true });
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
success: true,
|
|
50
|
+
message: `Opened in Draw.io web app (desktop app not found)`,
|
|
51
|
+
openedWith: "web"
|
|
52
|
+
};
|
|
53
|
+
} catch (webErr) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
message: `Failed to open Draw.io: ${webErr.message}`,
|
|
57
|
+
openedWith: null
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function isDrawioInstalled() {
|
|
63
|
+
const platform = process.platform;
|
|
64
|
+
try {
|
|
65
|
+
if (platform === "darwin") {
|
|
66
|
+
execSync("ls /Applications/Draw.io.app 2>/dev/null", { stdio: "ignore" });
|
|
67
|
+
return true;
|
|
68
|
+
} else if (platform === "linux") {
|
|
69
|
+
execSync("which drawio", { stdio: "ignore" });
|
|
70
|
+
return true;
|
|
71
|
+
} else if (platform === "win32") {
|
|
72
|
+
const paths = [
|
|
73
|
+
"C:\\Program Files\\Draw.io\\drawio.exe",
|
|
74
|
+
"C:\\Program Files (x86)\\Draw.io\\drawio.exe",
|
|
75
|
+
process.env.LOCALAPPDATA + "\\Programs\\Draw.io\\drawio.exe"
|
|
76
|
+
];
|
|
77
|
+
return paths.some((p) => fs.existsSync(p));
|
|
78
|
+
}
|
|
79
|
+
return false;
|
|
80
|
+
} catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
export {
|
|
85
|
+
isDrawioInstalled,
|
|
86
|
+
openDiagram
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=open-diagram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/tools/drawio-convert/open-diagram.js"],"sourcesContent":["/**\n * Open Diagram in Draw.io Application\n *\n * Cross-platform utility to open diagrams in Draw.io desktop app or web app\n */\n\nimport { execSync } from 'child_process';\nimport fs from 'fs';\n\n/**\n * Open diagram in Draw.io application\n * @param {string} drawioPath - Absolute path to .drawio file\n * @returns {Object} { success, message, openedWith }\n */\nexport function openDiagram(drawioPath) {\n // 1. Validate file exists\n if (!fs.existsSync(drawioPath)) {\n return {\n success: false,\n message: `File not found: ${drawioPath}`,\n openedWith: null,\n };\n }\n\n const platform = process.platform;\n let command;\n let openedWith = 'desktop';\n\n // 2. Build platform-specific command\n try {\n if (platform === 'darwin') {\n // macOS\n command = `open -a \"Draw.io\" \"${drawioPath}\"`;\n } else if (platform === 'linux') {\n // Linux - try Draw.io desktop first, fallback to xdg-open\n try {\n // Check if Draw.io is installed\n execSync('which drawio', { stdio: 'ignore' });\n command = `drawio \"${drawioPath}\"`;\n } catch {\n // Draw.io not found, use xdg-open\n command = `xdg-open \"${drawioPath}\"`;\n }\n } else if (platform === 'win32') {\n // Windows\n command = `start \"\" \"${drawioPath}\"`;\n } else {\n throw new Error(`Unsupported platform: ${platform}`);\n }\n\n // 3. Try to open desktop app\n execSync(command, { stdio: 'ignore' });\n\n return {\n success: true,\n message: `Opened in Draw.io desktop app`,\n openedWith: 'desktop',\n };\n } catch (err) {\n // Desktop app failed, fallback to web app\n try {\n const webUrl = `https://app.diagrams.net/?splash=0&local=1#${encodeURIComponent(drawioPath)}`;\n\n if (platform === 'darwin') {\n execSync(`open \"${webUrl}\"`, { stdio: 'ignore' });\n } else if (platform === 'linux') {\n execSync(`xdg-open \"${webUrl}\"`, { stdio: 'ignore' });\n } else if (platform === 'win32') {\n execSync(`start \"\" \"${webUrl}\"`, { stdio: 'ignore', shell: true });\n }\n\n return {\n success: true,\n message: `Opened in Draw.io web app (desktop app not found)`,\n openedWith: 'web',\n };\n } catch (webErr) {\n return {\n success: false,\n message: `Failed to open Draw.io: ${webErr.message}`,\n openedWith: null,\n };\n }\n }\n}\n\n/**\n * Check if Draw.io desktop app is installed\n * @returns {boolean} True if installed\n */\nexport function isDrawioInstalled() {\n const platform = process.platform;\n\n try {\n if (platform === 'darwin') {\n // Check macOS Applications folder\n execSync('ls /Applications/Draw.io.app 2>/dev/null', { stdio: 'ignore' });\n return true;\n } else if (platform === 'linux') {\n // Check Linux\n execSync('which drawio', { stdio: 'ignore' });\n return true;\n } else if (platform === 'win32') {\n // Check Windows (check common install locations)\n const paths = [\n 'C:\\\\Program Files\\\\Draw.io\\\\drawio.exe',\n 'C:\\\\Program Files (x86)\\\\Draw.io\\\\drawio.exe',\n process.env.LOCALAPPDATA + '\\\\Programs\\\\Draw.io\\\\drawio.exe',\n ];\n return paths.some(p => fs.existsSync(p));\n }\n return false;\n } catch {\n return false;\n }\n}\n"],"mappings":";;;AAMA,SAAS,gBAAgB;AACzB,OAAO,QAAQ;AAOR,SAAS,YAAY,YAAY;AAEtC,MAAI,CAAC,GAAG,WAAW,UAAU,GAAG;AAC9B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS,mBAAmB,UAAU;AAAA,MACtC,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ;AACzB,MAAI;AACJ,MAAI,aAAa;AAGjB,MAAI;AACF,QAAI,aAAa,UAAU;AAEzB,gBAAU,sBAAsB,UAAU;AAAA,IAC5C,WAAW,aAAa,SAAS;AAE/B,UAAI;AAEF,iBAAS,gBAAgB,EAAE,OAAO,SAAS,CAAC;AAC5C,kBAAU,WAAW,UAAU;AAAA,MACjC,QAAQ;AAEN,kBAAU,aAAa,UAAU;AAAA,MACnC;AAAA,IACF,WAAW,aAAa,SAAS;AAE/B,gBAAU,aAAa,UAAU;AAAA,IACnC,OAAO;AACL,YAAM,IAAI,MAAM,yBAAyB,QAAQ,EAAE;AAAA,IACrD;AAGA,aAAS,SAAS,EAAE,OAAO,SAAS,CAAC;AAErC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,IACd;AAAA,EACF,SAAS,KAAK;AAEZ,QAAI;AACF,YAAM,SAAS,8CAA8C,mBAAmB,UAAU,CAAC;AAE3F,UAAI,aAAa,UAAU;AACzB,iBAAS,SAAS,MAAM,KAAK,EAAE,OAAO,SAAS,CAAC;AAAA,MAClD,WAAW,aAAa,SAAS;AAC/B,iBAAS,aAAa,MAAM,KAAK,EAAE,OAAO,SAAS,CAAC;AAAA,MACtD,WAAW,aAAa,SAAS;AAC/B,iBAAS,aAAa,MAAM,KAAK,EAAE,OAAO,UAAU,OAAO,KAAK,CAAC;AAAA,MACnE;AAEA,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,IACF,SAAS,QAAQ;AACf,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,2BAA2B,OAAO,OAAO;AAAA,QAClD,YAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAMO,SAAS,oBAAoB;AAClC,QAAM,WAAW,QAAQ;AAEzB,MAAI;AACF,QAAI,aAAa,UAAU;AAEzB,eAAS,4CAA4C,EAAE,OAAO,SAAS,CAAC;AACxE,aAAO;AAAA,IACT,WAAW,aAAa,SAAS;AAE/B,eAAS,gBAAgB,EAAE,OAAO,SAAS,CAAC;AAC5C,aAAO;AAAA,IACT,WAAW,aAAa,SAAS;AAE/B,YAAM,QAAQ;AAAA,QACZ;AAAA,QACA;AAAA,QACA,QAAQ,IAAI,eAAe;AAAA,MAC7B;AACA,aAAO,MAAM,KAAK,OAAK,GAAG,WAAW,CAAC,CAAC;AAAA,IACzC;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
|