@jbrowse/bandage-core 6.0.1 → 6.0.3

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.
Files changed (162) hide show
  1. package/README.md +23 -7
  2. package/dist/alleleProjection/projectAlleles.js +10 -0
  3. package/dist/anchoredNodes.js +24 -0
  4. package/dist/bubbleSpreads.js +11 -0
  5. package/dist/bubbles/bubbleHalos.js +11 -0
  6. package/dist/bubbles/bubbleLine.js +14 -0
  7. package/dist/bubbles/bubblesFromGraph.js +10 -0
  8. package/dist/bubbles/classifyBubble.js +15 -0
  9. package/dist/bubbles/popBubble.js +9 -0
  10. package/dist/chunks/chunk-2CVHXFK7.js +530 -0
  11. package/dist/chunks/chunk-3S3YVOJ7.js +69 -0
  12. package/dist/chunks/chunk-47DYCZOK.js +115 -0
  13. package/dist/chunks/chunk-4EMPBO7S.js +117 -0
  14. package/dist/chunks/chunk-4S47XRYA.js +149 -0
  15. package/dist/chunks/chunk-5XQDMQXU.js +431 -0
  16. package/dist/chunks/chunk-6JEWNXCQ.js +90 -0
  17. package/dist/chunks/chunk-6SBUFFTB.js +97 -0
  18. package/dist/chunks/chunk-6SXMCK6I.js +476 -0
  19. package/dist/chunks/chunk-72N5DJHZ.js +155 -0
  20. package/dist/chunks/chunk-73RSLGZT.js +73 -0
  21. package/dist/chunks/chunk-7XHHVYG7.js +13 -0
  22. package/dist/chunks/chunk-AB35TJST.js +67 -0
  23. package/dist/chunks/chunk-BPLIXMH7.js +52 -0
  24. package/dist/chunks/chunk-BUBZ32IC.js +101 -0
  25. package/dist/chunks/chunk-BXEPA4KS.js +179 -0
  26. package/dist/chunks/chunk-C44YRP5F.js +85 -0
  27. package/dist/chunks/chunk-CDLPYR5O.js +135 -0
  28. package/dist/chunks/chunk-CJ2EE4AF.js +40 -0
  29. package/dist/chunks/chunk-CPMHA4W5.js +6 -0
  30. package/dist/chunks/chunk-CR7EGAFE.js +241 -0
  31. package/dist/chunks/chunk-CS3E4ETM.js +202 -0
  32. package/dist/chunks/chunk-CTSBC2O6.js +90 -0
  33. package/dist/chunks/chunk-D3M7SBKL.js +210 -0
  34. package/dist/chunks/chunk-DKOB2OPC.js +177 -0
  35. package/dist/chunks/chunk-EJ5OZTCK.js +52 -0
  36. package/dist/chunks/chunk-EK4HGYO7.js +174 -0
  37. package/dist/chunks/chunk-EPZORFTI.js +23 -0
  38. package/dist/chunks/chunk-ES2N6V56.js +83 -0
  39. package/dist/chunks/chunk-EZPBJPK6.js +54 -0
  40. package/dist/chunks/chunk-FYQWPEEY.js +65 -0
  41. package/dist/chunks/chunk-GGQRADFS.js +170 -0
  42. package/dist/chunks/chunk-GOY6REMT.js +43 -0
  43. package/dist/chunks/chunk-GQ2AOHU4.js +112 -0
  44. package/dist/chunks/chunk-HNQPEMYE.js +297 -0
  45. package/dist/chunks/chunk-IGVV37VI.js +60 -0
  46. package/dist/chunks/chunk-IO2PCPZI.js +218 -0
  47. package/dist/chunks/chunk-ISEI2FH3.js +108 -0
  48. package/dist/chunks/chunk-JKJWSY4V.js +32 -0
  49. package/dist/chunks/chunk-KQFOCDFY.js +73 -0
  50. package/dist/chunks/chunk-L3O7AWLI.js +52 -0
  51. package/dist/chunks/chunk-LLJUG2H7.js +6 -0
  52. package/dist/chunks/chunk-LOEA5IHZ.js +71 -0
  53. package/dist/chunks/chunk-LTUWJKHD.js +112 -0
  54. package/dist/chunks/chunk-MFKORG3F.js +44 -0
  55. package/dist/chunks/chunk-MI35EUIE.js +76 -0
  56. package/dist/chunks/chunk-MNUSQCLG.js +29 -0
  57. package/dist/chunks/chunk-MQJUG2D2.js +53 -0
  58. package/dist/chunks/chunk-MREQ7GIA.js +181 -0
  59. package/dist/chunks/chunk-N62KBLFC.js +326 -0
  60. package/dist/chunks/chunk-NNODIW4U.js +26 -0
  61. package/dist/chunks/chunk-PBENCR5L.js +60 -0
  62. package/dist/chunks/chunk-PCZ4PTYC.js +726 -0
  63. package/dist/chunks/chunk-PUG7LXDF.js +70 -0
  64. package/dist/chunks/chunk-QYBZZI5H.js +0 -0
  65. package/dist/chunks/chunk-R6ZUK4Y3.js +232 -0
  66. package/dist/chunks/chunk-RAKOB6IV.js +169 -0
  67. package/dist/chunks/chunk-ROF2R3RF.js +205 -0
  68. package/dist/chunks/chunk-RVS2QCOX.js +135 -0
  69. package/dist/chunks/chunk-ST2IBUAN.js +119 -0
  70. package/dist/chunks/chunk-SZNZ2T6D.js +198 -0
  71. package/dist/chunks/chunk-T43W7NKK.js +122 -0
  72. package/dist/chunks/chunk-TAMCZHLW.js +190 -0
  73. package/dist/chunks/chunk-TDQLINVI.js +16 -0
  74. package/dist/chunks/chunk-TEDQJPMI.js +131 -0
  75. package/dist/chunks/chunk-TZFWUT2C.js +66 -0
  76. package/dist/chunks/chunk-UVBGRJQX.js +50 -0
  77. package/dist/chunks/chunk-VHW7FDHU.js +42 -0
  78. package/dist/chunks/chunk-VZQ4FKLR.js +38 -0
  79. package/dist/chunks/chunk-WFX3MAKA.js +102 -0
  80. package/dist/chunks/chunk-WOO7QYKB.js +121 -0
  81. package/dist/chunks/chunk-WSIFAZU7.js +132 -0
  82. package/dist/chunks/chunk-X5L37W4J.js +82 -0
  83. package/dist/chunks/chunk-Y3IOTZJA.js +61 -0
  84. package/dist/chunks/chunk-YMSSF2RK.js +257 -0
  85. package/dist/cli/figure.js +84 -17
  86. package/dist/colorSchemes.js +10 -0
  87. package/dist/deletionEdges.js +13 -0
  88. package/dist/el.js +8 -0
  89. package/dist/facetGrid.js +16 -0
  90. package/dist/figure.js +51 -0
  91. package/dist/gaf/parseGaf.js +12 -0
  92. package/dist/gbzCut.js +19 -0
  93. package/dist/gbzJoin.js +6 -0
  94. package/dist/gbzWindow.js +28 -0
  95. package/dist/genes/exonOutline.js +11 -0
  96. package/dist/genes/geneFiles.js +14 -0
  97. package/dist/genes/genePins.js +10 -0
  98. package/dist/gfa/gfaConverter.js +11 -0
  99. package/dist/gfa-core/gfaParser.js +8 -0
  100. package/dist/gfa-core/index.js +9 -0
  101. package/dist/graphLabels.js +24 -0
  102. package/dist/index.js +262 -1407
  103. package/dist/labelLayout.js +24 -0
  104. package/dist/layout/anchoredLayout.js +11 -0
  105. package/dist/layout/deletionRoutes.js +10 -0
  106. package/dist/layout/drawnScale.js +22 -0
  107. package/dist/layout/mergeRuns.js +15 -0
  108. package/dist/layout/orderedLayout.js +12 -0
  109. package/dist/layout/orientToReference.js +7 -0
  110. package/dist/layout/placeOffReference.js +9 -0
  111. package/dist/layout/referenceSeeds.js +11 -0
  112. package/dist/layout/rowSpacing.js +6 -0
  113. package/dist/layout/sampleRowLayout.js +11 -0
  114. package/dist/layout/trimToWindow.js +99 -0
  115. package/dist/layout/tubeMapLayout.js +28 -0
  116. package/dist/layout/walkRowDraw.js +65 -0
  117. package/dist/layout/walkRowLayout.js +13 -0
  118. package/dist/layout/walkRows.js +11 -0
  119. package/dist/layout/walkStrip.js +40 -0
  120. package/dist/layoutModes.js +35 -0
  121. package/dist/loadBandage.js +6 -0
  122. package/dist/nodeWidths.js +18 -0
  123. package/dist/overlayLabels.js +18 -0
  124. package/dist/pansn.js +18 -0
  125. package/dist/pathAnchoring.js +18 -0
  126. package/dist/pathColors.js +31 -0
  127. package/dist/pipeline.js +40 -0
  128. package/dist/reference.js +24 -0
  129. package/dist/referenceRampCss.js +29 -0
  130. package/dist/referenceSpan.js +11 -0
  131. package/dist/referenceStrip.js +35 -0
  132. package/dist/renderer/Canvas2DRenderer.js +9 -0
  133. package/dist/renderer/GeometryBuilder.js +42 -0
  134. package/dist/renderer/colorBits.js +8 -0
  135. package/dist/renderer/recordingCanvas.js +44 -0
  136. package/dist/renderer/svgCanvas.js +6 -0
  137. package/dist/renderer/types.js +0 -0
  138. package/dist/tubeMap/axis.js +25 -0
  139. package/dist/tubeMap/coarsen.js +361 -0
  140. package/dist/tubeMap/connectors.js +13 -0
  141. package/dist/tubeMap/deviations.js +85 -0
  142. package/dist/tubeMap/draw.js +15 -0
  143. package/dist/tubeMap/frame.js +9 -0
  144. package/dist/tubeMap/genes.js +20 -0
  145. package/dist/tubeMap/mismatches.js +6 -0
  146. package/dist/tubeMap/nodeColors.js +21 -0
  147. package/dist/tubeMap/reads.js +17 -0
  148. package/dist/tubeMap/warp.js +8 -0
  149. package/dist/types/version.d.ts +1 -1
  150. package/dist/types.js +0 -0
  151. package/dist/util/SpatialIndex.js +13 -0
  152. package/dist/util/edgeCurves.js +10 -0
  153. package/dist/util/geometry.js +39 -0
  154. package/dist/util/hitDetection.js +20 -0
  155. package/dist/util/wheelZoom.js +6 -0
  156. package/dist/version.js +6 -0
  157. package/dist/viewport.js +33 -0
  158. package/dist/walkEncoding.js +39 -0
  159. package/dist/walkHighlight.js +26 -0
  160. package/dist/walkKey.js +17 -0
  161. package/package.json +38 -5
  162. package/dist/chunks/chunk-EXSFRX2F.js +0 -7400
