react-msaview 6.5.0 → 8.0.0
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.
- package/README.md +13 -11
- package/bundle/index.js +122 -112
- package/bundle/index.js.map +4 -4
- package/dist/colorSchemes.js +1 -2
- package/dist/colorSchemes.js.map +1 -1
- package/dist/columnStats.d.ts +28 -0
- package/dist/columnStats.js +34 -0
- package/dist/columnStats.js.map +1 -0
- package/dist/components/DragHandle.d.ts +3 -2
- package/dist/components/DragHandle.js +11 -5
- package/dist/components/DragHandle.js.map +1 -1
- package/dist/components/Loading.js +2 -2
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.js +17 -6
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +69 -4
- package/dist/components/MSAViewer.js +201 -8
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/PortalTooltip.d.ts +11 -0
- package/dist/components/PortalTooltip.js +29 -0
- package/dist/components/PortalTooltip.js.map +1 -0
- package/dist/components/ResizeHandles.d.ts +3 -3
- package/dist/components/ResizeHandles.js +13 -24
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/SequenceTextArea.js +3 -3
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/Track.js +41 -22
- package/dist/components/Track.js.map +1 -1
- package/dist/components/dialogs/{InterProScanDialog.d.ts → AnnotationFileDialog.d.ts} +2 -2
- package/dist/components/dialogs/AnnotationFileDialog.js +92 -0
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -0
- package/dist/components/dialogs/ExportSVGDialog.js +5 -3
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +13 -9
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/TrackInfoDialog.js +1 -1
- package/dist/components/dialogs/TrackInfoDialog.js.map +1 -1
- package/dist/components/header/GappynessSlider.js +6 -11
- package/dist/components/header/GappynessSlider.js.map +1 -1
- package/dist/components/header/Header.js +7 -0
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.js +0 -2
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/LoadWarnings.d.ts +6 -0
- package/dist/components/header/LoadWarnings.js +35 -0
- package/dist/components/header/LoadWarnings.js.map +1 -0
- package/dist/components/header/MultiAlignmentSelector.js +0 -0
- package/dist/components/header/MultiAlignmentSelector.js.map +1 -1
- package/dist/components/header/ScrollZoomIcons.d.ts +6 -0
- package/dist/components/header/ScrollZoomIcons.js +35 -0
- package/dist/components/header/ScrollZoomIcons.js.map +1 -0
- package/dist/components/header/TreeSettingsMenu.js +7 -1
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/UnshareableDataWarning.d.ts +6 -0
- package/dist/components/header/UnshareableDataWarning.js +40 -0
- package/dist/components/header/UnshareableDataWarning.js.map +1 -0
- package/dist/components/header/ZoomControls.js +49 -6
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/header/getAnnotationsMenu.js +11 -14
- package/dist/components/header/getAnnotationsMenu.js.map +1 -1
- package/dist/components/header/settingsMenuItems.js +10 -7
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.js +2 -6
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/import/util.js +2 -0
- package/dist/components/import/util.js.map +1 -1
- package/dist/components/minimap/Minimap.js +1 -2
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/msa/AnnotationLegend.js +27 -19
- package/dist/components/msa/AnnotationLegend.js.map +1 -1
- package/dist/components/msa/MSACanvas.js +1 -1
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +17 -20
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js +2 -1
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/domainBandCursor.d.ts +7 -11
- package/dist/components/msa/domainBandCursor.js +7 -11
- package/dist/components/msa/domainBandCursor.js.map +1 -1
- package/dist/components/msa/drawFeatureSpans.d.ts +53 -0
- package/dist/components/msa/drawFeatureSpans.js +78 -0
- package/dist/components/msa/drawFeatureSpans.js.map +1 -0
- package/dist/components/msa/legendRows.d.ts +8 -0
- package/dist/components/msa/legendRows.js +16 -0
- package/dist/components/msa/legendRows.js.map +1 -0
- package/dist/components/msa/msaRaster.d.ts +30 -27
- package/dist/components/msa/msaRaster.js +193 -90
- package/dist/components/msa/msaRaster.js.map +1 -1
- package/dist/components/msa/packDomainLanes.d.ts +20 -0
- package/dist/components/msa/packDomainLanes.js +33 -0
- package/dist/components/msa/packDomainLanes.js.map +1 -0
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +3 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +51 -87
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +44 -4
- package/dist/components/msa/renderHighlights.js +99 -11
- package/dist/components/msa/renderHighlights.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +1 -2
- package/dist/components/msa/renderMSABlock.js +28 -31
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +9 -30
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/msa/tileColor.js +4 -7
- package/dist/components/msa/tileColor.js.map +1 -1
- package/dist/components/msa/useMsaBlockMouse.d.ts +5 -3
- package/dist/components/msa/useMsaBlockMouse.js +6 -6
- package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
- package/dist/components/renderCtx.d.ts +1 -1
- package/dist/components/rowpanels/RowPanelBlock.d.ts +9 -0
- package/dist/components/rowpanels/RowPanelBlock.js +86 -0
- package/dist/components/rowpanels/RowPanelBlock.js.map +1 -0
- package/dist/components/rowpanels/RowPanelHeaders.d.ts +12 -0
- package/dist/components/rowpanels/RowPanelHeaders.js +38 -0
- package/dist/components/rowpanels/RowPanelHeaders.js.map +1 -0
- package/dist/components/{msa/ColumnStats.d.ts → rowpanels/RowPanels.d.ts} +2 -2
- package/dist/components/rowpanels/RowPanels.js +32 -0
- package/dist/components/rowpanels/RowPanels.js.map +1 -0
- package/dist/components/rowpanels/headerLayout.d.ts +1 -0
- package/dist/components/rowpanels/headerLayout.js +5 -0
- package/dist/components/rowpanels/headerLayout.js.map +1 -0
- package/dist/components/rowpanels/renderFeaturePanel.d.ts +21 -0
- package/dist/components/rowpanels/renderFeaturePanel.js +37 -0
- package/dist/components/rowpanels/renderFeaturePanel.js.map +1 -0
- package/dist/components/rowpanels/renderRowPanel.d.ts +23 -0
- package/dist/components/rowpanels/renderRowPanel.js +22 -0
- package/dist/components/rowpanels/renderRowPanel.js.map +1 -0
- package/dist/components/rowpanels/renderStrip.d.ts +20 -0
- package/dist/components/rowpanels/renderStrip.js +26 -0
- package/dist/components/rowpanels/renderStrip.js.map +1 -0
- package/dist/components/tracks/TrackBlocks.js +13 -16
- package/dist/components/tracks/TrackBlocks.js.map +1 -1
- package/dist/components/tracks/TrackTooltipContent.d.ts +15 -0
- package/dist/components/tracks/TrackTooltipContent.js +109 -0
- package/dist/components/tracks/TrackTooltipContent.js.map +1 -0
- package/dist/components/tracks/drawTracks.d.ts +30 -12
- package/dist/components/tracks/drawTracks.js +127 -34
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tracks/useTrackHover.d.ts +22 -0
- package/dist/components/tracks/useTrackHover.js +30 -0
- package/dist/components/tracks/useTrackHover.js.map +1 -0
- package/dist/components/tree/CladeLabels.d.ts +12 -0
- package/dist/components/tree/CladeLabels.js +48 -0
- package/dist/components/tree/CladeLabels.js.map +1 -0
- package/dist/components/tree/TreeCanvas.js +6 -4
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +6 -21
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeOverview.d.ts +14 -0
- package/dist/components/tree/TreeOverview.js +75 -0
- package/dist/components/tree/TreeOverview.js.map +1 -0
- package/dist/components/tree/TreeRuler.js +11 -5
- package/dist/components/tree/TreeRuler.js.map +1 -1
- package/dist/components/tree/cladeBrackets.d.ts +25 -0
- package/dist/components/tree/cladeBrackets.js +51 -0
- package/dist/components/tree/cladeBrackets.js.map +1 -0
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.js +2 -2
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +0 -1
- package/dist/components/tree/renderTreeCanvas.js +221 -47
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/tree/renderTreeOverview.d.ts +52 -0
- package/dist/components/tree/renderTreeOverview.js +138 -0
- package/dist/components/tree/renderTreeOverview.js.map +1 -0
- package/dist/components/tree/scaleBar.d.ts +10 -0
- package/dist/components/tree/scaleBar.js +24 -0
- package/dist/components/tree/scaleBar.js.map +1 -0
- package/dist/components/tree/useTreeHover.js +2 -4
- package/dist/components/tree/useTreeHover.js.map +1 -1
- package/dist/constants.d.ts +18 -1
- package/dist/constants.js +51 -8
- package/dist/constants.js.map +1 -1
- package/dist/createPaletteMap.d.ts +7 -6
- package/dist/createPaletteMap.js +10 -9
- package/dist/createPaletteMap.js.map +1 -1
- package/dist/element.d.ts +13 -0
- package/dist/element.js +269 -0
- package/dist/element.js.map +1 -0
- package/dist/featureFields.d.ts +11 -0
- package/dist/featureFields.js +17 -0
- package/dist/featureFields.js.map +1 -0
- package/dist/fetchUtils.d.ts +7 -7
- package/dist/fetchUtils.js +4 -32
- package/dist/fetchUtils.js.map +1 -1
- package/dist/flatToTree.js +1 -2
- package/dist/flatToTree.js.map +1 -1
- package/dist/ggplotPalettes.d.ts +10 -0
- package/dist/ggplotPalettes.js +58 -0
- package/dist/ggplotPalettes.js.map +1 -1
- package/dist/hierarchy.d.ts +29 -1
- package/dist/hierarchy.js +82 -19
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/model/DataModel.js +4 -4
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model/msaModel.d.ts +3 -2
- package/dist/model/msaModel.js +3 -2
- package/dist/model/msaModel.js.map +1 -1
- package/dist/model/treeModel.d.ts +30 -0
- package/dist/model/treeModel.js +37 -1
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +792 -259
- package/dist/model.js +2092 -675
- package/dist/model.js.map +1 -1
- package/dist/mount.d.ts +11 -0
- package/dist/mount.js +22 -0
- package/dist/mount.js.map +1 -0
- package/dist/neighborJoining.js +8 -32
- package/dist/neighborJoining.js.map +1 -1
- package/dist/renderToStaticMarkup.d.ts +15 -13
- package/dist/renderToStaticMarkup.js +37 -25
- package/dist/renderToStaticMarkup.js.map +1 -1
- package/dist/renderToSvg.js +198 -68
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +26 -28
- package/dist/rowCoordinateCalculations.js +13 -39
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/scales.d.ts +22 -0
- package/dist/scales.js +30 -0
- package/dist/scales.js.map +1 -0
- package/dist/seqPosToGlobalCol.d.ts +2 -3
- package/dist/seqPosToGlobalCol.js +5 -4
- package/dist/seqPosToGlobalCol.js.map +1 -1
- package/dist/sequenceLogo.d.ts +6 -11
- package/dist/sequenceLogo.js +6 -11
- package/dist/sequenceLogo.js.map +1 -1
- package/dist/stripDefault.d.ts +7 -14
- package/dist/stripDefault.js +7 -14
- package/dist/stripDefault.js.map +1 -1
- package/dist/svgTestUtil.d.ts +306 -124
- package/dist/types.d.ts +295 -3
- package/dist/umd.d.ts +2 -0
- package/dist/umd.js +4 -2
- package/dist/umd.js.map +1 -1
- package/dist/useCanvasAutorun.d.ts +5 -10
- package/dist/useCanvasAutorun.js +5 -10
- package/dist/useCanvasAutorun.js.map +1 -1
- package/dist/useMsaSvgFigure.d.ts +20 -0
- package/dist/useMsaSvgFigure.js +46 -0
- package/dist/useMsaSvgFigure.js.map +1 -0
- package/dist/util.d.ts +10 -4
- package/dist/util.js +37 -10
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wuss.d.ts +14 -0
- package/dist/wuss.js +55 -0
- package/dist/wuss.js.map +1 -0
- package/package.json +23 -14
- package/src/colorSchemes.ts +1 -2
- package/src/columnStats.ts +58 -0
- package/src/components/DragHandle.tsx +18 -7
- package/src/components/Loading.tsx +14 -8
- package/src/components/MSAView.tsx +19 -5
- package/src/components/MSAViewer.tsx +326 -10
- package/src/components/PortalTooltip.tsx +47 -0
- package/src/components/ResizeHandles.tsx +21 -36
- package/src/components/SequenceTextArea.tsx +3 -3
- package/src/components/Track.tsx +55 -18
- package/src/components/dialogs/AnnotationFileDialog.tsx +162 -0
- package/src/components/dialogs/ExportSVGDialog.tsx +7 -2
- package/src/components/dialogs/FeatureDialog.tsx +13 -9
- package/src/components/dialogs/TrackInfoDialog.tsx +1 -1
- package/src/components/header/GappynessSlider.tsx +6 -11
- package/src/components/header/Header.tsx +10 -0
- package/src/components/header/HeaderStatusArea.tsx +0 -5
- package/src/components/header/LoadWarnings.tsx +48 -0
- package/src/components/header/MultiAlignmentSelector.tsx +0 -0
- package/src/components/header/ScrollZoomIcons.tsx +52 -0
- package/src/components/header/TreeSettingsMenu.tsx +7 -1
- package/src/components/header/UnshareableDataWarning.tsx +56 -0
- package/src/components/header/ZoomControls.tsx +74 -14
- package/src/components/header/getAnnotationsMenu.ts +13 -17
- package/src/components/header/settingsMenuItems.ts +11 -6
- package/src/components/import/ImportForm.tsx +2 -2
- package/src/components/import/ImportFormExamples.tsx +4 -8
- package/src/components/import/util.ts +2 -0
- package/src/components/minimap/Minimap.tsx +1 -2
- package/src/components/msa/AnnotationLegend.tsx +48 -38
- package/src/components/msa/MSACanvas.tsx +3 -5
- package/src/components/msa/MSACanvasBlock.tsx +17 -21
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -1
- package/src/components/msa/domainBandCursor.ts +7 -11
- package/src/components/msa/drawFeatureSpans.ts +150 -0
- package/src/components/msa/legendRows.ts +24 -0
- package/src/components/msa/msaRaster.ts +236 -88
- package/src/components/msa/packDomainLanes.ts +36 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +69 -123
- package/src/components/msa/renderHighlights.ts +141 -10
- package/src/components/msa/renderMSABlock.ts +29 -38
- package/src/components/msa/renderMSAMouseover.ts +9 -39
- package/src/components/msa/tileColor.ts +4 -7
- package/src/components/msa/useMsaBlockMouse.ts +6 -6
- package/src/components/renderCtx.ts +1 -0
- package/src/components/rowpanels/RowPanelBlock.tsx +139 -0
- package/src/components/rowpanels/RowPanelHeaders.tsx +57 -0
- package/src/components/rowpanels/RowPanels.tsx +77 -0
- package/src/components/rowpanels/headerLayout.ts +5 -0
- package/src/components/rowpanels/renderFeaturePanel.ts +66 -0
- package/src/components/rowpanels/renderRowPanel.ts +41 -0
- package/src/components/rowpanels/renderStrip.ts +46 -0
- package/src/components/tracks/TrackBlocks.tsx +13 -18
- package/src/components/tracks/TrackTooltipContent.tsx +156 -0
- package/src/components/tracks/drawTracks.ts +169 -38
- package/src/components/tracks/useTrackHover.ts +42 -0
- package/src/components/tree/CladeLabels.tsx +77 -0
- package/src/components/tree/TreeCanvas.tsx +4 -3
- package/src/components/tree/TreeCanvasBlock.tsx +10 -32
- package/src/components/tree/TreeOverview.tsx +106 -0
- package/src/components/tree/TreeRuler.tsx +29 -5
- package/src/components/tree/cladeBrackets.ts +73 -0
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +2 -2
- package/src/components/tree/renderTreeCanvas.ts +312 -48
- package/src/components/tree/renderTreeOverview.ts +212 -0
- package/src/components/tree/scaleBar.ts +23 -0
- package/src/components/tree/useTreeHover.ts +2 -4
- package/src/constants.ts +61 -8
- package/src/createPaletteMap.ts +10 -9
- package/src/element.ts +321 -0
- package/src/featureFields.ts +19 -0
- package/src/fetchUtils.ts +7 -40
- package/src/flatToTree.ts +1 -2
- package/src/ggplotPalettes.ts +60 -0
- package/src/hierarchy.ts +97 -20
- package/src/index.ts +46 -6
- package/src/model/DataModel.ts +5 -4
- package/src/model/msaModel.ts +3 -2
- package/src/model/treeModel.ts +42 -0
- package/src/model.ts +2492 -793
- package/src/mount.tsx +32 -0
- package/src/neighborJoining.ts +8 -32
- package/src/rawImports.d.ts +9 -0
- package/src/renderToStaticMarkup.ts +41 -25
- package/src/renderToSvg.tsx +365 -92
- package/src/rowCoordinateCalculations.ts +16 -62
- package/src/scales.ts +47 -0
- package/src/seqPosToGlobalCol.ts +5 -4
- package/src/sequenceLogo.ts +6 -11
- package/src/stripDefault.ts +7 -14
- package/src/types.ts +352 -12
- package/src/umd.ts +4 -2
- package/src/useCanvasAutorun.ts +5 -10
- package/src/useMsaSvgFigure.ts +72 -0
- package/src/util.ts +40 -14
- package/src/version.ts +1 -1
- package/src/wuss.ts +62 -0
- package/dist/components/dialogs/InterProScanDialog.js +0 -137
- package/dist/components/dialogs/InterProScanDialog.js.map +0 -1
- package/dist/components/dialogs/InterProScanFileDialog.d.ts +0 -7
- package/dist/components/dialogs/InterProScanFileDialog.js +0 -64
- package/dist/components/dialogs/InterProScanFileDialog.js.map +0 -1
- package/dist/components/msa/ColumnStats.js +0 -42
- package/dist/components/msa/ColumnStats.js.map +0 -1
- package/dist/launchInterProScan.d.ts +0 -13
- package/dist/launchInterProScan.js +0 -110
- package/dist/launchInterProScan.js.map +0 -1
- package/dist/useColorContrast.d.ts +0 -10
- package/dist/useColorContrast.js +0 -13
- package/dist/useColorContrast.js.map +0 -1
- package/src/clustalX.test.ts +0 -74
- package/src/colSpace.test.ts +0 -67
- package/src/collapseLogic.test.ts +0 -115
- package/src/colorSchemes.docs.test.ts +0 -57
- package/src/columnCounts.test.ts +0 -73
- package/src/columnStats.test.ts +0 -94
- package/src/columnTracks.test.ts +0 -97
- package/src/components/dialogs/InterProScanDialog.tsx +0 -214
- package/src/components/dialogs/InterProScanFileDialog.tsx +0 -138
- package/src/components/minimap/minimapLayout.test.ts +0 -71
- package/src/components/msa/ColumnStats.tsx +0 -54
- package/src/components/msa/msaRaster.test.ts +0 -145
- package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +0 -51
- package/src/components/tree/renderTreeCanvas.test.ts +0 -296
- package/src/dataInitialized.test.ts +0 -42
- package/src/domainBands.test.ts +0 -122
- package/src/domainLetterColor.test.ts +0 -80
- package/src/exportFileName.test.ts +0 -40
- package/src/fetchUtils.test.ts +0 -83
- package/src/flatToTree.test.ts +0 -51
- package/src/hierarchy.test.ts +0 -228
- package/src/highlights.test.ts +0 -70
- package/src/impgRender.test.tsx +0 -68
- package/src/largeTree.test.ts +0 -67
- package/src/launchInterProScan.ts +0 -167
- package/src/loadErrorDisplay.test.tsx +0 -102
- package/src/modelFilehandleLoaders.test.ts +0 -137
- package/src/modelReset.test.ts +0 -120
- package/src/neighborJoining.test.ts +0 -164
- package/src/parseAsn1.test.ts +0 -36
- package/src/propertyConservation.test.ts +0 -36
- package/src/renderColumnTracksSvg.test.tsx +0 -108
- package/src/renderDomainsSvg.test.tsx +0 -118
- package/src/renderHighlightsSvg.test.tsx +0 -85
- package/src/renderMinimapSvg.test.tsx +0 -62
- package/src/renderRasterSvg.test.tsx +0 -144
- package/src/renderSequenceLogoSvg.test.tsx +0 -165
- package/src/renderToSvg.test.tsx +0 -65
- package/src/reset.test.ts +0 -61
- package/src/rowCoordinateCalculations.test.ts +0 -211
- package/src/rowSpace.test.ts +0 -46
- package/src/segmentOverlay.test.ts +0 -70
- package/src/seqPosToGlobalCol.test.ts +0 -59
- package/src/sequenceLogo.test.ts +0 -88
- package/src/setFontSize.test.ts +0 -33
- package/src/stripDefault.test.ts +0 -48
- package/src/stripDefaultSnapshot.test.ts +0 -87
- package/src/treeMetadata.test.ts +0 -39
- package/src/useCanvasAutorun.test.tsx +0 -98
- package/src/useColorContrast.ts +0 -18
- package/src/viewChrome.test.tsx +0 -134
- package/src/wheelZoom.test.ts +0 -46
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
//
|
|
3
|
-
// What a failed load LOOKS like, which is a different question from what the
|
|
4
|
-
// model recorded. modelFilehandleLoaders.test.ts already pins the model half --
|
|
5
|
-
// a rejected fetch sets `error` and clears `loadingMSA`, under the name "a
|
|
6
|
-
// failed fetch surfaces as an error" -- and it passed throughout the whole time
|
|
7
|
-
// a failed url showed the reader a spinner and nothing else.
|
|
8
|
-
//
|
|
9
|
-
// The error display was never missing. ImportForm renders `model.error`, and
|
|
10
|
-
// the reader could not get to it: a non-abort failure KEEPS its filehandle
|
|
11
|
-
// (only an abort clears it), so `hasPendingFilehandle` stayed true and
|
|
12
|
-
// Loading.tsx took its spinner branch ahead of the import form, permanently.
|
|
13
|
-
// Found on AlphaFold's `files/msa/` prefix answering 403 to every key in August
|
|
14
|
-
// 2026 -- the view opened, said "Downloading file" with a Cancel button, and
|
|
15
|
-
// was still saying it at 105s.
|
|
16
|
-
import React, { act } from 'react'
|
|
17
|
-
|
|
18
|
-
import { createRoot } from 'react-dom/client'
|
|
19
|
-
import { afterEach, beforeEach, expect, test } from 'vitest'
|
|
20
|
-
|
|
21
|
-
import MSAView from './components/Loading.tsx'
|
|
22
|
-
import MSAModelF from './model.ts'
|
|
23
|
-
|
|
24
|
-
import type { MsaViewModel } from './model.ts'
|
|
25
|
-
import type { Root } from 'react-dom/client'
|
|
26
|
-
|
|
27
|
-
Reflect.set(globalThis, 'IS_REACT_ACT_ENVIRONMENT', true)
|
|
28
|
-
|
|
29
|
-
let container: HTMLDivElement
|
|
30
|
-
let root: Root
|
|
31
|
-
let model: MsaViewModel
|
|
32
|
-
|
|
33
|
-
function uri(u: string) {
|
|
34
|
-
return { locationType: 'UriLocation' as const, uri: u }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function render() {
|
|
38
|
-
act(() => {
|
|
39
|
-
root.render(<MSAView model={model} />)
|
|
40
|
-
})
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
beforeEach(() => {
|
|
44
|
-
container = document.createElement('div')
|
|
45
|
-
document.body.append(container)
|
|
46
|
-
root = createRoot(container)
|
|
47
|
-
model = MSAModelF().create({ type: 'MsaView' })
|
|
48
|
-
model.setWidth(800)
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
afterEach(() => {
|
|
52
|
-
act(() => {
|
|
53
|
-
root.unmount()
|
|
54
|
-
})
|
|
55
|
-
container.remove()
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('a load that fails shows the error rather than a spinner forever', () => {
|
|
59
|
-
// the state the loader leaves behind on a 403: the filehandle it could not
|
|
60
|
-
// read is still set, nothing parsed, and the error recorded
|
|
61
|
-
model.setMSAFilehandle(uri('https://example.com/blocked.a3m'))
|
|
62
|
-
model.setLoadingMSA(false)
|
|
63
|
-
model.setError(new Error('HTTP 403 fetching blocked.a3m'))
|
|
64
|
-
render()
|
|
65
|
-
|
|
66
|
-
expect(container.textContent).toContain('403')
|
|
67
|
-
expect(container.textContent).not.toContain('Loading')
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
test('a load still in flight is a spinner, not an error', () => {
|
|
71
|
-
model.setMSAFilehandle(uri('https://example.com/slow.a3m'))
|
|
72
|
-
render()
|
|
73
|
-
|
|
74
|
-
expect(model.loadingMSA).toBe(true)
|
|
75
|
-
expect(container.textContent).not.toContain('Return to import form')
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
// A guard rather than a pin: this one passes without the fix too, because with
|
|
79
|
-
// no filehandle left set the view reaches the ImportForm and that already shows
|
|
80
|
-
// the error. It is here so the new branch cannot quietly swallow the case.
|
|
81
|
-
//
|
|
82
|
-
// It also records the surprise underneath: `dataInitialized` is itself
|
|
83
|
-
// `(msa || tree) && !error`, so ANY error hides a loaded alignment, including a
|
|
84
|
-
// tree or gff that 404s beside a good one -- setError is shared by every
|
|
85
|
-
// filehandle loader. Whether a failed OPTIONAL file should blank a good
|
|
86
|
-
// alignment is a real question and a wider one, since `dataInitialized` is read
|
|
87
|
-
// in several places; narrowing it is a design change rather than this fix.
|
|
88
|
-
test('an error over loaded data says so instead of a bare import form', () => {
|
|
89
|
-
const loaded = MSAModelF().create({
|
|
90
|
-
type: 'MsaView',
|
|
91
|
-
msaFormat: 'fasta',
|
|
92
|
-
height: 200,
|
|
93
|
-
data: { msa: '>seq1\nACDE\n>seq2\nACDF' },
|
|
94
|
-
})
|
|
95
|
-
loaded.setWidth(800)
|
|
96
|
-
loaded.setError(new Error('domains.gff 404'))
|
|
97
|
-
act(() => {
|
|
98
|
-
root.render(<MSAView model={loaded} />)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
expect(container.textContent).toContain('domains.gff 404')
|
|
102
|
-
})
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// The reactive filehandle loaders in afterCreate: each fetches when its
|
|
2
|
-
// filehandle changes, and each guards against a stale response, since a user can
|
|
3
|
-
// pick a second file while the first is still downloading.
|
|
4
|
-
import { beforeEach, expect, test, vi } from 'vitest'
|
|
5
|
-
|
|
6
|
-
import MSAModelF from './model.ts'
|
|
7
|
-
|
|
8
|
-
import type * as FetchUtils from './fetchUtils.ts'
|
|
9
|
-
|
|
10
|
-
// uri -> settle functions for the fetch that autorun kicked off
|
|
11
|
-
const inFlight = new Map<
|
|
12
|
-
string,
|
|
13
|
-
{ resolve: (text: string) => void; reject: (e: unknown) => void }
|
|
14
|
-
>()
|
|
15
|
-
|
|
16
|
-
vi.mock('@jbrowse/core/util/io', () => ({
|
|
17
|
-
openLocation: (loc: { uri: string }) => loc,
|
|
18
|
-
}))
|
|
19
|
-
|
|
20
|
-
vi.mock('./fetchUtils.ts', async importOriginal => ({
|
|
21
|
-
...(await importOriginal<typeof FetchUtils>()),
|
|
22
|
-
fetchTextWithProgress: (loc: { uri: string }) =>
|
|
23
|
-
new Promise<string>((resolve, reject) => {
|
|
24
|
-
inFlight.set(loc.uri, { resolve, reject })
|
|
25
|
-
}),
|
|
26
|
-
}))
|
|
27
|
-
|
|
28
|
-
function uri(u: string) {
|
|
29
|
-
return { locationType: 'UriLocation' as const, uri: u }
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function fasta(seq: string) {
|
|
33
|
-
return `>seq1\n${seq}`
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// let the awaited fetch and the actions that follow it run
|
|
37
|
-
function flush() {
|
|
38
|
-
return new Promise(resolve => setTimeout(resolve, 0))
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function makeModel() {
|
|
42
|
-
const model = MSAModelF().create({ type: 'MsaView' })
|
|
43
|
-
model.setWidth(800)
|
|
44
|
-
return model
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
inFlight.clear()
|
|
49
|
-
})
|
|
50
|
-
|
|
51
|
-
test('an msa filehandle loads into the model and clears its loading flag', async () => {
|
|
52
|
-
const model = makeModel()
|
|
53
|
-
model.setMSAFilehandle(uri('aln.fa'))
|
|
54
|
-
expect(model.loadingMSA).toBe(true)
|
|
55
|
-
|
|
56
|
-
inFlight.get('aln.fa')!.resolve(fasta('ACDE'))
|
|
57
|
-
await flush()
|
|
58
|
-
|
|
59
|
-
expect(model.data.msa).toBe(fasta('ACDE'))
|
|
60
|
-
expect(model.loadingMSA).toBe(false)
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
test('a slower earlier fetch never clobbers a newer one', async () => {
|
|
64
|
-
const model = makeModel()
|
|
65
|
-
model.setMSAFilehandle(uri('first.fa'))
|
|
66
|
-
model.setMSAFilehandle(uri('second.fa'))
|
|
67
|
-
|
|
68
|
-
// the newer fetch finishes first, then the abandoned one comes back
|
|
69
|
-
inFlight.get('second.fa')!.resolve(fasta('SECOND'))
|
|
70
|
-
await flush()
|
|
71
|
-
inFlight.get('first.fa')!.resolve(fasta('FIRST'))
|
|
72
|
-
await flush()
|
|
73
|
-
|
|
74
|
-
expect(model.data.msa).toBe(fasta('SECOND'))
|
|
75
|
-
expect(model.loadingMSA).toBe(false)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
test('a stale failure does not raise an error over live data', async () => {
|
|
79
|
-
const model = makeModel()
|
|
80
|
-
model.setMSAFilehandle(uri('first.fa'))
|
|
81
|
-
model.setMSAFilehandle(uri('second.fa'))
|
|
82
|
-
|
|
83
|
-
inFlight.get('second.fa')!.resolve(fasta('SECOND'))
|
|
84
|
-
await flush()
|
|
85
|
-
inFlight.get('first.fa')!.reject(new Error('too slow'))
|
|
86
|
-
await flush()
|
|
87
|
-
|
|
88
|
-
expect(model.error).toBeUndefined()
|
|
89
|
-
expect(model.data.msa).toBe(fasta('SECOND'))
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('cancelling drops the filehandle so the view returns to the import form', async () => {
|
|
93
|
-
const model = makeModel()
|
|
94
|
-
model.setMSAFilehandle(uri('aln.fa'))
|
|
95
|
-
|
|
96
|
-
inFlight.get('aln.fa')!.reject(new DOMException('Aborted', 'AbortError'))
|
|
97
|
-
await flush()
|
|
98
|
-
|
|
99
|
-
expect(model.msaFilehandle).toBeUndefined()
|
|
100
|
-
expect(model.error).toBeUndefined()
|
|
101
|
-
expect(model.loadingMSA).toBe(false)
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test('a failed fetch surfaces as an error', async () => {
|
|
105
|
-
const model = makeModel()
|
|
106
|
-
model.setMSAFilehandle(uri('aln.fa'))
|
|
107
|
-
|
|
108
|
-
inFlight.get('aln.fa')!.reject(new Error('404'))
|
|
109
|
-
await flush()
|
|
110
|
-
|
|
111
|
-
expect(model.error).toBeInstanceOf(Error)
|
|
112
|
-
expect(model.loadingMSA).toBe(false)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
test('tree, treeMetadata and gff filehandles each load into their own field', async () => {
|
|
116
|
-
const model = MSAModelF().create({
|
|
117
|
-
type: 'MsaView',
|
|
118
|
-
treeFilehandle: uri('tree.nh'),
|
|
119
|
-
treeMetadataFilehandle: uri('meta.json'),
|
|
120
|
-
gffFilehandle: uri('domains.gff'),
|
|
121
|
-
})
|
|
122
|
-
model.setWidth(800)
|
|
123
|
-
|
|
124
|
-
inFlight.get('tree.nh')!.resolve('(a,b);')
|
|
125
|
-
inFlight.get('meta.json')!.resolve('{"a":{"genome":"human"}}')
|
|
126
|
-
inFlight
|
|
127
|
-
.get('domains.gff')!
|
|
128
|
-
.resolve(
|
|
129
|
-
'##gff-version 3\na\tPfam\tprotein_match\t1\t2\t.\t.\t.\tName=PF00069',
|
|
130
|
-
)
|
|
131
|
-
await flush()
|
|
132
|
-
|
|
133
|
-
expect(model.data.tree).toBe('(a,b);')
|
|
134
|
-
expect(model.treeMetadata.a?.genome).toBe('human')
|
|
135
|
-
expect(model.actuallyShowDomains).toBe(true)
|
|
136
|
-
expect(model.loadingTree).toBe(false)
|
|
137
|
-
})
|
package/src/modelReset.test.ts
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// reset() returns the view to the import form, and the next file loads into
|
|
2
|
-
// the same model instance. It applies a default snapshot filtered to
|
|
3
|
-
// preservedOnReset, so anything file-derived that survived would be a hole in
|
|
4
|
-
// that list — the last test enumerates the snapshot keys to keep the list and
|
|
5
|
-
// the model's properties from drifting apart as properties are added. The
|
|
6
|
-
// stakes: node ids are path-derived (node-0-0-1), so a stale collapsed or
|
|
7
|
-
// showOnly id names a real node in the next tree and folds it.
|
|
8
|
-
import { getSnapshot } from '@jbrowse/mobx-state-tree'
|
|
9
|
-
import { describe, expect, test } from 'vitest'
|
|
10
|
-
|
|
11
|
-
import MSAModelF, { preservedOnReset } from './model.ts'
|
|
12
|
-
|
|
13
|
-
const firstFile = {
|
|
14
|
-
msa: '>a\nACGT\n>b\nACGT\n>c\nACGT\n>d\nACGT',
|
|
15
|
-
tree: '((a,b),(c,d));',
|
|
16
|
-
}
|
|
17
|
-
const secondFile = {
|
|
18
|
-
msa: '>e\nTTTT\n>f\nTTTT\n>g\nTTTT\n>h\nTTTT',
|
|
19
|
-
tree: '((e,f),(g,h));',
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function makeModel() {
|
|
23
|
-
const model = MSAModelF().create({ type: 'MsaView', data: firstFile })
|
|
24
|
-
model.setWidth(800)
|
|
25
|
-
return model
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function internalNodeId(model: ReturnType<typeof makeModel>) {
|
|
29
|
-
return model.leaves[0]!.parent!.data.id
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
describe('reset', () => {
|
|
33
|
-
test('a collapsed clade does not fold the next loaded tree', () => {
|
|
34
|
-
const model = makeModel()
|
|
35
|
-
model.toggleCollapsed(internalNodeId(model))
|
|
36
|
-
expect(model.leaves.length).toBe(3)
|
|
37
|
-
|
|
38
|
-
model.reset()
|
|
39
|
-
model.setData(secondFile)
|
|
40
|
-
expect(model.collapsed.length).toBe(0)
|
|
41
|
-
expect(model.leaves.map(l => l.data.name).toSorted()).toEqual([
|
|
42
|
-
'e',
|
|
43
|
-
'f',
|
|
44
|
-
'g',
|
|
45
|
-
'h',
|
|
46
|
-
])
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
test('showOnly does not restrict the next loaded tree', () => {
|
|
50
|
-
const model = makeModel()
|
|
51
|
-
model.setShowOnly(internalNodeId(model))
|
|
52
|
-
expect(model.leaves.length).toBe(2)
|
|
53
|
-
|
|
54
|
-
model.reset()
|
|
55
|
-
model.setData(secondFile)
|
|
56
|
-
expect(model.showOnly).toBe(undefined)
|
|
57
|
-
expect(model.leaves.length).toBe(4)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('clears file-derived volatiles', () => {
|
|
61
|
-
const model = makeModel()
|
|
62
|
-
model.setMousePos(2, 1)
|
|
63
|
-
model.setMouseClickPos(3, 0)
|
|
64
|
-
model.setHighlightedColumns([1, 2])
|
|
65
|
-
model.setHoveredTreeNode(internalNodeId(model))
|
|
66
|
-
|
|
67
|
-
model.reset()
|
|
68
|
-
expect(model.mouseCol).toBe(undefined)
|
|
69
|
-
expect(model.mouseClickCol).toBe(undefined)
|
|
70
|
-
expect(model.highlightedColumns).toBe(undefined)
|
|
71
|
-
expect(model.hoveredTreeNode).toBe(undefined)
|
|
72
|
-
expect(model.error).toBe(undefined)
|
|
73
|
-
expect(model.annotations).toEqual([])
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
test('display preferences survive', () => {
|
|
77
|
-
const model = makeModel()
|
|
78
|
-
model.setColorSchemeName('clustalx')
|
|
79
|
-
model.setDrawNodeBubbles(false)
|
|
80
|
-
model.toggleTrack('conservation')
|
|
81
|
-
|
|
82
|
-
model.reset()
|
|
83
|
-
expect(model.colorSchemeName).toBe('clustalx')
|
|
84
|
-
expect(model.drawNodeBubbles).toBe(false)
|
|
85
|
-
expect(model.turnedOffTracks.get('conservation')).toBe(true)
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
test('every property off preservedOnReset matches a fresh model', () => {
|
|
89
|
-
const model = makeModel()
|
|
90
|
-
model.toggleCollapsed(internalNodeId(model))
|
|
91
|
-
model.setShowOnly(internalNodeId(model))
|
|
92
|
-
model.drawRelativeTo('a')
|
|
93
|
-
model.setFilter('PF00001', true)
|
|
94
|
-
model.setScrollX(-100)
|
|
95
|
-
model.setScrollY(-50)
|
|
96
|
-
model.zoomIn()
|
|
97
|
-
model.setCurrentAlignment(1)
|
|
98
|
-
model.setMSAFilehandle({
|
|
99
|
-
uri: 'http://x/msa.fa',
|
|
100
|
-
locationType: 'UriLocation',
|
|
101
|
-
})
|
|
102
|
-
model.setTreeFilehandle({
|
|
103
|
-
uri: 'http://x/t.nh',
|
|
104
|
-
locationType: 'UriLocation',
|
|
105
|
-
})
|
|
106
|
-
model.setTreeMetadataFilehandle({
|
|
107
|
-
uri: 'http://x/m.json',
|
|
108
|
-
locationType: 'UriLocation',
|
|
109
|
-
})
|
|
110
|
-
model.setMSAFormat('fasta')
|
|
111
|
-
|
|
112
|
-
model.reset()
|
|
113
|
-
const fresh = MSAModelF().create({ type: 'MsaView' })
|
|
114
|
-
const strip = (snap: object) =>
|
|
115
|
-
Object.fromEntries(
|
|
116
|
-
Object.entries(snap).filter(([key]) => !preservedOnReset.has(key)),
|
|
117
|
-
)
|
|
118
|
-
expect(strip(getSnapshot(model))).toEqual(strip(getSnapshot(fresh)))
|
|
119
|
-
})
|
|
120
|
-
})
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { parseNewick } from 'msa-parsers'
|
|
2
|
-
import { describe, expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { calculateNeighborJoiningTree } from './neighborJoining.ts'
|
|
5
|
-
|
|
6
|
-
import type { NewickNode } from '@gmod/newick'
|
|
7
|
-
|
|
8
|
-
describe('calculateNeighborJoiningTree', () => {
|
|
9
|
-
test('generates valid Newick tree for 2 sequences', () => {
|
|
10
|
-
const rows: [string, string][] = [
|
|
11
|
-
['seq1', 'MKAA'],
|
|
12
|
-
['seq2', 'MKAA'],
|
|
13
|
-
]
|
|
14
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
15
|
-
|
|
16
|
-
expect(tree).toMatch(/;$/)
|
|
17
|
-
expect(tree).toContain('seq1')
|
|
18
|
-
expect(tree).toContain('seq2')
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
test('generates valid Newick tree for 3 sequences', () => {
|
|
22
|
-
const rows: [string, string][] = [
|
|
23
|
-
['human', 'MKAAYLSMFG'],
|
|
24
|
-
['mouse', 'MKAAYLSMFG'],
|
|
25
|
-
['chicken', 'MKAAFLSMFG'],
|
|
26
|
-
]
|
|
27
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
28
|
-
|
|
29
|
-
expect(tree).toMatch(/;$/)
|
|
30
|
-
expect(tree).toContain('human')
|
|
31
|
-
expect(tree).toContain('mouse')
|
|
32
|
-
expect(tree).toContain('chicken')
|
|
33
|
-
expect(tree).toContain('(')
|
|
34
|
-
expect(tree).toContain(')')
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
test('generates valid Newick tree for 4 sequences', () => {
|
|
38
|
-
const rows: [string, string][] = [
|
|
39
|
-
['A', 'MKAAYLSMFGKED'],
|
|
40
|
-
['B', 'MKAAYLSMFGKED'],
|
|
41
|
-
['C', 'MKAAFLSMFGKEE'],
|
|
42
|
-
['D', 'MKAAFLSMFGKEE'],
|
|
43
|
-
]
|
|
44
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
45
|
-
|
|
46
|
-
expect(tree).toMatch(/;$/)
|
|
47
|
-
expect(tree).toContain('A')
|
|
48
|
-
expect(tree).toContain('B')
|
|
49
|
-
expect(tree).toContain('C')
|
|
50
|
-
expect(tree).toContain('D')
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
test('includes branch lengths in tree', () => {
|
|
54
|
-
const rows: [string, string][] = [
|
|
55
|
-
['seq1', 'MKAAYLSMFG'],
|
|
56
|
-
['seq2', 'MKAAFLSMFG'],
|
|
57
|
-
['seq3', 'MKBBFLSMFG'],
|
|
58
|
-
]
|
|
59
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
60
|
-
|
|
61
|
-
// Branch lengths are formatted as :0.123456
|
|
62
|
-
expect(tree).toMatch(/:\d+\.\d+/)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
test('throws error for less than 2 sequences', () => {
|
|
66
|
-
const rows: [string, string][] = [['seq1', 'MKAA']]
|
|
67
|
-
expect(() => calculateNeighborJoiningTree(rows)).toThrow(
|
|
68
|
-
'Need at least 2 sequences',
|
|
69
|
-
)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
test('handles sequences with gaps', () => {
|
|
73
|
-
const rows: [string, string][] = [
|
|
74
|
-
['seq1', 'MK-AYLSMFG'],
|
|
75
|
-
['seq2', 'MKAAYLSMFG'],
|
|
76
|
-
['seq3', 'MKA-YLSMFG'],
|
|
77
|
-
]
|
|
78
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
79
|
-
|
|
80
|
-
expect(tree).toMatch(/;$/)
|
|
81
|
-
expect(tree).toContain('seq1')
|
|
82
|
-
expect(tree).toContain('seq2')
|
|
83
|
-
expect(tree).toContain('seq3')
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
test('treats a dot gap the same as a dash gap', () => {
|
|
87
|
-
// stockholm and a3m pad with '.', so the two spellings have to score alike
|
|
88
|
-
const withDashes: [string, string][] = [
|
|
89
|
-
['seq1', 'MK-AYLSMFG'],
|
|
90
|
-
['seq2', 'MKAAYLSMFG'],
|
|
91
|
-
['seq3', 'MKA-YLSMFG'],
|
|
92
|
-
]
|
|
93
|
-
const withDots = withDashes.map(
|
|
94
|
-
([name, seq]) => [name, seq.replaceAll('-', '.')] as [string, string],
|
|
95
|
-
)
|
|
96
|
-
expect(calculateNeighborJoiningTree(withDots)).toBe(
|
|
97
|
-
calculateNeighborJoiningTree(withDashes),
|
|
98
|
-
)
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
test('names with special characters round-trip through Newick parsing', () => {
|
|
102
|
-
const rows: [string, string][] = [
|
|
103
|
-
['EU105457.1|chr09:67680268..67675529_LTR/Copia', 'MKAA'],
|
|
104
|
-
['seq(2)', 'MKAA'],
|
|
105
|
-
]
|
|
106
|
-
const newick = calculateNeighborJoiningTree(rows)
|
|
107
|
-
const tree = parseNewick(newick)
|
|
108
|
-
|
|
109
|
-
function getLeafNames(node: NewickNode): (string | undefined)[] {
|
|
110
|
-
return node.children?.length
|
|
111
|
-
? node.children.flatMap(c => getLeafNames(c))
|
|
112
|
-
: [node.name]
|
|
113
|
-
}
|
|
114
|
-
const names = getLeafNames(tree)
|
|
115
|
-
expect(names).toContain('EU105457.1|chr09:67680268..67675529_LTR/Copia')
|
|
116
|
-
expect(names).toContain('seq(2)')
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
test('identical sequences have zero distance', () => {
|
|
120
|
-
const rows: [string, string][] = [
|
|
121
|
-
['seq1', 'MKAAYLSMFG'],
|
|
122
|
-
['seq2', 'MKAAYLSMFG'],
|
|
123
|
-
]
|
|
124
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
125
|
-
|
|
126
|
-
// Identical sequences should have equal branch lengths
|
|
127
|
-
const match = tree.match(/:(\d+\.\d+)/g)
|
|
128
|
-
expect(match).not.toBeNull()
|
|
129
|
-
if (match) {
|
|
130
|
-
const lengths = match.map(m => parseFloat(m.slice(1)))
|
|
131
|
-
// Branch lengths should be small or zero for identical sequences
|
|
132
|
-
for (const len of lengths) {
|
|
133
|
-
expect(len).toBeGreaterThanOrEqual(0)
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('more divergent sequences have larger distances', () => {
|
|
139
|
-
const rows: [string, string][] = [
|
|
140
|
-
['similar1', 'MKAAYLSMFGKED'],
|
|
141
|
-
['similar2', 'MKAAYLSMFGKED'],
|
|
142
|
-
['different', 'WWWWWWWWWWWWW'],
|
|
143
|
-
]
|
|
144
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
145
|
-
|
|
146
|
-
expect(tree).toMatch(/;$/)
|
|
147
|
-
// The tree should be valid even with very different sequences
|
|
148
|
-
expect(tree).toContain('similar1')
|
|
149
|
-
expect(tree).toContain('similar2')
|
|
150
|
-
expect(tree).toContain('different')
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
test('handles ragged rows, treating a short row as gapped past its end', () => {
|
|
154
|
-
const rows: [string, string][] = [
|
|
155
|
-
['full', 'MKAAYLSMFGKED'],
|
|
156
|
-
['short', 'MKAAYL'],
|
|
157
|
-
['other', 'WWWWWWWWWWWWW'],
|
|
158
|
-
]
|
|
159
|
-
const tree = calculateNeighborJoiningTree(rows)
|
|
160
|
-
|
|
161
|
-
expect(tree).toMatch(/;$/)
|
|
162
|
-
expect(tree).toContain('short')
|
|
163
|
-
})
|
|
164
|
-
})
|
package/src/parseAsn1.test.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs'
|
|
2
|
-
|
|
3
|
-
import { expect, test } from 'vitest'
|
|
4
|
-
|
|
5
|
-
import { flatToTree } from './flatToTree.ts'
|
|
6
|
-
import MSAModelF from './model.ts'
|
|
7
|
-
import { parseAsn1 } from './parseAsn1.ts'
|
|
8
|
-
|
|
9
|
-
const r = readFileSync(
|
|
10
|
-
new URL('../test/data/tree.asn', import.meta.url),
|
|
11
|
-
'utf8',
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
test('real data file', () => {
|
|
15
|
-
expect(parseAsn1(r)).toMatchSnapshot()
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
test('throws a clear error on input missing required sections', () => {
|
|
19
|
-
expect(() => parseAsn1('BioTreeContainer ::= { something {} }')).toThrow(
|
|
20
|
-
/missing/,
|
|
21
|
-
)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('the tree keeps the labels and branch lengths the file carries', () => {
|
|
25
|
-
// the parsed features have to survive into the tree the viewer draws, or a
|
|
26
|
-
// BLAST tree renders as a lengthless list of node ids
|
|
27
|
-
const model = MSAModelF().create({ type: 'MsaView', data: { tree: r } })
|
|
28
|
-
model.setWidth(1000)
|
|
29
|
-
|
|
30
|
-
expect(model.numRows).toBe(101)
|
|
31
|
-
expect(model.rowNames[0]).toBe(
|
|
32
|
-
'sodium/glucose cotransporter 4 [Gouania willdenowi]',
|
|
33
|
-
)
|
|
34
|
-
expect(model.allBranchesLength0).toBe(false)
|
|
35
|
-
expect(flatToTree(parseAsn1(r)).length).toBeUndefined()
|
|
36
|
-
})
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { columnCountsFromColumns } from './columnCounts.ts'
|
|
4
|
-
import { calculatePropertyConservation } from './propertyConservation.ts'
|
|
5
|
-
|
|
6
|
-
function propertyConservation(columns: string[]) {
|
|
7
|
-
return calculatePropertyConservation(columnCountsFromColumns(columns))
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
describe('property conservation', () => {
|
|
11
|
-
test('an invariant column scores 1', () => {
|
|
12
|
-
expect(propertyConservation(['LLLL'])[0]).toBe(1)
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
test('a column varying only within one property class stays fully conserved', () => {
|
|
16
|
-
// L/I/V/M are all hydrophobic: identity varies but the property does not
|
|
17
|
-
expect(propertyConservation(['LIVM'])[0]).toBe(1)
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
test('mixing opposite-charge classes lowers the score', () => {
|
|
21
|
-
// K/R (positive) vs D/E (negative): two equally-sized classes
|
|
22
|
-
const score = propertyConservation(['KRDE'])[0]!
|
|
23
|
-
expect(score).toBeGreaterThan(0)
|
|
24
|
-
expect(score).toBeLessThan(1)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
test('gaps reduce the score proportionally', () => {
|
|
28
|
-
const full = propertyConservation(['LLLL'])[0]!
|
|
29
|
-
const halfGapped = propertyConservation(['LL--'])[0]!
|
|
30
|
-
expect(halfGapped).toBeCloseTo(full * 0.5)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('an all-gap column scores 0', () => {
|
|
34
|
-
expect(propertyConservation(['----'])[0]).toBe(0)
|
|
35
|
-
})
|
|
36
|
-
})
|