mind-elixir
Version:
Mind elixir is a free open source mind map core.
229 lines (227 loc) • 6.58 kB
JavaScript
class x {
node;
children = [];
// slots[i] represents elements that appear *before* children[i]
// slots[children.length] represents elements that appear *after* all children
slots;
constructor(e) {
this.node = e;
const s = e.children?.length ?? 0;
this.slots = Array.from({ length: s + 1 }, () => []);
}
}
function j(a) {
const { nodeData: e, arrows: s = [], summaries: n = [] } = a, o = /* @__PURE__ */ new Map();
function r(t) {
const d = new x(t);
return o.set(t.id, d), t.children && (d.children = t.children.map(r)), d;
}
const i = r(e), l = [], g = /* @__PURE__ */ new Set();
for (const t of s) {
g.add(t.from), g.add(t.to);
const d = t.metadata, u = d?.parentId, p = d?.index ?? 1 / 0;
if (!u) {
l.push(t);
continue;
}
const w = o.get(u);
if (w) {
const y = Math.min(p, w.children.length);
w.slots[y].push({ type: "arrow", arrow: t });
} else
l.push(t);
}
for (const t of n) {
const d = o.get(t.parent);
if (d) {
const u = Math.min(t.end + 1, d.children.length);
d.slots[u].push({ type: "summary", summary: t });
}
}
function h(t) {
return o.get(t)?.node.metadata?.refId ?? t;
}
const f = [];
function c(t, d) {
const u = " ".repeat(d), p = " ".repeat(d + 1), w = t.node.metadata, y = [t.node.topic], M = w?.refId ?? (g.has(t.node.id) ? t.node.id : void 0);
M && y.push(`[^${M}]`), t.node.style && Object.keys(t.node.style).length > 0 && y.push(JSON.stringify(t.node.style)), f.push(`${u}- ${y.join(" ")}`);
for (let I = 0; I <= t.children.length; I++) {
for (const C of t.slots[I])
if (C.type === "arrow") {
const m = C.arrow, $ = m.bidirectional ? `<-${m.label ?? ""}->` : `>-${m.label ?? ""}->`;
f.push(`${p}- > [^${h(m.from)}] ${$} [^${h(m.to)}]`);
} else if (C.type === "summary") {
const m = C.summary, $ = m.end - m.start + 1, b = $ === t.children.length ? "" : `:${$} `;
f.push(`${p}- }${b}${m.label}`);
}
I < t.children.length && c(t.children[I], d + 1);
}
}
c(i, 0);
for (const t of l) {
const d = t.bidirectional ? `<-${t.label ?? ""}->` : `>-${t.label ?? ""}->`;
f.push(`- > [^${h(t.from)}] ${d} [^${h(t.to)}]`);
}
return f.join(`
`) + `
`;
}
function N() {
return ((/* @__PURE__ */ new Date()).getTime().toString(16) + Math.random().toString(16).substring(2)).substring(2, 18);
}
const k = `- Root Node
- Child Node 1
- Child Node 1-1 {"color": "#e87a90", "fontSize": "18px"}
- Child Node 1-2
- Child Node 1-3
- }:2 Summary of first two nodes
- Child Node 2
- Child Node 2-1 [^node-2-1]
- Child Node 2-2 [^id2]
- Child Node 2-3
- > [^node-2-1] <-Bidirectional Link-> [^id2]
- Child Node 3
- Child Node 3-1 [^id3]
- Child Node 3-2 [^id4]
- Child Node 3-3 [^id5] {"fontFamily": "Arial", "fontWeight": "bold"}
- > [^id3] >-Unidirectional Link-> [^id4]
- Child Node 4
- Child Node 4-1 [^id6]
- Child Node 4-2 [^id7]
- Child Node 4-3 [^id8]
- } Summary of all previous nodes
- Child Node 4-4
- > [^node-2-1] <-Link position is not restricted, as long as the id can be found during rendering-> [^id8]
`;
function v(a, e = "Root") {
const s = a.split(`
`).filter((h) => h.trim());
if (s.length === 0)
throw new Error("Failed to parse plaintext: no root node found");
const n = {
arrowLines: [],
nodeIdMap: /* @__PURE__ */ new Map()
}, o = [], r = [], i = [];
for (const h of s) {
const f = S(h), c = T(h);
for (; r.length > 0 && r[r.length - 1].indent >= f; )
r.pop();
const t = r.length > 0 ? r[r.length - 1].node : null, d = t ? t.children ??= [] : i;
if (c.type === "arrow") {
n.arrowLines.push({
content: c.content,
parentId: t?.id ?? null,
index: d.length
});
continue;
}
if (c.type === "summary") {
const w = O(c.content, d, t?.id ?? "");
w && o.push(w);
continue;
}
const u = N(), p = {
topic: c.topic,
id: u
};
c.style && (p.style = c.style), c.refId && (n.nodeIdMap.set(c.refId, u), p.metadata = { refId: c.refId }), d.push(p), r.push({ indent: f, node: p });
}
if (i.length === 0)
throw new Error("Failed to parse plaintext: no root node found");
let l;
i.length === 1 ? l = i[0] : l = {
topic: e,
id: N(),
children: i
};
const g = n.arrowLines.map(({ content: h, parentId: f, index: c }) => {
const t = R(h, n);
return t && (t.metadata = { parentId: f, index: c }), t;
}).filter((h) => h !== null);
return {
nodeData: l,
arrows: g.length > 0 ? g : void 0,
summaries: o.length > 0 ? o : void 0
};
}
function S(a) {
const e = a.match(/^(\s*)/);
return e ? e[1].length : 0;
}
function L(a) {
try {
const e = a.trim().startsWith("{") ? a : `{${a}}`;
return JSON.parse(e);
} catch {
return {};
}
}
function T(a) {
const s = a.trim().replace(/^-\s*/, "");
if (s.startsWith(">"))
return {
type: "arrow",
topic: "",
content: s.substring(1).trim()
};
if (s.startsWith("}"))
return {
type: "summary",
topic: "",
content: s.substring(1).trim()
};
let n = s, o, r;
const i = n.match(/\[\^([\w-]+)\]/);
i && (o = i[1], n = n.replace(i[0], "").trim());
const l = n.match(/\{([^}]+)\}/);
return l && (r = L(l[1]), n = n.replace(l[0], "").trim()), {
type: "node",
topic: n,
content: n,
refId: o,
style: r
};
}
function R(a, e) {
const s = a.match(/\[\^([\w-]+)\]\s*<-([^-]*)->\s*\[\^([\w-]+)\]/);
if (s) {
const o = s[1], r = s[2].trim(), i = s[3];
return {
id: N(),
label: r,
from: e.nodeIdMap.get(o) || o,
to: e.nodeIdMap.get(i) || i,
bidirectional: !0
};
}
const n = a.match(/\[\^([\w-]+)\]\s*>-([^-]*)->\s*\[\^([\w-]+)\]/);
if (n) {
const o = n[1], r = n[2].trim(), i = n[3];
return {
id: N(),
label: r,
from: e.nodeIdMap.get(o) || o,
to: e.nodeIdMap.get(i) || i
};
}
return null;
}
function O(a, e, s) {
const n = a.match(/^:(\d+)\s+(.*)/);
let o, r;
if (n ? (o = parseInt(n[1], 10), r = n[2]) : (o = e.length, r = a.trim()), e.length === 0 || o === 0)
return null;
const i = e.slice(-o), l = e.indexOf(i[0]), g = e.indexOf(i[i.length - 1]);
return {
id: N(),
label: r,
parent: s,
start: l,
end: g
};
}
export {
j as mindElixirToPlaintext,
k as plaintextExample,
v as plaintextToMindElixir
};