diff --git a/src/importreport.test.ts b/src/importreport.test.ts index fe7cd21..58736b3 100644 --- a/src/importreport.test.ts +++ b/src/importreport.test.ts @@ -124,3 +124,15 @@ test("XMind 7 boundaries are read too", async () => { expect(roots[0].bounds).toEqual([roots[0].children[1].id, ...roots[0].children.map((k) => k.id)]); // "(0,)" runs to the last child expect(lost).toEqual(["boundary titles dropped", "boundaries over several topics drawn around each topic"]); }); + +test("a structure set on a single topic is reported, one equal to the sheet's is not", async () => { + const sheet = [{ id: "s", class: "sheet", title: "S", rootTopic: { id: "r", title: "root", structureClass: "org.xmind.ui.map.clockwise", children: { attached: [ + { id: "a", title: "A", structureClass: "org.xmind.ui.org-chart.down", children: { attached: [{ id: "a1", title: "A1", structureClass: "org.xmind.ui.org-chart.down" }] } }, + { id: "b", title: "B", structureClass: "org.xmind.ui.map.clockwise" }, + ] } } }]; + const { lost } = await importXmindReport(zip({ "content.json": JSON.stringify(sheet) })); + expect(lost).toEqual(["2 × structures set on individual topics dropped"]); + const xml = `r + ab`; + expect((await importXmindReport(zip({ "content.xml": xml }))).lost).toEqual(["structures set on individual topics dropped"]); +}); diff --git a/src/xmind.ts b/src/xmind.ts index 539fc95..fee2c93 100644 --- a/src/xmind.ts +++ b/src/xmind.ts @@ -192,7 +192,7 @@ const picturesOf = (files: Map, rep: Report): Pictures => (t }; /** Summaries and boundaries found while reading topics; both live on the root of a sheet. */ -type Acc = { sums: Summary[]; bounds: string[] }; +type Acc = { sums: Summary[]; bounds: string[]; rootClass?: string }; /** "(2,4)" -> [2, 4]: the first and last summarised child. */ const rangeOf = (r: string | undefined) => { @@ -201,6 +201,8 @@ const rangeOf = (r: string | undefined) => { }; const fromX = (t: XTopic, ids: Map, rep: Report, acc: Acc, pic: Pictures, isRoot = false): Node => { + if (isRoot) acc.rootClass = t.structureClass; + else if (t.structureClass && t.structureClass !== acc.rootClass) rep.add("structures set on individual topics dropped"); const children = (t.children?.attached ?? []).map((c) => fromX(c, ids, rep, acc, pic)); // Floating topics hang off the central topic; elsewhere XMind has none and neither do we. const floating = t.children?.detached ?? []; diff --git a/src/xmindxml.ts b/src/xmindxml.ts index 734e794..b876cc0 100644 --- a/src/xmindxml.ts +++ b/src/xmindxml.ts @@ -142,9 +142,10 @@ export function resolveTopicLinks(roots: Node[], ids: Map) { roots.forEach(fix); } -function topicFromXml(t: XNode, ids: Map, rep: Report, bounds: string[]): Node { +function topicFromXml(t: XNode, ids: Map, rep: Report, bounds: string[], rootClass?: string): Node { + if (rootClass !== undefined && t.attrs["structure-class"] && t.attrs["structure-class"] !== rootClass) rep.add("structures set on individual topics dropped"); const attached = kid(t, "children")?.children.find((c) => c.name === "topics" && (c.attrs.type ?? "attached") === "attached"); - const children = (attached?.children ?? []).filter((c) => c.name === "topic").map((c) => topicFromXml(c, ids, rep, bounds)); + const children = (attached?.children ?? []).filter((c) => c.name === "topic").map((c) => topicFromXml(c, ids, rep, bounds, rootClass ?? t.attrs["structure-class"] ?? "")); const subs = kid(t, "children")?.children.filter((c) => c.name === "topics") ?? []; rep.add("floating topics dropped", subs.filter((c) => c.attrs.type === "detached").reduce((n, c) => n + c.children.length, 0)); rep.add("summaries dropped", subs.filter((c) => c.attrs.type === "summary").reduce((n, c) => n + c.children.length, 0));