@@ -0,0 +1,69 @@
1
+ import {
2
+ el
3
+ } from "./chunk-NNODIW4U.js";
4
+
5
+ // src/genes/exonOutline.ts
6
+ var EXON_COLOR = "#daa520";
7
+ var EXON_GAP_PX = 1;
8
+ var EXON_LINE_PX = 2;
9
+ var MIN_LANE_PX = 4;
10
+ function exonStretches(pins, halfWidthPx, lift, pathOf = (d) => d) {
11
+ const inkPx = (nodeId) => {
12
+ const own = halfWidthPx(nodeId) * 2;
13
+ return lift?.nodeIds.has(nodeId) ? Math.max(own, lift.walks.length * MIN_LANE_PX) : own;
14
+ };
15
+ return pins.flatMap(
16
+ (pin) => pin.exonsByNode.map(({ nodeId, d }) => ({
17
+ key: `${pin.gene.name}-${pin.gene.start}-${nodeId}`,
18
+ d: pathOf(d),
19
+ inner: inkPx(nodeId) + 2 * EXON_GAP_PX
20
+ }))
21
+ );
22
+ }
23
+ function exonOutlineTree(stretches, o) {
24
+ if (stretches.length === 0) {
25
+ return void 0;
26
+ }
27
+ const stroke = (s, color, width) => el("path", {
28
+ d: s.d,
29
+ fill: "none",
30
+ stroke: color,
31
+ "stroke-width": width,
32
+ "stroke-linecap": "round",
33
+ "stroke-linejoin": "round",
34
+ "vector-effect": o.transform ? "non-scaling-stroke" : void 0
35
+ });
36
+ return el(
37
+ "g",
38
+ {},
39
+ el(
40
+ "mask",
41
+ {
42
+ id: o.id,
43
+ maskUnits: "userSpaceOnUse",
44
+ x: 0,
45
+ y: 0,
46
+ width: o.width,
47
+ height: o.height
48
+ },
49
+ el(
50
+ "g",
51
+ { transform: o.transform },
52
+ ...stretches.map((s) => stroke(s, "#fff", s.inner + 2 * EXON_LINE_PX)),
53
+ ...stretches.map((s) => stroke(s, "#000", s.inner))
54
+ )
55
+ ),
56
+ el("rect", {
57
+ width: o.width,
58
+ height: o.height,
59
+ fill: EXON_COLOR,
60
+ mask: `url(#${o.id})`
61
+ })
62
+ );
63
+ }
64
+
65
+ export {
66
+ EXON_COLOR,
67
+ exonStretches,
68
+ exonOutlineTree
69
+ };
@@ -0,0 +1,115 @@
1
+ // src/renderer/svgCanvas.ts
2
+ var n = (v) => +v.toFixed(1);
3
+ function paint(css) {
4
+ const m = /^rgba?\(([^,]+),([^,]+),([^,)]+)(?:,([^)]+))?\)$/.exec(
5
+ css.replaceAll(" ", "")
6
+ );
7
+ if (!m) {
8
+ return { color: css, opacity: 1 };
9
+ }
10
+ const opacity = m[4] === void 0 ? 1 : Number(m[4]);
11
+ return { color: `rgb(${m[1]},${m[2]},${m[3]})`, opacity };
12
+ }
13
+ function paintAttrs(kind, css) {
14
+ const { color, opacity } = paint(css);
15
+ return `${kind}="${color}"${opacity < 1 ? ` ${kind}-opacity="${n(opacity)}"` : ""}`;
16
+ }
17
+ var DOT_PX = 0.5;
18
+ var DOT_CELL_PX = 0.25;
19
+ function svgCanvas(width, height) {
20
+ const out = [];
21
+ let subpaths = [];
22
+ const start = (x, y) => {
23
+ const s = { d: `M${n(x)} ${n(y)}`, segments: 0, x0: x, x1: x, y0: y, y1: y };
24
+ subpaths.push(s);
25
+ return s;
26
+ };
27
+ const reach = (points) => {
28
+ const s = subpaths.at(-1) ?? start(points[0], points[1]);
29
+ for (let i = 0; i < points.length; i += 2) {
30
+ s.x0 = Math.min(s.x0, points[i]);
31
+ s.x1 = Math.max(s.x1, points[i]);
32
+ s.y0 = Math.min(s.y0, points[i + 1]);
33
+ s.y1 = Math.max(s.y1, points[i + 1]);
34
+ }
35
+ s.segments++;
36
+ return s;
37
+ };
38
+ const pathData = (dots) => {
39
+ const seen = /* @__PURE__ */ new Set();
40
+ return subpaths.map((s) => {
41
+ if (!dots || s.x1 - s.x0 >= DOT_PX || s.y1 - s.y0 >= DOT_PX) {
42
+ return s.d;
43
+ }
44
+ const x = (s.x0 + s.x1) / 2;
45
+ const y = (s.y0 + s.y1) / 2;
46
+ const cell = `${Math.round(x / DOT_CELL_PX)} ${Math.round(y / DOT_CELL_PX)}`;
47
+ if (s.segments === 0 || seen.has(cell)) {
48
+ return "";
49
+ }
50
+ seen.add(cell);
51
+ return `M${n(x)} ${n(y)}h0`;
52
+ }).join("");
53
+ };
54
+ const ctx = {
55
+ canvas: void 0,
56
+ fillStyle: "#000",
57
+ strokeStyle: "#000",
58
+ lineWidth: 1,
59
+ lineCap: "butt",
60
+ lineJoin: "miter",
61
+ beginPath() {
62
+ subpaths = [];
63
+ },
64
+ moveTo(x, y) {
65
+ start(x, y);
66
+ },
67
+ lineTo(x, y) {
68
+ reach([x, y]).d += `L${n(x)} ${n(y)}`;
69
+ },
70
+ bezierCurveTo(cx0, cy0, cx1, cy1, x, y) {
71
+ reach([cx0, cy0, cx1, cy1, x, y]).d += `C${n(cx0)} ${n(cy0)} ${n(cx1)} ${n(cy1)} ${n(x)} ${n(y)}`;
72
+ },
73
+ closePath() {
74
+ const s = subpaths.at(-1);
75
+ if (s) {
76
+ s.d += "Z";
77
+ }
78
+ },
79
+ stroke() {
80
+ const d = pathData(ctx.lineCap !== "butt");
81
+ if (d) {
82
+ out.push(
83
+ `<path d="${d}" fill="none" ${paintAttrs("stroke", ctx.strokeStyle)} stroke-width="${n(ctx.lineWidth)}" stroke-linecap="${ctx.lineCap}" stroke-linejoin="${ctx.lineJoin}"/>`
84
+ );
85
+ }
86
+ },
87
+ fill() {
88
+ const d = pathData(false);
89
+ if (d) {
90
+ out.push(`<path d="${d}" ${paintAttrs("fill", ctx.fillStyle)}/>`);
91
+ }
92
+ },
93
+ fillRect(x, y, w, h) {
94
+ out.push(
95
+ `<rect x="${n(x)}" y="${n(y)}" width="${n(w)}" height="${n(h)}" ${paintAttrs("fill", ctx.fillStyle)}/>`
96
+ );
97
+ }
98
+ };
99
+ const canvas = {
100
+ width,
101
+ height,
102
+ style: {},
103
+ getContext: () => ctx
104
+ };
105
+ ctx.canvas = canvas;
106
+ return {
107
+ canvas,
108
+ // the drawing so far, as SVG elements in canvas pixels
109
+ markup: () => out.join("")
110
+ };
111
+ }
112
+
113
+ export {
114
+ svgCanvas
115
+ };
@@ -0,0 +1,117 @@
1
+ import {
2
+ computeEdgeCurves,
3
+ edgeJoinOf,
4
+ routedEdgeCurves,
5
+ strandSides
6
+ } from "./chunk-2CVHXFK7.js";
7
+ import {
8
+ firstNodeAtOrAfter,
9
+ isBackbone
10
+ } from "./chunk-FYQWPEEY.js";
11
+
12
+ // src/deletionEdges.ts
13
+ var MIN_DELETION_BP = 1;
14
+ function bypassedPoints(nodePositions, bypassed) {
15
+ return bypassed.flatMap((id) => nodePositions[id] ?? []);
16
+ }
17
+ function deletionArcCurves(nodePositions, deletion, axis, route, stranded = false) {
18
+ const from = nodePositions[deletion.from];
19
+ const to = nodePositions[deletion.to];
20
+ if (!from?.length || !to?.length) {
21
+ return void 0;
22
+ }
23
+ return route ? routedEdgeCurves(
24
+ from,
25
+ to,
26
+ route,
27
+ stranded ? strandSides(deletion) : void 0
28
+ ) : computeEdgeCurves(
29
+ from,
30
+ to,
31
+ edgeJoinOf(deletion, stranded),
32
+ 0,
33
+ 0,
34
+ axis,
35
+ bypassedPoints(nodePositions, deletion.bypassed)
36
+ );
37
+ }
38
+ function backboneBySequence(graph) {
39
+ const bySequence = /* @__PURE__ */ new Map();
40
+ for (const node of graph.nodes) {
41
+ if (isBackbone(node)) {
42
+ const list = bySequence.get(node.stable.refName);
43
+ if (list) {
44
+ list.push(node);
45
+ } else {
46
+ bySequence.set(node.stable.refName, [node]);
47
+ }
48
+ }
49
+ }
50
+ for (const list of bySequence.values()) {
51
+ list.sort((a, b) => a.stable.start - b.stable.start);
52
+ }
53
+ return bySequence;
54
+ }
55
+ function bypassedNodes(nodes, start, end) {
56
+ const bypassed = [];
57
+ if (nodes) {
58
+ for (let i = firstNodeAtOrAfter(nodes, start); i < nodes.length; i++) {
59
+ const node = nodes[i];
60
+ if (node.stable.start >= end) {
61
+ break;
62
+ }
63
+ if (node.stable.start + node.length <= end) {
64
+ bypassed.push(node.id);
65
+ }
66
+ }
67
+ }
68
+ return bypassed;
69
+ }
70
+ function skipsBetween(edge, from, to, forwards) {
71
+ const { fromStrand, toStrand } = edge;
72
+ if (fromStrand === void 0 || toStrand === void 0) {
73
+ return true;
74
+ }
75
+ const leavesRight = fromStrand === (from.stable.strand ?? "+");
76
+ const arrivesLeft = toStrand === (to.stable.strand ?? "+");
77
+ return forwards ? leavesRight && arrivesLeft : !leavesRight && !arrivesLeft;
78
+ }
79
+ function deletionEdges(graph) {
80
+ const byId = new Map(graph.nodes.map((n) => [n.id, n]));
81
+ const backbone = backboneBySequence(graph);
82
+ const found = [];
83
+ for (let edgeIndex = 0; edgeIndex < graph.edges.length; edgeIndex++) {
84
+ const edge = graph.edges[edgeIndex];
85
+ const from = byId.get(edge.from);
86
+ const to = byId.get(edge.to);
87
+ if (from !== void 0 && to !== void 0 && isBackbone(from) && isBackbone(to) && from.stable.refName === to.stable.refName) {
88
+ const forwards = from.stable.start <= to.stable.start;
89
+ const [left, right] = forwards ? [from, to] : [to, from];
90
+ const start = left.stable.start + left.length;
91
+ const end = right.stable.start;
92
+ const bp = end - start;
93
+ if (bp >= MIN_DELETION_BP && skipsBetween(edge, from, to, forwards)) {
94
+ const refName = left.stable.refName;
95
+ found.push({
96
+ edgeIndex,
97
+ from: edge.from,
98
+ to: edge.to,
99
+ ...edge.fromStrand ? { fromStrand: edge.fromStrand } : {},
100
+ ...edge.toStrand ? { toStrand: edge.toStrand } : {},
101
+ refName,
102
+ start,
103
+ end,
104
+ bp,
105
+ bypassed: bypassedNodes(backbone.get(refName), start, end)
106
+ });
107
+ }
108
+ }
109
+ }
110
+ return found;
111
+ }
112
+
113
+ export {
114
+ bypassedPoints,
115
+ deletionArcCurves,
116
+ deletionEdges
117
+ };
@@ -0,0 +1,149 @@
1
+ import {
2
+ SATURATED_PATH_COUNT
3
+ } from "./chunk-MFKORG3F.js";
4
+ import {
5
+ referenceOrder
6
+ } from "./chunk-HNQPEMYE.js";
7
+ import {
8
+ isBackbone
9
+ } from "./chunk-FYQWPEEY.js";
10
+
11
+ // src/bubbles/bubblesFromGraph.ts
12
+ function bubblesFromGraph(graph) {
13
+ if (!graph.nodes.some(isBackbone)) {
14
+ return [];
15
+ }
16
+ const byId = new Map(graph.nodes.map((n) => [n.id, n]));
17
+ const order = referenceOrder(graph);
18
+ const indexOf = new Map(order.map((id, i) => [id, i]));
19
+ const reach = new Int32Array(order.length + 1);
20
+ const succ = /* @__PURE__ */ new Map();
21
+ const linked = /* @__PURE__ */ new Set();
22
+ for (const e of graph.edges) {
23
+ const a = indexOf.get(e.from);
24
+ const b = indexOf.get(e.to);
25
+ if (a === void 0 || b === void 0 || a === b) {
26
+ continue;
27
+ }
28
+ linked.add(`${e.from}>${e.to}`).add(`${e.to}>${e.from}`);
29
+ const [lo, hi] = a < b ? [a, b] : [b, a];
30
+ reach[lo + 1]++;
31
+ reach[hi]--;
32
+ const [from, to] = a < b ? [e.from, e.to] : [e.to, e.from];
33
+ (succ.get(from) ?? succ.set(from, /* @__PURE__ */ new Set()).get(from)).add(to);
34
+ }
35
+ for (let i = 1; i < reach.length; i++) {
36
+ reach[i] += reach[i - 1];
37
+ }
38
+ const backbone = graph.nodes.filter(isBackbone).sort((a, b) => a.stable.start - b.stable.start);
39
+ const ends = /* @__PURE__ */ new Set([backbone[0].id, backbone.at(-1).id]);
40
+ const boundaries = backbone.map((node) => [node, indexOf.get(node.id)]).filter(([node, i]) => ends.has(node.id) || reach[i] === 0).sort(([a, ia], [b, ib]) => ia - ib || a.stable.start - b.stable.start);
41
+ const walkIndex = graph.paths?.map((p) => {
42
+ const at = /* @__PURE__ */ new Map();
43
+ p.nodeIds.forEach((id, i) => {
44
+ if (!at.has(id)) {
45
+ at.set(id, i);
46
+ }
47
+ });
48
+ return at;
49
+ });
50
+ const bubbles = [];
51
+ for (let i = 0; i + 1 < boundaries.length; i++) {
52
+ const [start, i0] = boundaries[i];
53
+ const [end, i1] = boundaries[i + 1];
54
+ const interior = order.slice(i0 + 1, i1);
55
+ if (interior.length === 0) {
56
+ continue;
57
+ }
58
+ const best = /* @__PURE__ */ new Map([[start.id, { min: 0, max: 0, n: 1 }]]);
59
+ for (const id of [start.id, ...interior]) {
60
+ const cur = best.get(id);
61
+ if (!cur) {
62
+ continue;
63
+ }
64
+ for (const t of succ.get(id) ?? []) {
65
+ const ti = indexOf.get(t);
66
+ if (ti > i1) {
67
+ continue;
68
+ }
69
+ const add = t === end.id ? 0 : byId.get(t).length;
70
+ const prev = best.get(t);
71
+ best.set(t, {
72
+ min: Math.min(prev?.min ?? Infinity, cur.min + add),
73
+ max: Math.max(prev?.max ?? -Infinity, cur.max + add),
74
+ n: Math.min(SATURATED_PATH_COUNT, cur.n + (prev?.n ?? 0))
75
+ });
76
+ }
77
+ }
78
+ const walked = walkIndex && walkRoutes(graph, byId, walkIndex, start.id, end.id);
79
+ const crossed = walked?.n ? walked : void 0;
80
+ const routes = crossed ?? best.get(end.id) ?? { min: 0, max: 0, n: 0 };
81
+ const walksLeave = walked !== void 0 && walked.left > 0;
82
+ const refStart = start.stable.start + start.length;
83
+ const refEnd = end.stable.start;
84
+ const chain = [
85
+ start.id,
86
+ ...interior.filter((id) => isBackbone(byId.get(id))),
87
+ end.id
88
+ ];
89
+ const chainBroken = chain.some(
90
+ (id, k) => k > 0 && !linked.has(`${chain[k - 1]}>${id}`)
91
+ );
92
+ const partial = chainBroken || walksLeave;
93
+ const fallback = chainBroken && !crossed;
94
+ bubbles.push({
95
+ refName: start.stable.refName,
96
+ start: refStart,
97
+ end: refEnd,
98
+ segmentCount: interior.length + 2,
99
+ pathCount: routes.n,
100
+ // a real inversion test needs each walk's direction relative to the
101
+ // reference; the first visit's strand is just whichever path anchored the
102
+ // node
103
+ inversion: false,
104
+ shortestAlleleLength: fallback ? refEnd - refStart : routes.min,
105
+ longestAlleleLength: fallback ? refEnd - refStart : routes.max,
106
+ segments: [start, ...interior.map((id) => byId.get(id)), end].map((n) => n.name).join(","),
107
+ shortestAllele: void 0,
108
+ longestAllele: void 0,
109
+ partial,
110
+ routes: crossed?.routes
111
+ });
112
+ }
113
+ return bubbles;
114
+ }
115
+ function walkRoutes(graph, byId, walkIndex, startId, endId) {
116
+ const seen = /* @__PURE__ */ new Map();
117
+ let min = Infinity;
118
+ let max = -Infinity;
119
+ let left = 0;
120
+ graph.paths.forEach((p, k) => {
121
+ const i0 = walkIndex[k].get(startId);
122
+ const i1 = walkIndex[k].get(endId);
123
+ if (i0 === void 0 || i1 === void 0) {
124
+ if (i0 !== void 0 || i1 !== void 0) {
125
+ left++;
126
+ }
127
+ return;
128
+ }
129
+ const steps = p.nodeIds.slice(Math.min(i0, i1) + 1, Math.max(i0, i1));
130
+ if (i1 < i0) {
131
+ steps.reverse();
132
+ }
133
+ let bp = 0;
134
+ for (const id of steps) {
135
+ bp += byId.get(id)?.length ?? 0;
136
+ }
137
+ const key = steps.join(",");
138
+ const route = seen.get(key) ?? { steps, bp, walks: [] };
139
+ route.walks.push(p.name);
140
+ seen.set(key, route);
141
+ min = Math.min(min, bp);
142
+ max = Math.max(max, bp);
143
+ });
144
+ return seen.size || left ? { min, max, n: seen.size, left, routes: [...seen.values()] } : void 0;
145
+ }
146
+
147
+ export {
148
+ bubblesFromGraph
149
+ };