air-dml 1.2.9 → 2.1.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.
@@ -1,670 +1,13 @@
1
- import { Parser } from '@dbml/core';
1
+ export { parseAirDML as parseAirDMLResult, exportToAirDML, Lexer, LexerError, Parser, ParseError, transformAstToDiagram, } from './new';
2
+ import { parseAirDML as parseAirDMLNew } from './new';
2
3
  export function parseAirDML(airDmlText, diagramId) {
3
- const commentMap = parseComments(airDmlText);
4
- const tableAttributes = parseTableAttributes(airDmlText);
5
- const columnAttributes = parseColumnAttributes(airDmlText);
6
- const referenceAttributes = parseReferenceAttributes(airDmlText);
7
- const cleanedDbml = removeExtendedAttributes(airDmlText);
8
- const parser = new Parser();
9
- const database = parser.parse(cleanedDbml, 'dbml');
10
- const project = database.name || 'Untitled Project';
11
- const databaseType = database.databaseType || 'PostgreSQL';
12
- const tables = database.schemas.flatMap((schema) => schema.tables.map((dbmlTable) => {
13
- const tableAttrs = tableAttributes.get(dbmlTable.name) || {};
14
- const columns = dbmlTable.fields.map((field) => {
15
- const colAttrs = columnAttributes.get(`${dbmlTable.name}.${field.name}`) || {};
16
- return {
17
- name: field.name,
18
- logicalName: colAttrs.alias,
19
- type: mapDbmlTypeToDataType(field.type.type_name),
20
- typeParams: Array.isArray(field.type.args) ? field.type.args.join(', ') : undefined,
21
- pk: field.pk || false,
22
- fk: colAttrs.fk || false,
23
- unique: field.unique || false,
24
- notNull: field.not_null || false,
25
- default: field.dbdefault?.value,
26
- increment: field.increment || false,
27
- note: field.note,
28
- };
29
- });
30
- return {
31
- id: `table-${dbmlTable.name}`,
32
- name: dbmlTable.name,
33
- logicalName: tableAttrs.alias,
34
- columns,
35
- color: tableAttrs.color,
36
- pos: tableAttrs.pos_x !== undefined && tableAttrs.pos_y !== undefined
37
- ? { x: tableAttrs.pos_x, y: tableAttrs.pos_y }
38
- : undefined,
39
- areaIds: [],
40
- note: dbmlTable.note,
41
- leadingComments: commentMap.get(`table:${dbmlTable.name}`),
42
- };
43
- }));
44
- const references = database.schemas.flatMap((schema) => schema.refs.map((ref) => {
45
- const refId = `ref-${ref.endpoints[0].tableName}-${ref.endpoints[0].fieldNames[0]}`;
46
- const refKey = `${ref.endpoints[0].tableName}.${ref.endpoints[0].fieldNames[0]}-${ref.endpoints[1].tableName}.${ref.endpoints[1].fieldNames[0]}`;
47
- const refAttrs = referenceAttributes.get(refKey) || {};
48
- const fromTableId = `table-${ref.endpoints[0].tableName}`;
49
- const fromTable = tables.find((t) => t.id === fromTableId);
50
- if (fromTable) {
51
- const fromColumn = fromTable.columns.find((c) => c.name === ref.endpoints[0].fieldNames[0]);
52
- if (fromColumn) {
53
- fromColumn.fk = true;
54
- }
55
- }
56
- let refComments;
57
- for (const [key, comments] of commentMap.entries()) {
58
- if (key.startsWith('ref:')) {
59
- const refDef = key.substring(4);
60
- const normalizedRef = refDef.replace(/\s*\[[^\]]*\]\s*$/, '').trim();
61
- const refPattern1 = `${ref.endpoints[0].tableName}.${ref.endpoints[0].fieldNames[0]}`;
62
- const refPattern2 = `${ref.endpoints[1].tableName}.${ref.endpoints[1].fieldNames[0]}`;
63
- if (normalizedRef.includes(refPattern1) && normalizedRef.includes(refPattern2)) {
64
- refComments = comments;
65
- break;
66
- }
67
- }
68
- }
69
- return {
70
- id: refId,
71
- fromTable: fromTableId,
72
- fromColumn: ref.endpoints[0].fieldNames[0],
73
- toTable: `table-${ref.endpoints[1].tableName}`,
74
- toColumn: ref.endpoints[1].fieldNames[0],
75
- type: mapDbmlRelationType(ref.name),
76
- swapEdge: refAttrs.swap_edge,
77
- leadingComments: refComments,
78
- };
79
- }));
80
- const aiInferredRefs = parseAiInferredRefs(airDmlText, commentMap);
81
- references.push(...aiInferredRefs);
82
- const areaAttributes = parseAreaAttributes(airDmlText);
83
- const areas = database.schemas.flatMap((schema) => (schema.tableGroups || []).map((group) => {
84
- const areaAttrs = areaAttributes.get(group.name) || {};
85
- const areaId = `area-${group.name}`;
86
- if (group.tables) {
87
- group.tables.forEach((tableRef) => {
88
- const tableName = typeof tableRef === 'string' ? tableRef : tableRef.name;
89
- const table = tables.find(t => t.name === tableName);
90
- if (table && !table.areaIds?.includes(areaId)) {
91
- table.areaIds = [...(table.areaIds || []), areaId];
92
- }
93
- });
94
- }
95
- const commonColumns = parseAreaCommonColumns(airDmlText, group.name);
96
- const note = parseAreaNote(airDmlText, group.name);
97
- const databaseType = parseAreaDatabaseType(airDmlText, group.name);
98
- const tableNames = (group.tables || []).map((tableRef) => typeof tableRef === 'string' ? tableRef : tableRef.name);
99
- const tableIds = tableNames
100
- .map((tableName) => {
101
- const table = tables.find(t => t.name === tableName);
102
- return table?.id;
103
- })
104
- .filter(Boolean);
105
- return {
106
- id: areaId,
107
- name: group.name,
108
- tables: tableIds,
109
- color: areaAttrs.color,
110
- pos: areaAttrs.pos_x !== undefined && areaAttrs.pos_y !== undefined
111
- ? { x: areaAttrs.pos_x, y: areaAttrs.pos_y }
112
- : undefined,
113
- width: areaAttrs.width,
114
- height: areaAttrs.height,
115
- labelHorizontal: areaAttrs.label_horizontal,
116
- labelVertical: areaAttrs.label_vertical,
117
- databaseType,
118
- note,
119
- commonColumns,
120
- leadingComments: commentMap.get(`area:${group.name}`),
121
- };
122
- }));
123
- return {
124
- id: diagramId || `diagram-${Date.now()}`,
125
- name: project,
126
- project,
127
- database: databaseType,
128
- tables,
129
- references,
130
- areas,
131
- createdAt: new Date().toISOString(),
132
- updatedAt: new Date().toISOString(),
133
- };
134
- }
135
- export function exportToAirDML(diagram) {
136
- let airDml = '';
137
- const formatComments = (comments) => {
138
- if (!comments || comments.length === 0)
139
- return '';
140
- return comments.map(c => `// ${c}\n`).join('');
141
- };
142
- airDml += `// ${diagram.name}\n`;
143
- const projectName = diagram.project || diagram.name || 'Untitled';
144
- airDml += `Project ${escapeIdentifier(projectName)} {\n`;
145
- airDml += ` database_type: '${diagram.database || 'PostgreSQL'}'\n`;
146
- airDml += ` Note: "Generated with AIR-DML"\n`;
147
- airDml += `}\n\n`;
148
- diagram.tables.forEach((table) => {
149
- airDml += formatComments(table.leadingComments);
150
- const tableAttrs = [];
151
- if (table.logicalName) {
152
- tableAttrs.push(`alias: "${escapeString(table.logicalName)}"`);
153
- }
154
- if (table.pos) {
155
- tableAttrs.push(`pos_x: ${table.pos.x}`);
156
- tableAttrs.push(`pos_y: ${table.pos.y}`);
157
- }
158
- if (table.color) {
159
- tableAttrs.push(`color: "${table.color}"`);
160
- }
161
- const attrStr = tableAttrs.length > 0 ? ` [${tableAttrs.join(', ')}]` : '';
162
- airDml += `Table ${escapeIdentifier(table.name)}${attrStr} {\n`;
163
- table.columns.forEach((column) => {
164
- const constraints = [];
165
- if (column.pk)
166
- constraints.push('pk');
167
- if (column.fk)
168
- constraints.push('fk');
169
- if (column.unique)
170
- constraints.push('unique');
171
- if (column.notNull)
172
- constraints.push('not null');
173
- if (column.increment)
174
- constraints.push('increment');
175
- if (column.default)
176
- constraints.push(`default: ${column.default}`);
177
- if (column.logicalName) {
178
- constraints.push(`alias: "${escapeString(column.logicalName)}"`);
179
- }
180
- if (column.note) {
181
- constraints.push(`note: "${escapeString(column.note)}"`);
182
- }
183
- const typeStr = column.typeParams
184
- ? `${column.type}(${column.typeParams})`
185
- : column.type;
186
- const constraintStr = constraints.length > 0 ? ` [${constraints.join(', ')}]` : '';
187
- airDml += ` ${escapeIdentifier(column.name)} ${typeStr}${constraintStr}\n`;
188
- });
189
- if (table.note) {
190
- airDml += `\n Note: "${escapeString(table.note)}"\n`;
191
- }
192
- airDml += `}\n\n`;
193
- });
194
- diagram.references.forEach((ref) => {
195
- airDml += formatComments(ref.leadingComments);
196
- const fromTable = diagram.tables.find((t) => t.id === ref.fromTable);
197
- const toTable = diagram.tables.find((t) => t.id === ref.toTable);
198
- if (fromTable && toTable) {
199
- const relSymbol = getRelationshipSymbol(ref.type);
200
- const refAttrs = [];
201
- if (ref.swapEdge) {
202
- refAttrs.push('swapEdge: true');
203
- }
204
- const attrStr = refAttrs.length > 0 ? ` [${refAttrs.join(', ')}]` : '';
205
- airDml += `Ref: ${escapeIdentifier(fromTable.name)}.${escapeIdentifier(ref.fromColumn)} ${relSymbol} ${escapeIdentifier(toTable.name)}.${escapeIdentifier(ref.toColumn)}${attrStr}\n`;
206
- }
207
- });
208
- airDml += '\n';
209
- if (diagram.areas && diagram.areas.length > 0) {
210
- diagram.areas.forEach((area) => {
211
- airDml += formatComments(area.leadingComments);
212
- const tablesInArea = diagram.tables.filter(t => t.areaIds?.includes(area.id));
213
- const tableNames = tablesInArea
214
- .map(table => escapeIdentifier(table.name))
215
- .filter(Boolean);
216
- if (tableNames.length > 0) {
217
- const areaAttrs = [];
218
- if (area.pos) {
219
- areaAttrs.push(`pos_x: ${area.pos.x}`);
220
- areaAttrs.push(`pos_y: ${area.pos.y}`);
221
- }
222
- if (area.width) {
223
- areaAttrs.push(`width: ${area.width}`);
224
- }
225
- if (area.height) {
226
- areaAttrs.push(`height: ${area.height}`);
227
- }
228
- if (area.color) {
229
- areaAttrs.push(`color: "${area.color}"`);
230
- }
231
- if (area.labelHorizontal) {
232
- areaAttrs.push(`label_horizontal: "${area.labelHorizontal}"`);
233
- }
234
- if (area.labelVertical) {
235
- areaAttrs.push(`label_vertical: "${area.labelVertical}"`);
236
- }
237
- const attrStr = areaAttrs.length > 0 ? ` [${areaAttrs.join(', ')}]` : '';
238
- airDml += `Area ${escapeIdentifier(area.name)}${attrStr} {\n`;
239
- tableNames.forEach((name) => {
240
- airDml += ` ${name}\n`;
241
- });
242
- if (area.databaseType) {
243
- airDml += `\n database_type: "${area.databaseType}"\n`;
244
- }
245
- if (area.commonColumns && area.commonColumns.length > 0) {
246
- airDml += `\n CommonColumns: [\n`;
247
- area.commonColumns.forEach((column) => {
248
- const constraints = [];
249
- if (column.pk)
250
- constraints.push('pk');
251
- if (column.fk)
252
- constraints.push('fk');
253
- if (column.unique)
254
- constraints.push('unique');
255
- if (column.notNull)
256
- constraints.push('not null');
257
- if (column.increment)
258
- constraints.push('increment');
259
- if (column.default)
260
- constraints.push(`default: ${column.default}`);
261
- if (column.logicalName) {
262
- constraints.push(`alias: "${escapeString(column.logicalName)}"`);
263
- }
264
- const typeStr = column.typeParams
265
- ? `${column.type}(${column.typeParams})`
266
- : column.type;
267
- const constraintStr = constraints.length > 0 ? ` [${constraints.join(', ')}]` : '';
268
- airDml += ` ${escapeIdentifier(column.name)} ${typeStr}${constraintStr}\n`;
269
- });
270
- airDml += ` ]\n`;
271
- }
272
- if (area.note) {
273
- airDml += `\n Note: "${area.note.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"\n`;
274
- }
275
- airDml += `}\n\n`;
276
- }
277
- });
278
- }
279
- return airDml.trim();
280
- }
281
- function splitAttributes(attrsStr) {
282
- const result = [];
283
- let current = '';
284
- let inQuotes = false;
285
- let quoteChar = '';
286
- for (let i = 0; i < attrsStr.length; i++) {
287
- const char = attrsStr[i];
288
- if ((char === '"' || char === "'") && (i === 0 || attrsStr[i - 1] !== '\\')) {
289
- if (!inQuotes) {
290
- inQuotes = true;
291
- quoteChar = char;
292
- }
293
- else if (char === quoteChar) {
294
- inQuotes = false;
295
- quoteChar = '';
296
- }
297
- current += char;
298
- }
299
- else if (char === ',' && !inQuotes) {
300
- if (current.trim()) {
301
- result.push(current.trim());
302
- }
303
- current = '';
304
- }
305
- else {
306
- current += char;
307
- }
308
- }
309
- if (current.trim()) {
310
- result.push(current.trim());
311
- }
312
- return result;
313
- }
314
- function removeExtendedAttributes(airDmlText) {
315
- let cleaned = airDmlText;
316
- cleaned = cleaned.replace(/Table\s+(["`]?)(\w+)\1\s*\[([^\]]+)\]/g, (_match, quote, tableName, attrs) => {
317
- const standardAttrs = splitAttributes(attrs)
318
- .filter((attr) => {
319
- const attrName = attr.split(':')[0].trim().toLowerCase();
320
- return attrName === 'headercolor' || attrName.startsWith('note');
321
- });
322
- if (standardAttrs.length > 0) {
323
- return `Table ${quote}${tableName}${quote} [${standardAttrs.join(', ')}]`;
324
- }
325
- else {
326
- return `Table ${quote}${tableName}${quote}`;
327
- }
328
- });
329
- cleaned = cleaned.replace(/(\s+)(["`]?)(\w+)\2\s+(\w+(?:\([^)]*\))?)\s*\[([^\]]+)\]/g, (_match, indent, quote, colName, colType, attrs) => {
330
- const standardAttrs = splitAttributes(attrs)
331
- .filter((attr) => {
332
- const lower = attr.toLowerCase();
333
- return (lower === 'pk' ||
334
- lower === 'unique' ||
335
- lower === 'not null' ||
336
- lower === 'increment' ||
337
- lower.startsWith('default') ||
338
- lower.startsWith('note') ||
339
- lower.startsWith('ref'));
340
- });
341
- if (standardAttrs.length > 0) {
342
- return `${indent}${quote}${colName}${quote} ${colType} [${standardAttrs.join(', ')}]`;
343
- }
344
- else {
345
- return `${indent}${quote}${colName}${quote} ${colType}`;
346
- }
347
- });
348
- cleaned = cleaned.replace(/Ref\s*:\s*([^[\n]+)\[([^\]]+)\]/g, (_match, refDef, attrs) => {
349
- const standardAttrs = splitAttributes(attrs)
350
- .filter((attr) => {
351
- const lower = attr.toLowerCase();
352
- return lower.startsWith('delete') || lower.startsWith('update') ||
353
- lower.startsWith('ondelete') || lower.startsWith('onupdate');
354
- });
355
- if (standardAttrs.length > 0) {
356
- return `Ref: ${refDef}[${standardAttrs.join(', ')}]`;
357
- }
358
- else {
359
- return `Ref: ${refDef}`;
360
- }
361
- });
362
- cleaned = cleaned.replace(/Ref\s*:\s*[^\n]*~[^\n]*/g, '');
363
- cleaned = cleaned.replace(/Area\s+(["`]?)(.+?)\1\s*\[([^\]]+)\]/g, (_match, quote, areaName) => {
364
- return `TableGroup ${quote}${areaName}${quote}`;
365
- });
366
- cleaned = cleaned.replace(/Area\s+(["`]?)(.+?)\1\s*\{/g, (_match, quote, areaName) => {
367
- return `TableGroup ${quote}${areaName}${quote} {`;
368
- });
369
- return cleaned;
370
- }
371
- function parseTableAttributes(airDmlText) {
372
- const result = new Map();
373
- const tableRegex = /Table\s+(["`]?)(\w+)\1\s*\[([^\]]+)\]/g;
374
- let match;
375
- while ((match = tableRegex.exec(airDmlText)) !== null) {
376
- const tableName = match[2];
377
- const attrsStr = match[3];
378
- const attrs = parseAttributesString(attrsStr);
379
- result.set(tableName, attrs);
380
- }
381
- return result;
382
- }
383
- function parseColumnAttributes(airDmlText) {
384
- const result = new Map();
385
- const tableBlocks = airDmlText.split(/Table\s+/);
386
- tableBlocks.forEach((block) => {
387
- const tableNameMatch = block.match(/^(["`]?)(\w+)\1\s*(?:\[[^\]]*\])?\s*\{/);
388
- if (!tableNameMatch)
389
- return;
390
- const tableName = tableNameMatch[2];
391
- const columnRegex = /^\s*(["`]?)(\w+)\1\s+\w+(?:\([^)]*\))?\s*\[([^\]]+)\]/gm;
392
- let colMatch;
393
- while ((colMatch = columnRegex.exec(block)) !== null) {
394
- const columnName = colMatch[2];
395
- const attrsStr = colMatch[3];
396
- const attrs = parseAttributesString(attrsStr);
397
- if (attrs.alias || attrs.fk !== undefined) {
398
- result.set(`${tableName}.${columnName}`, attrs);
399
- }
400
- }
401
- });
402
- return result;
403
- }
404
- function parseAreaAttributes(airDmlText) {
405
- const result = new Map();
406
- const areaRegex = /Area\s+(["`]?)(.+?)\1\s*\[([^\]]+)\]/g;
407
- let match;
408
- while ((match = areaRegex.exec(airDmlText)) !== null) {
409
- const areaName = match[2];
410
- const attrsStr = match[3];
411
- const attrs = parseAttributesString(attrsStr);
412
- result.set(areaName, attrs);
413
- }
414
- return result;
415
- }
416
- function parseAreaCommonColumns(airDmlText, areaName) {
417
- const areaBlockRegex = new RegExp(`Area\\s+(["\`]?)${areaName}\\1\\s*(?:\\[[^\\]]*\\])?\\s*\\{([^}]*)\\}`, 's');
418
- const areaMatch = areaBlockRegex.exec(airDmlText);
419
- if (!areaMatch)
420
- return undefined;
421
- const areaContent = areaMatch[2];
422
- const commonColumnsRegex = /CommonColumns:?\s*\[([^\]]*)\]/s;
423
- const commonColumnsMatch = commonColumnsRegex.exec(areaContent);
424
- if (!commonColumnsMatch)
425
- return undefined;
426
- const columnsContent = commonColumnsMatch[1];
427
- const columns = [];
428
- const columnLines = columnsContent.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('//'));
429
- for (const line of columnLines) {
430
- const columnMatch = line.match(/^(["`]?)(\w+)\1\s+(\w+)(?:\(([^)]+)\))?\s*(?:\[([^\]]+)\])?/);
431
- if (!columnMatch)
432
- continue;
433
- const columnName = columnMatch[2];
434
- const typeName = columnMatch[3];
435
- const typeParams = columnMatch[4];
436
- const constraintsStr = columnMatch[5] || '';
437
- const column = {
438
- name: columnName,
439
- type: mapDbmlTypeToDataType(typeName),
440
- typeParams,
441
- pk: /\bpk\b/.test(constraintsStr),
442
- fk: /\bfk\b/.test(constraintsStr),
443
- unique: /\bunique\b/.test(constraintsStr),
444
- notNull: /\bnot\s+null\b/.test(constraintsStr),
445
- increment: /\bincrement\b/.test(constraintsStr),
446
- };
447
- const aliasMatch = constraintsStr.match(/alias\s*:\s*"([^"]*)"/);
448
- if (aliasMatch) {
449
- column.logicalName = aliasMatch[1];
450
- }
451
- const defaultMatch = constraintsStr.match(/default\s*:\s*([^,\]]+)/);
452
- if (defaultMatch) {
453
- column.default = defaultMatch[1].trim();
454
- }
455
- columns.push(column);
456
- }
457
- return columns.length > 0 ? columns : undefined;
458
- }
459
- function parseAreaNote(airDmlText, areaName) {
460
- const areaBlockRegex = new RegExp(`Area\\s+(["\`]?)${areaName}\\1\\s*(?:\\[[^\\]]*\\])?\\s*\\{([^}]*)\\}`, 's');
461
- const areaMatch = areaBlockRegex.exec(airDmlText);
462
- if (!areaMatch)
463
- return undefined;
464
- const areaContent = areaMatch[2];
465
- const noteRegex = /Note:?\s*"([^"]*)"/;
466
- const noteMatch = noteRegex.exec(areaContent);
467
- return noteMatch ? noteMatch[1] : undefined;
468
- }
469
- function parseAreaDatabaseType(airDmlText, areaName) {
470
- const areaBlockRegex = new RegExp(`Area\\s+(["\`]?)${areaName}\\1\\s*(?:\\[[^\\]]*\\])?\\s*\\{([^}]*)\\}`, 's');
471
- const areaMatch = areaBlockRegex.exec(airDmlText);
472
- if (!areaMatch)
473
- return undefined;
474
- const areaContent = areaMatch[2];
475
- const databaseTypeRegex = /database_type:?\s*["']([^"']*)["']/;
476
- const databaseTypeMatch = databaseTypeRegex.exec(areaContent);
477
- return databaseTypeMatch ? databaseTypeMatch[1] : undefined;
478
- }
479
- function parseReferenceAttributes(airDmlText) {
480
- const result = new Map();
481
- const refRegex = /Ref\s*:\s*(["`]?)(\w+)\1\.(["`]?)(\w+)\3\s*[<>\-~]+\s*(["`]?)(\w+)\5\.(["`]?)(\w+)\7\s*\[([^\]]+)\]/g;
482
- let match;
483
- while ((match = refRegex.exec(airDmlText)) !== null) {
484
- const fromTable = match[2];
485
- const fromColumn = match[4];
486
- const toTable = match[6];
487
- const toColumn = match[8];
488
- const attrsStr = match[9];
489
- const attrs = parseAttributesString(attrsStr);
490
- const refKey = `${fromTable}.${fromColumn}-${toTable}.${toColumn}`;
491
- result.set(refKey, attrs);
492
- }
493
- return result;
494
- }
495
- function parseAiInferredRefs(airDmlText, commentMap) {
496
- const refs = [];
497
- const refRegex = /Ref\s*:\s*(["`]?)(\w+)\1\.(["`]?)(\w+)\3\s*~\s*(["`]?)(\w+)\5\.(["`]?)(\w+)\7(?:\s*\[([^\]]+)\])?/g;
498
- let match;
499
- while ((match = refRegex.exec(airDmlText)) !== null) {
500
- const fromTable = match[2];
501
- const fromColumn = match[4];
502
- const toTable = match[6];
503
- const toColumn = match[8];
504
- const attrsStr = match[9] || '';
505
- const attrs = parseAttributesString(attrsStr);
506
- const refId = `ref-${fromTable}-${fromColumn}-${toTable}-${toColumn}`;
507
- let refComments;
508
- for (const [key, comments] of commentMap.entries()) {
509
- if (key.startsWith('ref:')) {
510
- const refDef = key.substring(4);
511
- if (refDef.includes(fromTable) && refDef.includes(fromColumn) &&
512
- refDef.includes(toTable) && refDef.includes(toColumn) &&
513
- refDef.includes('~')) {
514
- refComments = comments;
515
- break;
516
- }
517
- }
518
- }
519
- refs.push({
520
- id: refId,
521
- fromTable: `table-${fromTable}`,
522
- fromColumn: fromColumn,
523
- toTable: `table-${toTable}`,
524
- toColumn: toColumn,
525
- type: 'ai-inferred',
526
- swapEdge: attrs.swap_edge,
527
- leadingComments: refComments,
528
- });
529
- }
530
- return refs;
531
- }
532
- function parseComments(airDmlText) {
533
- const commentMap = new Map();
534
- const lines = airDmlText.split('\n');
535
- let accumulatedComments = [];
536
- for (let i = 0; i < lines.length; i++) {
537
- const line = lines[i].trim();
538
- const commentMatch = line.match(/^\/\/\s*(.*)$/);
539
- if (commentMatch) {
540
- accumulatedComments.push(commentMatch[1]);
541
- continue;
542
- }
543
- if (accumulatedComments.length > 0 && line.length > 0) {
544
- let elementKey = null;
545
- const tableMatch = line.match(/^Table\s+(\w+)/);
546
- if (tableMatch) {
547
- elementKey = `table:${tableMatch[1]}`;
548
- }
549
- const areaMatch = line.match(/^Area\s+"([^"]+)"/);
550
- if (areaMatch) {
551
- elementKey = `area:${areaMatch[1]}`;
552
- }
553
- const refMatch = line.match(/^Ref\s*:\s*(.+)/);
554
- if (refMatch) {
555
- const refDef = refMatch[1].trim();
556
- elementKey = `ref:${refDef}`;
557
- }
558
- if (elementKey) {
559
- commentMap.set(elementKey, [...accumulatedComments]);
560
- accumulatedComments = [];
561
- }
562
- }
563
- }
564
- return commentMap;
565
- }
566
- function parseAttributesString(attrsStr) {
567
- const attrs = {};
568
- const aliasMatch = attrsStr.match(/alias\s*:\s*"([^"]*)"/);
569
- if (aliasMatch)
570
- attrs.alias = aliasMatch[1];
571
- const posXMatch = attrsStr.match(/pos_x\s*:\s*(-?\d+(?:\.\d+)?)/);
572
- if (posXMatch)
573
- attrs.pos_x = parseFloat(posXMatch[1]);
574
- const posYMatch = attrsStr.match(/pos_y\s*:\s*(-?\d+(?:\.\d+)?)/);
575
- if (posYMatch)
576
- attrs.pos_y = parseFloat(posYMatch[1]);
577
- const widthMatch = attrsStr.match(/width\s*:\s*(-?\d+(?:\.\d+)?)/);
578
- if (widthMatch)
579
- attrs.width = parseFloat(widthMatch[1]);
580
- const heightMatch = attrsStr.match(/height\s*:\s*(-?\d+(?:\.\d+)?)/);
581
- if (heightMatch)
582
- attrs.height = parseFloat(heightMatch[1]);
583
- const colorMatch = attrsStr.match(/color\s*:\s*"([^"]*)"/);
584
- if (colorMatch)
585
- attrs.color = colorMatch[1];
586
- const databaseTypeMatch = attrsStr.match(/database_type\s*:\s*"([^"]*)"/);
587
- if (databaseTypeMatch)
588
- attrs.database_type = databaseTypeMatch[1];
589
- const labelHorizontalMatch = attrsStr.match(/label_horizontal\s*:\s*"([^"]*)"/);
590
- if (labelHorizontalMatch)
591
- attrs.label_horizontal = labelHorizontalMatch[1];
592
- const labelVerticalMatch = attrsStr.match(/label_vertical\s*:\s*"([^"]*)"/);
593
- if (labelVerticalMatch)
594
- attrs.label_vertical = labelVerticalMatch[1];
595
- const swapEdgeMatch = attrsStr.match(/(?:swapEdge|swap_edge)\s*:\s*(true|false)/);
596
- if (swapEdgeMatch)
597
- attrs.swap_edge = swapEdgeMatch[1] === 'true';
598
- if (/\bfk\b/.test(attrsStr))
599
- attrs.fk = true;
600
- return attrs;
601
- }
602
- function mapDbmlTypeToDataType(dbmlType) {
603
- const typeMap = {
604
- int: 'integer',
605
- integer: 'integer',
606
- bigint: 'bigint',
607
- smallint: 'smallint',
608
- serial: 'serial',
609
- bigserial: 'bigserial',
610
- varchar: 'varchar',
611
- char: 'char',
612
- text: 'text',
613
- boolean: 'boolean',
614
- bool: 'boolean',
615
- date: 'date',
616
- time: 'time',
617
- timestamp: 'timestamp',
618
- timestamptz: 'timestamptz',
619
- numeric: 'numeric',
620
- decimal: 'decimal',
621
- real: 'real',
622
- double: 'double precision',
623
- json: 'json',
624
- jsonb: 'jsonb',
625
- uuid: 'uuid',
626
- bytea: 'bytea',
627
- };
628
- const lowerType = dbmlType.toLowerCase();
629
- return typeMap[lowerType] || dbmlType;
630
- }
631
- function mapDbmlRelationType(relType) {
632
- if (relType === '<')
633
- return 'many-to-one';
634
- if (relType === '>')
635
- return 'one-to-many';
636
- if (relType === '-')
637
- return 'one-to-one';
638
- if (relType === '<>' || relType === '><')
639
- return 'many-to-many';
640
- if (relType === '~')
641
- return 'ai-inferred';
642
- return 'many-to-one';
643
- }
644
- function getRelationshipSymbol(relType) {
645
- if (relType === 'many-to-one')
646
- return '<';
647
- if (relType === 'one-to-many')
648
- return '>';
649
- if (relType === 'one-to-one')
650
- return '-';
651
- if (relType === 'many-to-many')
652
- return '><';
653
- if (relType === 'any')
654
- return '~';
655
- if (relType === 'ai-inferred')
656
- return '~';
657
- return '<';
658
- }
659
- function escapeIdentifier(name) {
660
- if (/[^a-zA-Z0-9_]/.test(name)) {
661
- return `"${name.replace(/"/g, '\\"')}"`;
4
+ const result = parseAirDMLNew(airDmlText, { diagramId });
5
+ if (!result.success || !result.diagram) {
6
+ throw new Error(result.error || 'パースに失敗しました');
662
7
  }
663
- return name;
8
+ return result.diagram;
664
9
  }
665
- function escapeString(str) {
666
- if (!str)
667
- return '';
668
- return str.replace(/'/g, "\\'").replace(/\n/g, '\\n');
10
+ export function parseAirDMLSafe(airDmlText, diagramId) {
11
+ return parseAirDMLNew(airDmlText, { diagramId });
669
12
  }
670
13
  //# sourceMappingURL=index.js.map