(xmlString: string)
| 62 | * @returns A legal XML string with properly closed tags and removed incomplete mxCell elements. |
| 63 | */ |
| 64 | export function convertToLegalXml(xmlString: string): string { |
| 65 | // This regex will match either self-closing <mxCell .../> or a block element |
| 66 | // <mxCell ...> ... </mxCell>. Unfinished ones are left out because they don't match. |
| 67 | const regex = /<mxCell\b[^>]*(?:\/>|>([\s\S]*?)<\/mxCell>)/g |
| 68 | let match: RegExpExecArray | null |
| 69 | let result = "<root>\n" |
| 70 | |
| 71 | while ((match = regex.exec(xmlString)) !== null) { |
| 72 | // match[0] contains the entire matched mxCell block |
| 73 | let cellContent = match[0] |
| 74 | |
| 75 | // Remove orphaned <mxPoint> elements that are directly inside <mxGeometry> |
| 76 | // without an 'as' attribute (like as="sourcePoint", as="targetPoint") |
| 77 | // and not inside <Array as="points"> |
| 78 | // These cause "Could not add object mxPoint" errors in draw.io |
| 79 | // First check if there's an <Array as="points"> - if so, keep all mxPoints inside it |
| 80 | const hasArrayPoints = /<Array\s+as="points">/.test(cellContent) |
| 81 | if (!hasArrayPoints) { |
| 82 | // Remove mxPoint elements without 'as' attribute |
| 83 | cellContent = cellContent.replace( |
| 84 | /<mxPoint\b[^>]*\/>/g, |
| 85 | (pointMatch) => { |
| 86 | // Keep if it has an 'as' attribute |
| 87 | if (/\sas=/.test(pointMatch)) { |
| 88 | return pointMatch |
| 89 | } |
| 90 | // Remove orphaned mxPoint |
| 91 | return "" |
| 92 | }, |
| 93 | ) |
| 94 | } |
| 95 | |
| 96 | // Indent each line of the matched block for readability. |
| 97 | const formatted = cellContent |
| 98 | .split("\n") |
| 99 | .map((line) => " " + line.trim()) |
| 100 | .filter((line) => line.trim()) // Remove empty lines from removed mxPoints |
| 101 | .join("\n") |
| 102 | result += formatted + "\n" |
| 103 | } |
| 104 | result += "</root>" |
| 105 | |
| 106 | return result |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * Wrap XML content with the full mxfile structure required by draw.io. |
no outgoing calls
no test coverage detected