mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-08 18:16:44 +02:00
Refactor mindmap validation to handle multiple root nodes and add SquareNode support
This commit is contained in:
@@ -41,9 +41,10 @@ export class MindmapValidator {
|
||||
checkSingleRoot(doc: MindmapDoc, accept: ValidationAcceptor): void {
|
||||
// eslint-disable-next-line no-console
|
||||
console.debug('CHECKING SINGLE ROOT');
|
||||
let rootNodeFound = false;
|
||||
let rootNodeIndentation;
|
||||
|
||||
for (const row of doc.MindmapRows) {
|
||||
console.debug('ROW BY ROW', row.indent);
|
||||
// Skip non-node items (e.g., class decorations, icon decorations)
|
||||
if (
|
||||
!row.item ||
|
||||
@@ -52,18 +53,24 @@ export class MindmapValidator {
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is a root node (no indentation)
|
||||
if (row.indent === undefined) {
|
||||
if (rootNodeFound) {
|
||||
// If we've already found a root node, report an error
|
||||
accept('error', 'Multiple root nodes are not allowed in a mindmap.', {
|
||||
node: row,
|
||||
property: 'item',
|
||||
});
|
||||
} else {
|
||||
rootNodeFound = true;
|
||||
}
|
||||
if (
|
||||
rootNodeIndentation === undefined && // Check if this is a root node (no indentation)
|
||||
row.indent === undefined
|
||||
) {
|
||||
rootNodeIndentation = 0;
|
||||
} else if (row.indent === undefined) {
|
||||
console.debug('FAIL 1', rootNodeIndentation, row.indent);
|
||||
// If we've already found a root node, report an error
|
||||
accept('error', 'Multiple root nodes are not allowed in a mindmap.', {
|
||||
node: row,
|
||||
property: 'item',
|
||||
});
|
||||
} else if (rootNodeIndentation >= row.indent) {
|
||||
console.debug('FAIL 2', rootNodeIndentation, row.indent, row.item);
|
||||
accept('error', 'Multiple root nodes are not allowed in a mindmap.', {
|
||||
node: row,
|
||||
property: 'item',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ Item:
|
||||
|
||||
// Use a special rule order to handle the parsing precedence
|
||||
Node:
|
||||
CircleNode | OtherComplex | SimpleNode | RoundedNode;
|
||||
CircleNode | OtherComplex | SimpleNode | RoundedNode | SquareNode;
|
||||
|
||||
// Specifically handle double parentheses case - highest priority
|
||||
CircleNode:
|
||||
@@ -29,6 +29,9 @@ CircleNode:
|
||||
RoundedNode:
|
||||
(id=ID)? desc=(ROUNDED_STR_QUOTES|ROUNDED_STR);
|
||||
|
||||
SquareNode:
|
||||
(id=ID)? desc=(SQUARE_STR_QUOTES|SQUARE_STR);
|
||||
|
||||
// Handle other complex node variants
|
||||
OtherComplex:
|
||||
id=ID
|
||||
@@ -62,6 +65,8 @@ terminal CLASS_KEYWORD: ':::';
|
||||
terminal CIRCLE_STR: /\(\(([\s\S]*?)\)\)/;
|
||||
terminal ROUNDED_STR_QUOTES: /\(\"([\s\S]*?)\"\)/;
|
||||
terminal ROUNDED_STR: /\(([\s\S]*?)\)/;
|
||||
terminal SQUARE_STR_QUOTES: /\[\"([\s\S]*?)\"\]/;
|
||||
terminal SQUARE_STR: /\[([\s\S]*?)\]/;
|
||||
// terminal CIRCLE_STR: /(?!\(\()[\s\S]+?(?!\(\()/;
|
||||
terminal ID: /[a-zA-Z0-9_\-\.\/]+/;
|
||||
terminal STRING: /"[^"]*"|'[^']*'/;
|
||||
|
@@ -15,6 +15,10 @@ export class MindmapValueConverter extends AbstractMermaidValueConverter {
|
||||
return input.replace('(', '').replace(')', '').trim();
|
||||
} else if (rule.name === 'ROUNDED_STR_QUOTES') {
|
||||
return input.replace('("', '').replace('")', '').trim();
|
||||
} else if (rule.name === 'SQUARE_STR') {
|
||||
return input.replace('[', '').replace(']', '').trim();
|
||||
} else if (rule.name === 'SQUARE_STR_QUOTES') {
|
||||
return input.replace('["', '').replace('"]', '').trim();
|
||||
} else if (rule.name === 'ARCH_TEXT_ICON') {
|
||||
return input.replace(/["()]/g, '');
|
||||
} else if (rule.name === 'ARCH_TITLE') {
|
||||
|
@@ -133,7 +133,7 @@ describe('Hierarchy (ported from mindmap.spec.ts)', () => {
|
||||
expect(child2Node.id).toBe('child2');
|
||||
});
|
||||
|
||||
it.only('MMP-5 Multiple roots are illegal', async () => {
|
||||
it('MMP-5 Multiple roots are illegal', async () => {
|
||||
const str = 'mindmap\nroot\nfakeRoot';
|
||||
const result = await validatedParse(str, { validation: true });
|
||||
// Langium parser may not throw, but should have parserErrors
|
||||
@@ -145,10 +145,10 @@ describe('Hierarchy (ported from mindmap.spec.ts)', () => {
|
||||
expect(result2.diagnostics?.length).toBe(0);
|
||||
});
|
||||
|
||||
it('MMP-6 real root in wrong place', () => {
|
||||
it('MMP-6 real root in wrong place', async () => {
|
||||
const str = 'mindmap\n root\n fakeRoot\nrealRootWrongPlace';
|
||||
const result = parse(str);
|
||||
expect(result.parserErrors.length).toBeGreaterThan(0);
|
||||
const r2 = await validatedParse(str, { validation: true });
|
||||
expect(r2.diagnostics?.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user