matterviz 0.3.6 → 0.3.7
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/dist/EmptyState.svelte.d.ts +9 -0
- package/dist/FilePicker.svelte +360 -0
- package/dist/FilePicker.svelte.d.ts +17 -0
- package/dist/Icon.svelte.d.ts +13 -0
- package/dist/MillerIndexInput.svelte +66 -0
- package/dist/MillerIndexInput.svelte.d.ts +7 -0
- package/dist/api/mp.d.ts +6 -0
- package/dist/api/mp.js +22 -0
- package/dist/api/optimade.d.ts +45 -0
- package/dist/api/optimade.js +135 -0
- package/dist/brillouin/BrillouinZone.svelte +549 -0
- package/dist/brillouin/BrillouinZone.svelte.d.ts +83 -0
- package/dist/brillouin/BrillouinZoneControls.svelte +144 -0
- package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +17 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte +146 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +146 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
- package/dist/brillouin/BrillouinZoneScene.svelte +476 -0
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +48 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte +92 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +8 -0
- package/dist/brillouin/compute.d.ts +17 -0
- package/dist/brillouin/compute.js +426 -0
- package/dist/brillouin/index.d.ts +8 -0
- package/dist/brillouin/index.js +7 -0
- package/dist/brillouin/types.d.ts +43 -0
- package/dist/brillouin/types.js +1 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
- package/dist/chempot-diagram/async-compute.svelte.js +78 -0
- package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
- package/dist/chempot-diagram/chempot-worker.js +11 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +32 -0
- package/dist/chempot-diagram/compute.d.ts +48 -0
- package/dist/chempot-diagram/compute.js +806 -0
- package/dist/chempot-diagram/index.d.ts +6 -0
- package/dist/chempot-diagram/index.js +6 -0
- package/dist/chempot-diagram/pointer.d.ts +16 -0
- package/dist/chempot-diagram/pointer.js +40 -0
- package/dist/chempot-diagram/temperature.d.ts +15 -0
- package/dist/chempot-diagram/temperature.js +34 -0
- package/dist/chempot-diagram/types.d.ts +81 -0
- package/dist/chempot-diagram/types.js +28 -0
- package/dist/colors/index.d.ts +47 -0
- package/dist/colors/index.js +203 -0
- package/dist/composition/BarChart.svelte +297 -0
- package/dist/composition/BarChart.svelte.d.ts +39 -0
- package/dist/composition/BubbleChart.svelte +218 -0
- package/dist/composition/BubbleChart.svelte.d.ts +28 -0
- package/dist/composition/Composition.svelte +165 -0
- package/dist/composition/Composition.svelte.d.ts +15 -0
- package/dist/composition/Formula.svelte +268 -0
- package/dist/composition/Formula.svelte.d.ts +19 -0
- package/dist/composition/FormulaFilter.svelte +1257 -0
- package/dist/composition/FormulaFilter.svelte.d.ts +51 -0
- package/dist/composition/PieChart.svelte +323 -0
- package/dist/composition/PieChart.svelte.d.ts +37 -0
- package/dist/composition/format.d.ts +15 -0
- package/dist/composition/format.js +109 -0
- package/dist/composition/index.d.ts +20 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +56 -0
- package/dist/composition/parse.js +474 -0
- package/dist/constants.d.ts +29 -0
- package/dist/constants.js +99 -0
- package/dist/controls.d.ts +14 -0
- package/dist/controls.js +30 -0
- package/dist/convex-hull/ConvexHull.svelte +157 -0
- package/dist/convex-hull/ConvexHull.svelte.d.ts +13 -0
- package/dist/convex-hull/ConvexHull2D.svelte +825 -0
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +11 -0
- package/dist/convex-hull/ConvexHull3D.svelte +1801 -0
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +8 -0
- package/dist/convex-hull/ConvexHull4D.svelte +1398 -0
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +8 -0
- package/dist/convex-hull/ConvexHullControls.svelte +535 -0
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +48 -0
- package/dist/convex-hull/ConvexHullInfoPane.svelte +125 -0
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +20 -0
- package/dist/convex-hull/ConvexHullStats.svelte +929 -0
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +17 -0
- package/dist/convex-hull/ConvexHullTooltip.svelte +131 -0
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +33 -0
- package/dist/convex-hull/GasPressureControls.svelte +247 -0
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +11 -0
- package/dist/convex-hull/StructurePopup.svelte +151 -0
- package/dist/convex-hull/StructurePopup.svelte.d.ts +18 -0
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +8 -0
- package/dist/convex-hull/barycentric-coords.d.ts +18 -0
- package/dist/convex-hull/barycentric-coords.js +182 -0
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +40 -0
- package/dist/convex-hull/gas-thermodynamics.d.ts +16 -0
- package/dist/convex-hull/gas-thermodynamics.js +314 -0
- package/dist/convex-hull/helpers.d.ts +114 -0
- package/dist/convex-hull/helpers.js +710 -0
- package/dist/convex-hull/index.d.ts +119 -0
- package/dist/convex-hull/index.js +58 -0
- package/dist/convex-hull/thermodynamics.d.ts +67 -0
- package/dist/convex-hull/thermodynamics.js +1752 -0
- package/dist/convex-hull/types.d.ts +162 -0
- package/dist/convex-hull/types.js +36 -0
- package/dist/coordination/CoordinationBarPlot.svelte +311 -0
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +30 -0
- package/dist/coordination/calc-coordination.d.ts +15 -0
- package/dist/coordination/calc-coordination.js +63 -0
- package/dist/coordination/index.d.ts +8 -0
- package/dist/coordination/index.js +7 -0
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte.d.ts +20 -0
- package/dist/element/ElementHeading.svelte +26 -0
- package/dist/element/ElementHeading.svelte.d.ts +8 -0
- package/dist/element/ElementPhoto.svelte +57 -0
- package/dist/element/ElementPhoto.svelte.d.ts +9 -0
- package/dist/element/ElementStats.svelte +80 -0
- package/dist/element/ElementStats.svelte.d.ts +8 -0
- package/dist/element/ElementTile.svelte +484 -0
- package/dist/element/ElementTile.svelte.d.ts +29 -0
- package/dist/element/Nucleus.svelte.d.ts +17 -0
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +2 -0
- package/dist/element/index.d.ts +8 -0
- package/dist/element/index.js +7 -0
- package/dist/element/types.d.ts +57 -0
- package/dist/element/types.js +1 -0
- package/dist/feedback/ClickFeedback.svelte +58 -0
- package/dist/feedback/ClickFeedback.svelte.d.ts +12 -0
- package/dist/feedback/DragOverlay.svelte +42 -0
- package/dist/feedback/DragOverlay.svelte.d.ts +7 -0
- package/dist/feedback/Spinner.svelte.d.ts +7 -0
- package/dist/feedback/StatusMessage.svelte.d.ts +9 -0
- package/dist/feedback/index.d.ts +4 -0
- package/dist/feedback/index.js +4 -0
- package/dist/fermi-surface/FermiSlice.svelte +189 -0
- package/dist/fermi-surface/FermiSlice.svelte.d.ts +24 -0
- package/dist/fermi-surface/FermiSurface.svelte +600 -0
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +83 -0
- package/dist/fermi-surface/FermiSurfaceControls.svelte +448 -0
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +35 -0
- package/dist/fermi-surface/FermiSurfaceScene.svelte +794 -0
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +50 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +8 -0
- package/dist/fermi-surface/compute.d.ts +5 -0
- package/dist/fermi-surface/compute.js +538 -0
- package/dist/fermi-surface/constants.d.ts +9 -0
- package/dist/fermi-surface/constants.js +27 -0
- package/dist/fermi-surface/export.d.ts +5 -0
- package/dist/fermi-surface/export.js +50 -0
- package/dist/fermi-surface/index.d.ts +12 -0
- package/dist/fermi-surface/index.js +13 -0
- package/dist/fermi-surface/marching-cubes.d.ts +2 -0
- package/dist/fermi-surface/marching-cubes.js +2 -0
- package/dist/fermi-surface/parse.d.ts +2 -0
- package/dist/fermi-surface/parse.js +491 -0
- package/dist/fermi-surface/symmetry.d.ts +3 -0
- package/dist/fermi-surface/symmetry.js +46 -0
- package/dist/fermi-surface/types.d.ts +110 -0
- package/dist/fermi-surface/types.js +4 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
- package/dist/heatmap-matrix/index.d.ts +53 -0
- package/dist/heatmap-matrix/index.js +100 -0
- package/dist/heatmap-matrix/shared.d.ts +2 -0
- package/dist/heatmap-matrix/shared.js +4 -0
- package/dist/icons.d.ts +569 -0
- package/dist/icons.js +648 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +39 -0
- package/dist/io/decompress.d.ts +11 -0
- package/dist/io/decompress.js +74 -0
- package/dist/io/export.d.ts +16 -0
- package/dist/io/export.js +316 -0
- package/dist/io/fetch.d.ts +5 -0
- package/dist/io/fetch.js +39 -0
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +7 -0
- package/dist/io/index.js +6 -0
- package/dist/io/is-binary.d.ts +1 -0
- package/dist/io/is-binary.js +20 -0
- package/dist/io/types.d.ts +8 -0
- package/dist/io/types.js +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +123 -0
- package/dist/isosurface/Isosurface.svelte +285 -0
- package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
- package/dist/isosurface/IsosurfaceControls.svelte +277 -0
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
- package/dist/isosurface/index.d.ts +5 -0
- package/dist/isosurface/index.js +6 -0
- package/dist/isosurface/parse.d.ts +6 -0
- package/dist/isosurface/parse.js +553 -0
- package/dist/isosurface/slice.d.ts +11 -0
- package/dist/isosurface/slice.js +140 -0
- package/dist/isosurface/types.d.ts +56 -0
- package/dist/isosurface/types.js +227 -0
- package/dist/labels.d.ts +53 -0
- package/dist/labels.js +277 -0
- package/dist/layout/FullscreenToggle.svelte +50 -0
- package/dist/layout/FullscreenToggle.svelte.d.ts +7 -0
- package/dist/layout/InfoCard.svelte +120 -0
- package/dist/layout/InfoCard.svelte.d.ts +21 -0
- package/dist/layout/InfoTag.svelte +185 -0
- package/dist/layout/InfoTag.svelte.d.ts +19 -0
- package/dist/layout/PropertyFilter.svelte +246 -0
- package/dist/layout/PropertyFilter.svelte.d.ts +24 -0
- package/dist/layout/SettingsSection.svelte +148 -0
- package/dist/layout/SettingsSection.svelte.d.ts +17 -0
- package/dist/layout/SubpageGrid.svelte +82 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/fullscreen.d.ts +9 -0
- package/dist/layout/fullscreen.js +53 -0
- package/dist/layout/index.d.ts +10 -0
- package/dist/layout/index.js +8 -0
- package/dist/layout/json-tree/JsonNode.svelte +548 -0
- package/dist/layout/json-tree/JsonNode.svelte.d.ts +11 -0
- package/dist/layout/json-tree/JsonTree.svelte +1230 -0
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +6 -0
- package/dist/layout/json-tree/JsonValue.svelte.d.ts +9 -0
- package/dist/layout/json-tree/index.d.ts +3 -0
- package/dist/layout/json-tree/index.js +3 -0
- package/dist/layout/json-tree/types.d.ts +74 -0
- package/dist/layout/json-tree/types.js +2 -0
- package/dist/layout/json-tree/utils.d.ts +29 -0
- package/dist/layout/json-tree/utils.js +641 -0
- package/dist/marching-cubes.d.ts +14 -0
- package/dist/marching-cubes.js +540 -0
- package/dist/math.d.ts +101 -0
- package/dist/math.js +905 -0
- package/dist/overlays/ContextMenu.svelte +162 -0
- package/dist/overlays/ContextMenu.svelte.d.ts +25 -0
- package/dist/overlays/CopyButton.svelte +45 -0
- package/dist/overlays/CopyButton.svelte.d.ts +8 -0
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +487 -0
- package/dist/overlays/DraggablePane.svelte.d.ts +36 -0
- package/dist/overlays/InfoPaneCards.svelte +149 -0
- package/dist/overlays/InfoPaneCards.svelte.d.ts +22 -0
- package/dist/overlays/index.d.ts +3 -0
- package/dist/overlays/index.js +3 -0
- package/dist/periodic-table/PeriodicTable.svelte +469 -0
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +55 -0
- package/dist/periodic-table/PeriodicTableControls.svelte +557 -0
- package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +24 -0
- package/dist/periodic-table/PropertySelect.svelte +37 -0
- package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
- package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
- package/dist/periodic-table/index.d.ts +10 -0
- package/dist/periodic-table/index.js +4 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +44 -0
- package/dist/phase-diagram/PhaseDiagramControls.svelte +444 -0
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +30 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +19 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +16 -0
- package/dist/phase-diagram/TdbInfoPanel.svelte +203 -0
- package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +12 -0
- package/dist/phase-diagram/build-diagram.d.ts +11 -0
- package/dist/phase-diagram/build-diagram.js +160 -0
- package/dist/phase-diagram/colors.d.ts +35 -0
- package/dist/phase-diagram/colors.js +51 -0
- package/dist/phase-diagram/diagram-input.d.ts +29 -0
- package/dist/phase-diagram/diagram-input.js +3 -0
- package/dist/phase-diagram/index.d.ts +13 -0
- package/dist/phase-diagram/index.js +11 -0
- package/dist/phase-diagram/parse.d.ts +55 -0
- package/dist/phase-diagram/parse.js +272 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +867 -0
- package/dist/phase-diagram/types.d.ts +93 -0
- package/dist/phase-diagram/types.js +1 -0
- package/dist/phase-diagram/utils.d.ts +118 -0
- package/dist/phase-diagram/utils.js +604 -0
- package/dist/plot/AxisLabel.svelte +51 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +2113 -0
- package/dist/plot/BarPlot.svelte.d.ts +84 -0
- package/dist/plot/BarPlotControls.svelte +66 -0
- package/dist/plot/BarPlotControls.svelte.d.ts +18 -0
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +721 -0
- package/dist/plot/ColorBar.svelte.d.ts +31 -0
- package/dist/plot/ColorScaleSelect.svelte +54 -0
- package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
- package/dist/plot/ElementScatter.svelte +63 -0
- package/dist/plot/ElementScatter.svelte.d.ts +14 -0
- package/dist/plot/FillArea.svelte.d.ts +21 -0
- package/dist/plot/Histogram.svelte +1558 -0
- package/dist/plot/Histogram.svelte.d.ts +50 -0
- package/dist/plot/HistogramControls.svelte +212 -0
- package/dist/plot/HistogramControls.svelte.d.ts +22 -0
- package/dist/plot/InteractiveAxisLabel.svelte +96 -0
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +14 -0
- package/dist/plot/Line.svelte +84 -0
- package/dist/plot/Line.svelte.d.ts +15 -0
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte +537 -0
- package/dist/plot/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/PlotLegend.svelte +569 -0
- package/dist/plot/PlotLegend.svelte.d.ts +29 -0
- package/dist/plot/PlotTooltip.svelte +67 -0
- package/dist/plot/PlotTooltip.svelte.d.ts +17 -0
- package/dist/plot/PortalSelect.svelte +253 -0
- package/dist/plot/PortalSelect.svelte.d.ts +16 -0
- package/dist/plot/ReferenceLine.svelte.d.ts +20 -0
- package/dist/plot/ReferenceLine3D.svelte +156 -0
- package/dist/plot/ReferenceLine3D.svelte.d.ts +14 -0
- package/dist/plot/ReferencePlane.svelte +175 -0
- package/dist/plot/ReferencePlane.svelte.d.ts +14 -0
- package/dist/plot/ScatterPlot.svelte +2778 -0
- package/dist/plot/ScatterPlot.svelte.d.ts +96 -0
- package/dist/plot/ScatterPlot3D.svelte +529 -0
- package/dist/plot/ScatterPlot3D.svelte.d.ts +95 -0
- package/dist/plot/ScatterPlot3DControls.svelte +437 -0
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +20 -0
- package/dist/plot/ScatterPlot3DScene.svelte +912 -0
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +74 -0
- package/dist/plot/ScatterPlotControls.svelte +306 -0
- package/dist/plot/ScatterPlotControls.svelte.d.ts +17 -0
- package/dist/plot/ScatterPoint.svelte +182 -0
- package/dist/plot/ScatterPoint.svelte.d.ts +22 -0
- package/dist/plot/SpacegroupBarPlot.svelte +293 -0
- package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
- package/dist/plot/Surface3D.svelte +197 -0
- package/dist/plot/Surface3D.svelte.d.ts +13 -0
- package/dist/plot/ZeroLines.svelte +97 -0
- package/dist/plot/ZeroLines.svelte.d.ts +33 -0
- package/dist/plot/ZoomRect.svelte +23 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.d.ts +19 -0
- package/dist/plot/axis-utils.js +78 -0
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.d.ts +37 -0
- package/dist/plot/data-cleaning.js +855 -0
- package/dist/plot/data-transform.d.ts +16 -0
- package/dist/plot/data-transform.js +45 -0
- package/dist/plot/defaults.d.ts +19 -0
- package/dist/plot/defaults.js +9 -0
- package/dist/plot/fill-utils.d.ts +46 -0
- package/dist/plot/fill-utils.js +322 -0
- package/dist/plot/hover-lock.svelte.d.ts +14 -0
- package/dist/plot/hover-lock.svelte.js +46 -0
- package/dist/plot/index.d.ts +41 -0
- package/dist/plot/index.js +39 -0
- package/dist/plot/interactions.d.ts +12 -0
- package/dist/plot/interactions.js +101 -0
- package/dist/plot/layout.d.ts +78 -0
- package/dist/plot/layout.js +273 -0
- package/dist/plot/reference-line.d.ts +60 -0
- package/dist/plot/reference-line.js +314 -0
- package/dist/plot/scales.d.ts +48 -0
- package/dist/plot/scales.js +481 -0
- package/dist/plot/svg.d.ts +1 -0
- package/dist/plot/svg.js +11 -0
- package/dist/plot/types.d.ts +831 -0
- package/dist/plot/types.js +99 -0
- package/dist/plot/utils/label-placement.d.ts +68 -0
- package/dist/plot/utils/label-placement.js +326 -0
- package/dist/plot/utils/series-visibility.d.ts +15 -0
- package/dist/plot/utils/series-visibility.js +85 -0
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +247 -0
- package/dist/rdf/RdfPlot.svelte.d.ts +27 -0
- package/dist/rdf/calc-rdf.d.ts +4 -0
- package/dist/rdf/calc-rdf.js +111 -0
- package/dist/rdf/index.d.ts +23 -0
- package/dist/rdf/index.js +2 -0
- package/dist/sanitize.d.ts +6 -0
- package/dist/sanitize.js +116 -0
- package/dist/settings.d.ts +255 -0
- package/dist/settings.js +1132 -0
- package/dist/spectral/Bands.svelte +1040 -0
- package/dist/spectral/Bands.svelte.d.ts +40 -0
- package/dist/spectral/BandsAndDos.svelte +134 -0
- package/dist/spectral/BandsAndDos.svelte.d.ts +18 -0
- package/dist/spectral/BrillouinBandsDos.svelte +252 -0
- package/dist/spectral/BrillouinBandsDos.svelte.d.ts +20 -0
- package/dist/spectral/Dos.svelte +697 -0
- package/dist/spectral/Dos.svelte.d.ts +29 -0
- package/dist/spectral/helpers.d.ts +119 -0
- package/dist/spectral/helpers.js +1032 -0
- package/dist/spectral/index.d.ts +6 -0
- package/dist/spectral/index.js +6 -0
- package/dist/spectral/types.d.ts +84 -0
- package/dist/spectral/types.js +2 -0
- package/dist/state.svelte.d.ts +25 -0
- package/dist/state.svelte.js +45 -0
- package/dist/structure/Arrow.svelte +72 -0
- package/dist/structure/Arrow.svelte.d.ts +15 -0
- package/dist/structure/AtomLegend.svelte +815 -0
- package/dist/structure/AtomLegend.svelte.d.ts +35 -0
- package/dist/structure/Bond.svelte +140 -0
- package/dist/structure/Bond.svelte.d.ts +9 -0
- package/dist/structure/CanvasTooltip.svelte +33 -0
- package/dist/structure/CanvasTooltip.svelte.d.ts +12 -0
- package/dist/structure/CellSelect.svelte +349 -0
- package/dist/structure/CellSelect.svelte.d.ts +13 -0
- package/dist/structure/Cylinder.svelte +45 -0
- package/dist/structure/Cylinder.svelte.d.ts +10 -0
- package/dist/structure/Lattice.svelte +196 -0
- package/dist/structure/Lattice.svelte.d.ts +17 -0
- package/dist/structure/Structure.svelte +2248 -0
- package/dist/structure/Structure.svelte.d.ts +89 -0
- package/dist/structure/StructureControls.svelte +1273 -0
- package/dist/structure/StructureControls.svelte.d.ts +31 -0
- package/dist/structure/StructureExportPane.svelte +252 -0
- package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
- package/dist/structure/StructureInfoPane.svelte +737 -0
- package/dist/structure/StructureInfoPane.svelte.d.ts +19 -0
- package/dist/structure/StructureScene.svelte +2255 -0
- package/dist/structure/StructureScene.svelte.d.ts +111 -0
- package/dist/structure/atom-properties.d.ts +37 -0
- package/dist/structure/atom-properties.js +200 -0
- package/dist/structure/bond-order-perception.d.ts +13 -0
- package/dist/structure/bond-order-perception.js +384 -0
- package/dist/structure/bonding.d.ts +68 -0
- package/dist/structure/bonding.js +696 -0
- package/dist/structure/export.d.ts +20 -0
- package/dist/structure/export.js +727 -0
- package/dist/structure/index.d.ts +126 -0
- package/dist/structure/index.js +169 -0
- package/dist/structure/label-placement.d.ts +14 -0
- package/dist/structure/label-placement.js +72 -0
- package/dist/structure/measure.d.ts +6 -0
- package/dist/structure/measure.js +29 -0
- package/dist/structure/parse.d.ts +66 -0
- package/dist/structure/parse.js +1392 -0
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +99 -0
- package/dist/structure/pbc.d.ts +9 -0
- package/dist/structure/pbc.js +123 -0
- package/dist/structure/supercell.d.ts +8 -0
- package/dist/structure/supercell.js +170 -0
- package/dist/structure/validation.d.ts +2 -0
- package/dist/structure/validation.js +10 -0
- package/dist/symmetry/SymmetryStats.svelte +226 -0
- package/dist/symmetry/SymmetryStats.svelte.d.ts +21 -0
- package/dist/symmetry/WyckoffTable.svelte +120 -0
- package/dist/symmetry/WyckoffTable.svelte.d.ts +11 -0
- package/dist/symmetry/cell-transform.d.ts +12 -0
- package/dist/symmetry/cell-transform.js +91 -0
- package/dist/symmetry/index.d.ts +43 -0
- package/dist/symmetry/index.js +228 -0
- package/dist/symmetry/spacegroups.d.ts +9 -0
- package/dist/symmetry/spacegroups.js +394 -0
- package/dist/table/HeatmapTable.svelte +1833 -0
- package/dist/table/HeatmapTable.svelte.d.ts +49 -0
- package/dist/table/ToggleMenu.svelte +385 -0
- package/dist/table/ToggleMenu.svelte.d.ts +11 -0
- package/dist/table/index.d.ts +74 -0
- package/dist/table/index.js +38 -0
- package/dist/theme/ThemeControl.svelte +53 -0
- package/dist/theme/ThemeControl.svelte.d.ts +9 -0
- package/dist/theme/index.d.ts +29 -0
- package/dist/theme/index.js +79 -0
- package/dist/time.d.ts +4 -0
- package/dist/time.js +70 -0
- package/dist/tooltip/TooltipContent.svelte +58 -0
- package/dist/tooltip/TooltipContent.svelte.d.ts +31 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/types.d.ts +8 -0
- package/dist/tooltip/types.js +1 -0
- package/dist/trajectory/Trajectory.svelte +1545 -0
- package/dist/trajectory/Trajectory.svelte.d.ts +77 -0
- package/dist/trajectory/TrajectoryError.svelte +128 -0
- package/dist/trajectory/TrajectoryError.svelte.d.ts +13 -0
- package/dist/trajectory/TrajectoryExportPane.svelte +357 -0
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +17 -0
- package/dist/trajectory/TrajectoryInfoPane.svelte +313 -0
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +17 -0
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.d.ts +5 -0
- package/dist/trajectory/extract.js +162 -0
- package/dist/trajectory/format-detect.d.ts +9 -0
- package/dist/trajectory/format-detect.js +76 -0
- package/dist/trajectory/frame-reader.d.ts +17 -0
- package/dist/trajectory/frame-reader.js +332 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +164 -0
- package/dist/trajectory/index.d.ts +63 -0
- package/dist/trajectory/index.js +126 -0
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +73 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +127 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +298 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +179 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +68 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +110 -0
- package/dist/trajectory/plotting.d.ts +28 -0
- package/dist/trajectory/plotting.js +423 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +45 -0
- package/dist/xrd/XrdPlot.svelte +615 -0
- package/dist/xrd/XrdPlot.svelte.d.ts +28 -0
- package/dist/xrd/broadening.d.ts +20 -0
- package/dist/xrd/broadening.js +97 -0
- package/dist/xrd/calc-xrd.d.ts +37 -0
- package/dist/xrd/calc-xrd.js +336 -0
- package/dist/xrd/index.d.ts +37 -0
- package/dist/xrd/index.js +4 -0
- package/dist/xrd/parse.d.ts +13 -0
- package/dist/xrd/parse.js +749 -0
- package/license +1 -1
- package/package.json +232 -1457
- package/readme.md +98 -171
- package/.vscode/launch.json +0 -13
- package/.vscodeignore +0 -7
- package/dist/assets/STLExporter-BpTH3YHE.js +0 -8
- package/dist/assets/browser-DdDecX_W.js +0 -1
- package/dist/assets/export-qgn-H9y6.js +0 -2
- package/dist/assets/main-DiKYzti2.css +0 -1
- package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
- package/dist/extension.js +0 -31293
- package/dist/src/lib/FilePicker.svelte +0 -360
- package/dist/src/lib/MillerIndexInput.svelte +0 -66
- package/dist/src/lib/api/mp.ts +0 -26
- package/dist/src/lib/api/optimade.ts +0 -204
- package/dist/src/lib/brillouin/BrillouinZone.svelte +0 -549
- package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +0 -144
- package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +0 -146
- package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +0 -146
- package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +0 -476
- package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +0 -92
- package/dist/src/lib/brillouin/compute.ts +0 -529
- package/dist/src/lib/brillouin/index.ts +0 -8
- package/dist/src/lib/brillouin/types.ts +0 -51
- package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +0 -327
- package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +0 -846
- package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +0 -3193
- package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +0 -94
- package/dist/src/lib/chempot-diagram/chempot-worker.ts +0 -11
- package/dist/src/lib/chempot-diagram/color.ts +0 -42
- package/dist/src/lib/chempot-diagram/compute.ts +0 -1014
- package/dist/src/lib/chempot-diagram/index.ts +0 -6
- package/dist/src/lib/chempot-diagram/pointer.ts +0 -56
- package/dist/src/lib/chempot-diagram/temperature.ts +0 -77
- package/dist/src/lib/chempot-diagram/types.ts +0 -130
- package/dist/src/lib/colors/index.ts +0 -249
- package/dist/src/lib/composition/BarChart.svelte +0 -297
- package/dist/src/lib/composition/BubbleChart.svelte +0 -218
- package/dist/src/lib/composition/Composition.svelte +0 -165
- package/dist/src/lib/composition/Formula.svelte +0 -268
- package/dist/src/lib/composition/FormulaFilter.svelte +0 -1257
- package/dist/src/lib/composition/PieChart.svelte +0 -323
- package/dist/src/lib/composition/format.ts +0 -155
- package/dist/src/lib/composition/index.ts +0 -37
- package/dist/src/lib/composition/parse.ts +0 -605
- package/dist/src/lib/constants.ts +0 -134
- package/dist/src/lib/controls.ts +0 -42
- package/dist/src/lib/convex-hull/ConvexHull.svelte +0 -157
- package/dist/src/lib/convex-hull/ConvexHull2D.svelte +0 -825
- package/dist/src/lib/convex-hull/ConvexHull3D.svelte +0 -1801
- package/dist/src/lib/convex-hull/ConvexHull4D.svelte +0 -1398
- package/dist/src/lib/convex-hull/ConvexHullControls.svelte +0 -535
- package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +0 -125
- package/dist/src/lib/convex-hull/ConvexHullStats.svelte +0 -929
- package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +0 -131
- package/dist/src/lib/convex-hull/GasPressureControls.svelte +0 -247
- package/dist/src/lib/convex-hull/StructurePopup.svelte +0 -151
- package/dist/src/lib/convex-hull/barycentric-coords.ts +0 -246
- package/dist/src/lib/convex-hull/demo-temperature.ts +0 -63
- package/dist/src/lib/convex-hull/gas-thermodynamics.ts +0 -405
- package/dist/src/lib/convex-hull/helpers.ts +0 -932
- package/dist/src/lib/convex-hull/index.ts +0 -202
- package/dist/src/lib/convex-hull/thermodynamics.ts +0 -2192
- package/dist/src/lib/convex-hull/types.ts +0 -267
- package/dist/src/lib/coordination/CoordinationBarPlot.svelte +0 -311
- package/dist/src/lib/coordination/calc-coordination.ts +0 -93
- package/dist/src/lib/coordination/index.ts +0 -9
- package/dist/src/lib/effects.svelte.ts +0 -48
- package/dist/src/lib/element/ElementHeading.svelte +0 -26
- package/dist/src/lib/element/ElementPhoto.svelte +0 -57
- package/dist/src/lib/element/ElementStats.svelte +0 -80
- package/dist/src/lib/element/ElementTile.svelte +0 -484
- package/dist/src/lib/element/data.ts +0 -14
- package/dist/src/lib/element/index.ts +0 -8
- package/dist/src/lib/element/types.ts +0 -62
- package/dist/src/lib/feedback/ClickFeedback.svelte +0 -58
- package/dist/src/lib/feedback/DragOverlay.svelte +0 -42
- package/dist/src/lib/feedback/index.ts +0 -4
- package/dist/src/lib/fermi-surface/FermiSlice.svelte +0 -189
- package/dist/src/lib/fermi-surface/FermiSurface.svelte +0 -600
- package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +0 -448
- package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +0 -794
- package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
- package/dist/src/lib/fermi-surface/compute.ts +0 -728
- package/dist/src/lib/fermi-surface/constants.ts +0 -32
- package/dist/src/lib/fermi-surface/export.ts +0 -64
- package/dist/src/lib/fermi-surface/index.ts +0 -14
- package/dist/src/lib/fermi-surface/marching-cubes.ts +0 -3
- package/dist/src/lib/fermi-surface/parse.ts +0 -574
- package/dist/src/lib/fermi-surface/symmetry.ts +0 -56
- package/dist/src/lib/fermi-surface/types.ts +0 -159
- package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +0 -1545
- package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
- package/dist/src/lib/heatmap-matrix/index.ts +0 -167
- package/dist/src/lib/heatmap-matrix/shared.ts +0 -7
- package/dist/src/lib/icons.ts +0 -650
- package/dist/src/lib/index.ts +0 -61
- package/dist/src/lib/io/decompress.ts +0 -92
- package/dist/src/lib/io/export.ts +0 -385
- package/dist/src/lib/io/fetch.ts +0 -46
- package/dist/src/lib/io/file-drop.ts +0 -51
- package/dist/src/lib/io/index.ts +0 -7
- package/dist/src/lib/io/is-binary.ts +0 -24
- package/dist/src/lib/io/types.ts +0 -8
- package/dist/src/lib/io/url-drop.ts +0 -141
- package/dist/src/lib/isosurface/Isosurface.svelte +0 -285
- package/dist/src/lib/isosurface/IsosurfaceControls.svelte +0 -277
- package/dist/src/lib/isosurface/index.ts +0 -7
- package/dist/src/lib/isosurface/parse.ts +0 -656
- package/dist/src/lib/isosurface/slice.ts +0 -175
- package/dist/src/lib/isosurface/types.ts +0 -309
- package/dist/src/lib/labels.ts +0 -320
- package/dist/src/lib/layout/FullscreenToggle.svelte +0 -50
- package/dist/src/lib/layout/InfoCard.svelte +0 -120
- package/dist/src/lib/layout/InfoTag.svelte +0 -185
- package/dist/src/lib/layout/PropertyFilter.svelte +0 -246
- package/dist/src/lib/layout/SettingsSection.svelte +0 -148
- package/dist/src/lib/layout/SubpageGrid.svelte +0 -82
- package/dist/src/lib/layout/fullscreen.ts +0 -65
- package/dist/src/lib/layout/index.ts +0 -11
- package/dist/src/lib/layout/json-tree/JsonNode.svelte +0 -548
- package/dist/src/lib/layout/json-tree/JsonTree.svelte +0 -1230
- package/dist/src/lib/layout/json-tree/index.ts +0 -3
- package/dist/src/lib/layout/json-tree/types.ts +0 -126
- package/dist/src/lib/layout/json-tree/utils.ts +0 -682
- package/dist/src/lib/marching-cubes.ts +0 -614
- package/dist/src/lib/math.ts +0 -1081
- package/dist/src/lib/overlays/ContextMenu.svelte +0 -162
- package/dist/src/lib/overlays/CopyButton.svelte +0 -45
- package/dist/src/lib/overlays/DragControlTab.svelte +0 -98
- package/dist/src/lib/overlays/DraggablePane.svelte +0 -487
- package/dist/src/lib/overlays/InfoPaneCards.svelte +0 -149
- package/dist/src/lib/overlays/index.ts +0 -3
- package/dist/src/lib/periodic-table/PeriodicTable.svelte +0 -469
- package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +0 -557
- package/dist/src/lib/periodic-table/PropertySelect.svelte +0 -37
- package/dist/src/lib/periodic-table/index.ts +0 -12
- package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
- package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +0 -444
- package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
- package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +0 -184
- package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +0 -391
- package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +0 -203
- package/dist/src/lib/phase-diagram/build-diagram.ts +0 -186
- package/dist/src/lib/phase-diagram/colors.ts +0 -58
- package/dist/src/lib/phase-diagram/diagram-input.ts +0 -40
- package/dist/src/lib/phase-diagram/index.ts +0 -13
- package/dist/src/lib/phase-diagram/parse.ts +0 -348
- package/dist/src/lib/phase-diagram/svg-to-diagram.ts +0 -1023
- package/dist/src/lib/phase-diagram/types.ts +0 -144
- package/dist/src/lib/phase-diagram/utils.ts +0 -775
- package/dist/src/lib/plot/AxisLabel.svelte +0 -51
- package/dist/src/lib/plot/BarPlot.svelte +0 -2113
- package/dist/src/lib/plot/BarPlotControls.svelte +0 -66
- package/dist/src/lib/plot/BinnedScatterPlot.svelte +0 -1114
- package/dist/src/lib/plot/ColorBar.svelte +0 -721
- package/dist/src/lib/plot/ColorScaleSelect.svelte +0 -54
- package/dist/src/lib/plot/ElementScatter.svelte +0 -63
- package/dist/src/lib/plot/Histogram.svelte +0 -1558
- package/dist/src/lib/plot/HistogramControls.svelte +0 -212
- package/dist/src/lib/plot/InteractiveAxisLabel.svelte +0 -96
- package/dist/src/lib/plot/Line.svelte +0 -84
- package/dist/src/lib/plot/PlotAxis.svelte +0 -169
- package/dist/src/lib/plot/PlotControls.svelte +0 -537
- package/dist/src/lib/plot/PlotLegend.svelte +0 -569
- package/dist/src/lib/plot/PlotTooltip.svelte +0 -67
- package/dist/src/lib/plot/PortalSelect.svelte +0 -253
- package/dist/src/lib/plot/ReferenceLine3D.svelte +0 -156
- package/dist/src/lib/plot/ReferencePlane.svelte +0 -175
- package/dist/src/lib/plot/ScatterPlot.svelte +0 -2778
- package/dist/src/lib/plot/ScatterPlot3D.svelte +0 -529
- package/dist/src/lib/plot/ScatterPlot3DControls.svelte +0 -437
- package/dist/src/lib/plot/ScatterPlot3DScene.svelte +0 -912
- package/dist/src/lib/plot/ScatterPlotControls.svelte +0 -306
- package/dist/src/lib/plot/ScatterPoint.svelte +0 -182
- package/dist/src/lib/plot/SpacegroupBarPlot.svelte +0 -293
- package/dist/src/lib/plot/Surface3D.svelte +0 -197
- package/dist/src/lib/plot/ZeroLines.svelte +0 -97
- package/dist/src/lib/plot/ZoomRect.svelte +0 -23
- package/dist/src/lib/plot/adaptive-density.ts +0 -316
- package/dist/src/lib/plot/auto-place.ts +0 -184
- package/dist/src/lib/plot/axis-utils.ts +0 -122
- package/dist/src/lib/plot/binned-scatter-types.ts +0 -83
- package/dist/src/lib/plot/data-cleaning.ts +0 -1069
- package/dist/src/lib/plot/data-transform.ts +0 -69
- package/dist/src/lib/plot/defaults.ts +0 -9
- package/dist/src/lib/plot/fill-utils.ts +0 -494
- package/dist/src/lib/plot/hover-lock.svelte.ts +0 -60
- package/dist/src/lib/plot/index.ts +0 -53
- package/dist/src/lib/plot/interactions.ts +0 -119
- package/dist/src/lib/plot/layout.ts +0 -425
- package/dist/src/lib/plot/reference-line.ts +0 -426
- package/dist/src/lib/plot/scales.ts +0 -654
- package/dist/src/lib/plot/svg.ts +0 -23
- package/dist/src/lib/plot/types.ts +0 -1144
- package/dist/src/lib/plot/utils/label-placement.ts +0 -541
- package/dist/src/lib/plot/utils/series-visibility.ts +0 -140
- package/dist/src/lib/plot/utils.ts +0 -11
- package/dist/src/lib/rdf/RdfPlot.svelte +0 -247
- package/dist/src/lib/rdf/calc-rdf.ts +0 -167
- package/dist/src/lib/rdf/index.ts +0 -27
- package/dist/src/lib/sanitize.ts +0 -126
- package/dist/src/lib/settings.ts +0 -1479
- package/dist/src/lib/spectral/Bands.svelte +0 -1040
- package/dist/src/lib/spectral/BandsAndDos.svelte +0 -134
- package/dist/src/lib/spectral/BrillouinBandsDos.svelte +0 -252
- package/dist/src/lib/spectral/Dos.svelte +0 -697
- package/dist/src/lib/spectral/helpers.ts +0 -1381
- package/dist/src/lib/spectral/index.ts +0 -8
- package/dist/src/lib/spectral/types.ts +0 -112
- package/dist/src/lib/state.svelte.ts +0 -64
- package/dist/src/lib/structure/Arrow.svelte +0 -72
- package/dist/src/lib/structure/AtomLegend.svelte +0 -815
- package/dist/src/lib/structure/Bond.svelte +0 -140
- package/dist/src/lib/structure/CanvasTooltip.svelte +0 -33
- package/dist/src/lib/structure/CellSelect.svelte +0 -349
- package/dist/src/lib/structure/Cylinder.svelte +0 -45
- package/dist/src/lib/structure/Lattice.svelte +0 -196
- package/dist/src/lib/structure/Structure.svelte +0 -2248
- package/dist/src/lib/structure/StructureControls.svelte +0 -1273
- package/dist/src/lib/structure/StructureExportPane.svelte +0 -252
- package/dist/src/lib/structure/StructureInfoPane.svelte +0 -737
- package/dist/src/lib/structure/StructureScene.svelte +0 -2255
- package/dist/src/lib/structure/atom-properties.ts +0 -316
- package/dist/src/lib/structure/bond-order-perception.ts +0 -447
- package/dist/src/lib/structure/bonding.ts +0 -944
- package/dist/src/lib/structure/export.ts +0 -861
- package/dist/src/lib/structure/index.ts +0 -291
- package/dist/src/lib/structure/label-placement.ts +0 -130
- package/dist/src/lib/structure/measure.ts +0 -45
- package/dist/src/lib/structure/parse.ts +0 -1705
- package/dist/src/lib/structure/partial-occupancy.ts +0 -183
- package/dist/src/lib/structure/pbc.ts +0 -164
- package/dist/src/lib/structure/supercell.ts +0 -226
- package/dist/src/lib/structure/validation.ts +0 -11
- package/dist/src/lib/symmetry/SymmetryStats.svelte +0 -226
- package/dist/src/lib/symmetry/WyckoffTable.svelte +0 -120
- package/dist/src/lib/symmetry/cell-transform.ts +0 -118
- package/dist/src/lib/symmetry/index.ts +0 -348
- package/dist/src/lib/symmetry/spacegroups.ts +0 -404
- package/dist/src/lib/table/HeatmapTable.svelte +0 -1833
- package/dist/src/lib/table/ToggleMenu.svelte +0 -385
- package/dist/src/lib/table/index.ts +0 -139
- package/dist/src/lib/theme/ThemeControl.svelte +0 -53
- package/dist/src/lib/theme/index.ts +0 -107
- package/dist/src/lib/time.ts +0 -71
- package/dist/src/lib/tooltip/TooltipContent.svelte +0 -58
- package/dist/src/lib/tooltip/index.ts +0 -2
- package/dist/src/lib/tooltip/types.ts +0 -13
- package/dist/src/lib/trajectory/Trajectory.svelte +0 -1545
- package/dist/src/lib/trajectory/TrajectoryError.svelte +0 -128
- package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +0 -357
- package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +0 -313
- package/dist/src/lib/trajectory/constants.ts +0 -7
- package/dist/src/lib/trajectory/extract.ts +0 -196
- package/dist/src/lib/trajectory/format-detect.ts +0 -96
- package/dist/src/lib/trajectory/frame-reader.ts +0 -456
- package/dist/src/lib/trajectory/helpers.ts +0 -217
- package/dist/src/lib/trajectory/index.ts +0 -218
- package/dist/src/lib/trajectory/parse/ase.ts +0 -109
- package/dist/src/lib/trajectory/parse/hdf5.ts +0 -173
- package/dist/src/lib/trajectory/parse/index.ts +0 -411
- package/dist/src/lib/trajectory/parse/lammps.ts +0 -215
- package/dist/src/lib/trajectory/parse/vasp.ts +0 -102
- package/dist/src/lib/trajectory/parse/xyz.ts +0 -143
- package/dist/src/lib/trajectory/plotting.ts +0 -599
- package/dist/src/lib/trajectory/types.ts +0 -13
- package/dist/src/lib/utils.ts +0 -56
- package/dist/src/lib/xrd/XrdPlot.svelte +0 -615
- package/dist/src/lib/xrd/broadening.ts +0 -130
- package/dist/src/lib/xrd/calc-xrd.ts +0 -397
- package/dist/src/lib/xrd/index.ts +0 -38
- package/dist/src/lib/xrd/parse.ts +0 -858
- package/dist/webview.js +0 -29421
- package/icon.png +0 -0
- package/matterviz-0.3.2.vsix +0 -0
- package/matterviz-0.3.4.vsix +0 -0
- package/matterviz-0.3.5.vsix +0 -0
- package/scripts/sync-config.ts +0 -101
- package/src/declarations.d.ts +0 -2
- package/src/extension.ts +0 -972
- package/src/node-io.ts +0 -65
- package/src/types.ts +0 -17
- package/src/webview/JsonBrowser.svelte +0 -1079
- package/src/webview/PlotPanel.svelte +0 -346
- package/src/webview/detect.ts +0 -444
- package/src/webview/main.ts +0 -764
- package/src/webview/plot-utils.ts +0 -250
- package/test-fixtures/all-viz-types.json.gz +0 -0
- package/test-fixtures/plot-demo-data.json.gz +0 -0
- package/tests/detect.test.ts +0 -604
- package/tests/extension.test.ts +0 -2041
- package/tests/node-io.test.ts +0 -39
- package/tests/plot-utils.test.ts +0 -302
- package/tests/vite-plugin-json-gz.test.ts +0 -114
- package/tests/vscode-mock.ts +0 -18
- package/tests/webview.test.ts +0 -231
- package/tsconfig.json +0 -20
- package/vite-plugin-json-gz.ts +0 -29
- package/vite.config.ts +0 -34
- package/vite.extension.config.ts +0 -34
- /package/dist/{src/lib/EmptyState.svelte → EmptyState.svelte} +0 -0
- /package/dist/{src/lib/Icon.svelte → Icon.svelte} +0 -0
- /package/dist/{src/lib/app.css → app.css} +0 -0
- /package/dist/{src/lib/chempot-diagram → chempot-diagram}/ChemPotScene3D.svelte +0 -0
- /package/dist/{src/lib/colors → colors}/alloy-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/dark-mode-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/jmol-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/muted-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/pastel-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/vesta-colors.json +0 -0
- /package/dist/{src/lib/convex-hull → convex-hull}/TemperatureSlider.svelte +0 -0
- /package/dist/{src/lib/element → element}/BohrAtom.svelte +0 -0
- /package/dist/{src/lib/element → element}/Nucleus.svelte +0 -0
- /package/dist/{src/lib/element → element}/data.json +0 -0
- /package/dist/{src/lib/element → element}/data.json.gz +0 -0
- /package/dist/{src/lib/element → element}/data.json.gz.d.ts +0 -0
- /package/dist/{src/lib/element → element}/data.schema.json +0 -0
- /package/dist/{src/lib/element-image-urls.json → element-image-urls.json} +0 -0
- /package/dist/{src/lib/feedback → feedback}/Spinner.svelte +0 -0
- /package/dist/{src/lib/feedback → feedback}/StatusMessage.svelte +0 -0
- /package/dist/{src/lib/layout → layout}/json-tree/JsonValue.svelte +0 -0
- /package/dist/{src/lib/periodic-table → periodic-table}/TableInset.svelte +0 -0
- /package/dist/{src/lib/plot → plot}/FillArea.svelte +0 -0
- /package/dist/{src/lib/plot → plot}/ReferenceLine.svelte +0 -0
- /package/dist/{src/lib/theme → theme}/themes.mjs +0 -0
- /package/dist/{src/lib/xrd → xrd}/atomic_scattering_params.json +0 -0
package/tests/extension.test.ts
DELETED
|
@@ -1,2041 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
STRUCTURE_EXTENSIONS,
|
|
3
|
-
TRAJ_EXTENSIONS,
|
|
4
|
-
TRAJ_KEYWORDS,
|
|
5
|
-
VASP_VOLUMETRIC_REGEX,
|
|
6
|
-
} from '$lib/constants'
|
|
7
|
-
import type { ThemeName } from '$lib/theme/index'
|
|
8
|
-
import { is_trajectory_file } from '$lib/trajectory/parse'
|
|
9
|
-
import { Buffer } from 'node:buffer'
|
|
10
|
-
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
|
11
|
-
import type { ExtensionContext, Tab, TextEditor, Uri } from 'vscode'
|
|
12
|
-
import pkg_json from '../package.json' with { type: 'json' }
|
|
13
|
-
import {
|
|
14
|
-
activate,
|
|
15
|
-
create_html,
|
|
16
|
-
get_defaults,
|
|
17
|
-
get_file,
|
|
18
|
-
get_theme,
|
|
19
|
-
handle_msg,
|
|
20
|
-
MessageData,
|
|
21
|
-
read_file,
|
|
22
|
-
render,
|
|
23
|
-
should_auto_render,
|
|
24
|
-
} from '../src/extension'
|
|
25
|
-
import { VOLUMETRIC_VASP_RE } from '../src/types'
|
|
26
|
-
import type { FileData } from '../src/webview/main'
|
|
27
|
-
|
|
28
|
-
// Mock modules
|
|
29
|
-
const mock_fs = vi.hoisted(() => ({
|
|
30
|
-
readFileSync: vi.fn().mockReturnValue(`mock content`),
|
|
31
|
-
existsSync: vi.fn().mockReturnValue(true),
|
|
32
|
-
readdirSync: vi.fn().mockReturnValue([]),
|
|
33
|
-
}))
|
|
34
|
-
|
|
35
|
-
vi.mock(`node:fs`, () => mock_fs)
|
|
36
|
-
vi.mock(`node:path`, async (importOriginal) => {
|
|
37
|
-
const actual = (await importOriginal()) as Record<string, unknown>
|
|
38
|
-
return {
|
|
39
|
-
...actual,
|
|
40
|
-
basename: vi.fn((p: string) => p.split(`/`).pop() || ``),
|
|
41
|
-
dirname: vi.fn((p: string) => p.split(`/`).slice(0, -1).join(`/`) || `/`),
|
|
42
|
-
join: vi.fn((...paths: string[]) => paths.join(`/`)),
|
|
43
|
-
isAbsolute: vi.fn((p: string) => p.startsWith(`/`)),
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const msg_args = {
|
|
48
|
-
// generic placeholder arguments for all messages
|
|
49
|
-
filename: `filename`,
|
|
50
|
-
request_id: `request_id`,
|
|
51
|
-
file_path: `file_path`,
|
|
52
|
-
frame_index: 0,
|
|
53
|
-
} as const
|
|
54
|
-
|
|
55
|
-
const mock_vscode = vi.hoisted(() => ({
|
|
56
|
-
window: {
|
|
57
|
-
showInformationMessage: vi.fn(),
|
|
58
|
-
showErrorMessage: vi.fn(),
|
|
59
|
-
showTextDocument: vi.fn(),
|
|
60
|
-
showSaveDialog: vi.fn(),
|
|
61
|
-
createWebviewPanel: vi.fn(),
|
|
62
|
-
activeTextEditor: null as TextEditor | null,
|
|
63
|
-
tabGroups: { activeTabGroup: { activeTab: null as Tab | null } },
|
|
64
|
-
registerCustomEditorProvider: vi.fn(),
|
|
65
|
-
activeColorTheme: { kind: 1 }, // Light theme by default
|
|
66
|
-
onDidChangeActiveColorTheme: vi.fn(() => ({ dispose: vi.fn() })),
|
|
67
|
-
onDidChangeActiveTextEditor: vi.fn(() => ({ dispose: vi.fn() })),
|
|
68
|
-
},
|
|
69
|
-
workspace: {
|
|
70
|
-
getConfiguration: vi.fn(() => ({
|
|
71
|
-
get: vi.fn((_key: string, default_val: string) => default_val),
|
|
72
|
-
})),
|
|
73
|
-
onDidChangeConfiguration: vi.fn(() => ({ dispose: vi.fn() })),
|
|
74
|
-
openTextDocument: vi.fn(),
|
|
75
|
-
onDidOpenTextDocument: vi.fn(() => ({ dispose: vi.fn() })),
|
|
76
|
-
onDidCreateFiles: vi.fn(() => ({ dispose: vi.fn() })),
|
|
77
|
-
onDidRenameFiles: vi.fn(() => ({ dispose: vi.fn() })),
|
|
78
|
-
createFileSystemWatcher: vi.fn(() => ({
|
|
79
|
-
onDidChange: vi.fn(),
|
|
80
|
-
onDidDelete: vi.fn(),
|
|
81
|
-
dispose: vi.fn(),
|
|
82
|
-
})),
|
|
83
|
-
fs: { stat: vi.fn(), readFile: vi.fn(), writeFile: vi.fn() },
|
|
84
|
-
},
|
|
85
|
-
commands: { registerCommand: vi.fn(), executeCommand: vi.fn() },
|
|
86
|
-
Uri: {
|
|
87
|
-
file: vi.fn((p: string) => ({ fsPath: p })),
|
|
88
|
-
joinPath: vi.fn((_base: unknown, ...paths: string[]) => ({
|
|
89
|
-
fsPath: paths.join(`/`),
|
|
90
|
-
})),
|
|
91
|
-
parse: vi.fn((url: string) => ({ toString: () => url })),
|
|
92
|
-
},
|
|
93
|
-
ViewColumn: { Active: 1, Beside: 2 },
|
|
94
|
-
ColorThemeKind: { Light: 1, Dark: 2, HighContrast: 3, HighContrastLight: 4 },
|
|
95
|
-
UIKind: { Desktop: 1, Web: 2 },
|
|
96
|
-
RelativePattern: class {
|
|
97
|
-
constructor(
|
|
98
|
-
public base: unknown,
|
|
99
|
-
public pattern: string,
|
|
100
|
-
) {}
|
|
101
|
-
},
|
|
102
|
-
version: `1.99.0`,
|
|
103
|
-
env: {
|
|
104
|
-
appName: `VSCode`,
|
|
105
|
-
remoteName: undefined,
|
|
106
|
-
uiKind: 1, // Desktop
|
|
107
|
-
clipboard: {
|
|
108
|
-
writeText: vi.fn(() => Promise.resolve()),
|
|
109
|
-
readText: vi.fn(() => Promise.resolve(``)),
|
|
110
|
-
},
|
|
111
|
-
openExternal: vi.fn(() => Promise.resolve(true)),
|
|
112
|
-
},
|
|
113
|
-
}))
|
|
114
|
-
|
|
115
|
-
vi.mock(`vscode`, () => mock_vscode)
|
|
116
|
-
|
|
117
|
-
describe(`MatterViz Extension`, () => {
|
|
118
|
-
let mock_file_system_watcher: {
|
|
119
|
-
onDidChange: ReturnType<typeof vi.fn>
|
|
120
|
-
onDidDelete: ReturnType<typeof vi.fn>
|
|
121
|
-
dispose: ReturnType<typeof vi.fn>
|
|
122
|
-
}
|
|
123
|
-
const supported_volumetric_filenames: [string, string][] = [
|
|
124
|
-
[`CHGCAR`, `VASP volumetric`],
|
|
125
|
-
[`AECCAR0`, `VASP volumetric`],
|
|
126
|
-
[`AECCAR1`, `VASP volumetric`],
|
|
127
|
-
[`AECCAR2`, `VASP volumetric`],
|
|
128
|
-
[`ELFCAR`, `VASP volumetric`],
|
|
129
|
-
[`LOCPOT`, `VASP volumetric`],
|
|
130
|
-
[`PARCHG`, `VASP volumetric`],
|
|
131
|
-
[`PARCHG.gz`, `VASP volumetric`],
|
|
132
|
-
[`PARCHG.BAND_1`, `VASP volumetric`],
|
|
133
|
-
[`run_PARCHG_001`, `VASP volumetric`],
|
|
134
|
-
[`density.cube`, `Gaussian cube`],
|
|
135
|
-
[`density.cube.gz`, `Gaussian cube`],
|
|
136
|
-
]
|
|
137
|
-
const volumetric_auto_render_filenames: [string, boolean][] =
|
|
138
|
-
supported_volumetric_filenames.map(([filename]) => [filename, true] as [string, boolean])
|
|
139
|
-
|
|
140
|
-
test(`extensionKind should be configured as ["workspace"] to work locally and in remote SSH sessions`, () => {
|
|
141
|
-
// https://github.com/janosh/matterviz/issues/129#issuecomment-3193473225
|
|
142
|
-
expect(pkg_json.extensionKind).toEqual([`workspace`])
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
test(`extension volumetric regex stays in sync with app detection`, () => {
|
|
146
|
-
expect(VOLUMETRIC_VASP_RE.source).toBe(VASP_VOLUMETRIC_REGEX.source)
|
|
147
|
-
expect(VOLUMETRIC_VASP_RE.flags).toBe(VASP_VOLUMETRIC_REGEX.flags)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
describe(`Custom Editor File Patterns`, () => {
|
|
151
|
-
const custom_editors = pkg_json.contributes.customEditors
|
|
152
|
-
const matterviz_editor = custom_editors.find(
|
|
153
|
-
(editor) => editor.viewType === `matterviz.viewer`,
|
|
154
|
-
)
|
|
155
|
-
const patterns = matterviz_editor?.selector.map((sel) => sel.filenamePattern) ?? []
|
|
156
|
-
|
|
157
|
-
// Tests if a filename matches any pattern (simplified glob matching).
|
|
158
|
-
const matches_any_pattern = (filename: string): boolean => {
|
|
159
|
-
for (const pattern of patterns) {
|
|
160
|
-
// Convert glob pattern to regex
|
|
161
|
-
const regex_str = pattern
|
|
162
|
-
.replace(/\./g, `\\.`) // escape dots
|
|
163
|
-
.replace(/\*/g, `.*`) // * → .*
|
|
164
|
-
.replace(/\{([^}]+)\}/g, (_, group) => `(${group.split(`,`).join(`|`)})`) // {a,b} → (a|b)
|
|
165
|
-
const regex = new RegExp(`^${regex_str}$`, `i`)
|
|
166
|
-
if (regex.test(filename)) return true
|
|
167
|
-
}
|
|
168
|
-
return false
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
test(`should have matterviz.viewer custom editor defined`, () => {
|
|
172
|
-
expect(matterviz_editor).toBeDefined()
|
|
173
|
-
expect(matterviz_editor?.displayName).toBe(`MatterViz Viewer`)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
// Tests auto-synced with library constants to prevent regressions
|
|
177
|
-
test.each<[string, string]>([
|
|
178
|
-
// All trajectory extensions from library
|
|
179
|
-
...TRAJ_EXTENSIONS.map(
|
|
180
|
-
(ext: string) => [`test${ext}`, `TRAJ_EXT ${ext}`] as [string, string],
|
|
181
|
-
),
|
|
182
|
-
// All structure extensions from library (uncompressed, .gz, .bz2)
|
|
183
|
-
...STRUCTURE_EXTENSIONS.flatMap(
|
|
184
|
-
(ext: string) =>
|
|
185
|
-
[
|
|
186
|
-
[`test${ext}`, `STRUCT_EXT ${ext}`],
|
|
187
|
-
[`test${ext}.gz`, `${ext}.gz`],
|
|
188
|
-
] as [string, string][],
|
|
189
|
-
),
|
|
190
|
-
// All trajectory keywords in filenames
|
|
191
|
-
...TRAJ_KEYWORDS.map(
|
|
192
|
-
(kw: string) => [`${kw}_output.dat`, `TRAJ_KW ${kw}`] as [string, string],
|
|
193
|
-
),
|
|
194
|
-
// VASP special filenames + additional VS Code-only formats
|
|
195
|
-
[`POSCAR`, `VASP`],
|
|
196
|
-
[`CONTCAR`, `VASP`],
|
|
197
|
-
[`XDATCAR`, `VASP`],
|
|
198
|
-
[`OUTCAR`, `VASP`],
|
|
199
|
-
[`simulation.h5`, `HDF5`],
|
|
200
|
-
[`data.hdf5`, `HDF5`],
|
|
201
|
-
[`dynamics.dcd`, `DCD`],
|
|
202
|
-
[`run.trr`, `TRR`],
|
|
203
|
-
[`molecule.xyz`, `XYZ`],
|
|
204
|
-
[`atoms.extxyz`, `extXYZ`],
|
|
205
|
-
...supported_volumetric_filenames,
|
|
206
|
-
])(`pattern matches "%s" (%s)`, (filename) => {
|
|
207
|
-
expect(matches_any_pattern(filename)).toBe(true)
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
test.each([
|
|
211
|
-
[`myCHGCARfile`],
|
|
212
|
-
[`prefixPARCHGsuffix`],
|
|
213
|
-
[`notes_ELFCARbackup`],
|
|
214
|
-
[`report-AECCARnotes`],
|
|
215
|
-
[`density.cube.bz2`],
|
|
216
|
-
[`structure.cif.bz2`],
|
|
217
|
-
])(`pattern does not match unsupported near miss "%s"`, (filename) => {
|
|
218
|
-
expect(matches_any_pattern(filename)).toBe(false)
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
beforeEach(async () => {
|
|
223
|
-
vi.clearAllMocks()
|
|
224
|
-
|
|
225
|
-
// Import extension module and clear all watchers
|
|
226
|
-
const ext = await import(`../src/extension`)
|
|
227
|
-
ext.active_watchers.clear()
|
|
228
|
-
ext.active_frame_loaders.clear()
|
|
229
|
-
ext.auto_render_timers.clear()
|
|
230
|
-
ext.active_auto_render_panels.clear()
|
|
231
|
-
|
|
232
|
-
mock_fs.readFileSync.mockReturnValue(`mock content`)
|
|
233
|
-
mock_fs.existsSync.mockReturnValue(true)
|
|
234
|
-
mock_fs.readdirSync.mockReturnValue([])
|
|
235
|
-
mock_vscode.window.activeTextEditor = null
|
|
236
|
-
|
|
237
|
-
// Reset theme to default Light theme to avoid inter-test coupling
|
|
238
|
-
mock_vscode.window.activeColorTheme = { kind: 1 } // Light theme by default
|
|
239
|
-
|
|
240
|
-
// Set up file system watcher mock
|
|
241
|
-
mock_file_system_watcher = {
|
|
242
|
-
onDidChange: vi.fn(),
|
|
243
|
-
onDidDelete: vi.fn(),
|
|
244
|
-
dispose: vi.fn(),
|
|
245
|
-
}
|
|
246
|
-
mock_vscode.workspace.createFileSystemWatcher.mockReturnValue(mock_file_system_watcher)
|
|
247
|
-
|
|
248
|
-
// Set up default mock for vscode.workspace.fs.stat to return file stats
|
|
249
|
-
mock_vscode.workspace.fs.stat.mockResolvedValue({ size: 1000, type: 1 })
|
|
250
|
-
mock_vscode.workspace.fs.readFile.mockResolvedValue(
|
|
251
|
-
new Uint8Array(Buffer.from(`mock content`)),
|
|
252
|
-
)
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
// Test data consolidation
|
|
256
|
-
const mock_webview = {
|
|
257
|
-
cspSource: `vscode-webview:`,
|
|
258
|
-
asWebviewUri: vi.fn(
|
|
259
|
-
(uri: { fsPath: string }) =>
|
|
260
|
-
`vscode-webview://unit-test${encodeURIComponent(uri.fsPath)}`,
|
|
261
|
-
),
|
|
262
|
-
onDidReceiveMessage: vi.fn(),
|
|
263
|
-
postMessage: vi.fn(),
|
|
264
|
-
html: ``,
|
|
265
|
-
}
|
|
266
|
-
const mock_context = {
|
|
267
|
-
extensionUri: { fsPath: `/test` },
|
|
268
|
-
subscriptions: [],
|
|
269
|
-
} as unknown as ExtensionContext
|
|
270
|
-
|
|
271
|
-
test.each([
|
|
272
|
-
[`test.gz`, true],
|
|
273
|
-
[`test.h5`, true],
|
|
274
|
-
[`test.traj`, true], // ASE binary files should be treated as compressed
|
|
275
|
-
[`test.hdf5`, true],
|
|
276
|
-
[`md_npt_300K.traj`, true], // Specific ASE ULM binary file
|
|
277
|
-
[`ase-LiMnO2-chgnet-relax.traj`, true], // Another ASE ULM binary file
|
|
278
|
-
[`test.cif`, false],
|
|
279
|
-
[`test.xyz`, false], // .xyz files are text format, not compressed binary
|
|
280
|
-
[`test.json`, false],
|
|
281
|
-
[``, false],
|
|
282
|
-
])(`file reading: "%s" → compressed:%s`, async (filename, expected_compressed) => {
|
|
283
|
-
const result = await read_file(`/test/${filename}`)
|
|
284
|
-
expect(result.filename).toBe(filename)
|
|
285
|
-
expect(result.is_base64).toBe(expected_compressed)
|
|
286
|
-
// Assert payload differences instead of redundant API calls
|
|
287
|
-
if (expected_compressed) {
|
|
288
|
-
expect(result.content).toBe(Buffer.from(`mock content`).toString(`base64`))
|
|
289
|
-
} else {
|
|
290
|
-
expect(result.content).toBe(`mock content`)
|
|
291
|
-
}
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
test(`file reading: large file should return sentinel`, async () => {
|
|
295
|
-
const large_file_size = 2 * 1024 * 1024 * 1024 // 2GB, above MAX_VSCODE_FILE_SIZE (1GB)
|
|
296
|
-
const filename = `large-structure.cif`
|
|
297
|
-
const file_path = `/test/${filename}`
|
|
298
|
-
|
|
299
|
-
// Mock fs.stat to return a size above the threshold
|
|
300
|
-
mock_vscode.workspace.fs.stat.mockResolvedValue({
|
|
301
|
-
size: large_file_size,
|
|
302
|
-
type: 1,
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
const result = await read_file(file_path)
|
|
306
|
-
|
|
307
|
-
expect(result.filename).toBe(filename)
|
|
308
|
-
expect(result.content).toBe(`LARGE_FILE:${file_path}:${large_file_size}`)
|
|
309
|
-
expect(result.is_base64).toBe(false)
|
|
310
|
-
// readFile should not be called for large files
|
|
311
|
-
expect(mock_vscode.workspace.fs.readFile).not.toHaveBeenCalled()
|
|
312
|
-
})
|
|
313
|
-
|
|
314
|
-
test(`file reading: large binary file should return sentinel with base64 flag`, async () => {
|
|
315
|
-
const large_file_size = 2 * 1024 * 1024 * 1024 // 2GB, above MAX_VSCODE_FILE_SIZE (1GB)
|
|
316
|
-
const filename = `large-trajectory.traj`
|
|
317
|
-
const file_path = `/test/${filename}`
|
|
318
|
-
|
|
319
|
-
// Mock fs.stat to return a size above the threshold
|
|
320
|
-
mock_vscode.workspace.fs.stat.mockResolvedValue({
|
|
321
|
-
size: large_file_size,
|
|
322
|
-
type: 1,
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
const result = await read_file(file_path)
|
|
326
|
-
|
|
327
|
-
expect(result.filename).toBe(filename)
|
|
328
|
-
expect(result.content).toBe(`LARGE_FILE:${file_path}:${large_file_size}`)
|
|
329
|
-
expect(result.is_base64).toBe(true) // Binary files should have base64 flag
|
|
330
|
-
// readFile should not be called for large files
|
|
331
|
-
expect(mock_vscode.workspace.fs.readFile).not.toHaveBeenCalled()
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
test.each([
|
|
335
|
-
[`md_npt_300K.traj`, true, true], // ASE binary trajectory
|
|
336
|
-
[`ase-LiMnO2-chgnet-relax.traj`, true, true], // ASE binary trajectory
|
|
337
|
-
[`simulation_nvt_250K.traj`, true, true], // ASE binary trajectory
|
|
338
|
-
[`water_cluster_md.traj`, true, true], // ASE binary trajectory
|
|
339
|
-
[`optimization_relax.traj`, true, true], // ASE binary trajectory
|
|
340
|
-
[`regular_text.traj`, true, true], // .traj files are always binary
|
|
341
|
-
// filename-only based .xyz/.extxyz detection always assumes structure, requires file content to look for frames and recognize as trajectory
|
|
342
|
-
[`test.xyz`, false, false],
|
|
343
|
-
[`test.extxyz`, false, false],
|
|
344
|
-
[`test.cif`, false, false], // Not a trajectory file
|
|
345
|
-
])(
|
|
346
|
-
`ASE trajectory file handling: "%s" → trajectory:%s, binary:%s`,
|
|
347
|
-
async (filename, is_trajectory, is_binary) => {
|
|
348
|
-
expect(is_trajectory_file(filename)).toBe(is_trajectory)
|
|
349
|
-
if (is_trajectory) {
|
|
350
|
-
const result = await read_file(`/test/${filename}`)
|
|
351
|
-
expect(result.is_base64).toBe(is_binary)
|
|
352
|
-
}
|
|
353
|
-
},
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
// Integration test for ASE trajectory file processing (simulates the exact failing scenario)
|
|
357
|
-
test(`ASE trajectory file end-to-end processing`, async () => {
|
|
358
|
-
const ase_filename = `ase-LiMnO2-chgnet-relax.traj`
|
|
359
|
-
|
|
360
|
-
// Step 1: Extension should detect this as a trajectory file
|
|
361
|
-
expect(is_trajectory_file(ase_filename)).toBe(true)
|
|
362
|
-
|
|
363
|
-
// Step 2: Extension should read this as binary (compressed)
|
|
364
|
-
const file_result = await read_file(`/test/${ase_filename}`)
|
|
365
|
-
expect(file_result.filename).toBe(ase_filename)
|
|
366
|
-
expect(file_result.is_base64).toBe(true)
|
|
367
|
-
expect(file_result.content).toBe(Buffer.from(`mock content`).toString(`base64`)) // base64 encoded binary data
|
|
368
|
-
|
|
369
|
-
// Step 3: Verify webview data structure matches expected format
|
|
370
|
-
const webview_data = {
|
|
371
|
-
type: `trajectory` as const,
|
|
372
|
-
data: file_result,
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// Step 4: HTML generation should work with this data
|
|
376
|
-
const webview_data_with_theme = { ...webview_data, theme: `light` as const }
|
|
377
|
-
const html = create_html(mock_webview, mock_context, webview_data_with_theme)
|
|
378
|
-
|
|
379
|
-
expect(html).toContain(`<!DOCTYPE html>`)
|
|
380
|
-
expect(html).toContain(JSON.stringify(webview_data_with_theme))
|
|
381
|
-
|
|
382
|
-
// Step 5: Verify the exact data structure that would be sent to webview
|
|
383
|
-
const parsed_data = JSON.parse(/matterviz_data=(\{[\s\S]*?\});/.exec(html)?.[1] ?? `{}`)
|
|
384
|
-
expect(parsed_data.type).toBe(`trajectory`)
|
|
385
|
-
expect(parsed_data.data.filename).toBe(ase_filename)
|
|
386
|
-
expect(parsed_data.data.is_base64).toBe(true)
|
|
387
|
-
expect(parsed_data.data.content).toBe(Buffer.from(`mock content`).toString(`base64`))
|
|
388
|
-
expect(parsed_data.theme).toBe(`light`)
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
test.each([
|
|
392
|
-
[{ fsPath: `/test/file.cif` } as unknown as Uri, `file.cif`],
|
|
393
|
-
[{ fsPath: `/test/structure.xyz` } as unknown as Uri, `structure.xyz`],
|
|
394
|
-
])(`get_file with URI`, async (uri, expected_filename) => {
|
|
395
|
-
const result = await get_file(uri)
|
|
396
|
-
expect(result.filename).toBe(expected_filename)
|
|
397
|
-
})
|
|
398
|
-
|
|
399
|
-
test(`get_file with active editor`, async () => {
|
|
400
|
-
mock_vscode.window.activeTextEditor = {
|
|
401
|
-
document: { fileName: `/test/active.cif`, getText: () => `active content` },
|
|
402
|
-
} as TextEditor
|
|
403
|
-
const result = await get_file()
|
|
404
|
-
expect(result.filename).toBe(`active.cif`)
|
|
405
|
-
expect(result.content).toBe(`active content`)
|
|
406
|
-
expect(result.is_base64).toBe(false)
|
|
407
|
-
})
|
|
408
|
-
|
|
409
|
-
test(`get_file with active tab`, async () => {
|
|
410
|
-
mock_vscode.window.tabGroups.activeTabGroup.activeTab = {
|
|
411
|
-
input: { uri: { fsPath: `/test/tab.cif` } },
|
|
412
|
-
} as unknown as Tab
|
|
413
|
-
const result = await get_file()
|
|
414
|
-
expect(result.filename).toBe(`tab.cif`)
|
|
415
|
-
})
|
|
416
|
-
|
|
417
|
-
test(`get_file throws when no file found`, async () => {
|
|
418
|
-
mock_vscode.window.tabGroups.activeTabGroup.activeTab = null
|
|
419
|
-
await expect(get_file()).rejects.toThrow(
|
|
420
|
-
`No file selected. MatterViz needs an active editor to know what to render.`,
|
|
421
|
-
)
|
|
422
|
-
})
|
|
423
|
-
|
|
424
|
-
test.each([
|
|
425
|
-
[`structure`, { filename: `test.cif`, content: `content`, is_base64: false }],
|
|
426
|
-
[`trajectory`, { filename: `test.traj`, content: `YmluYXJ5`, is_base64: true }],
|
|
427
|
-
[
|
|
428
|
-
`structure`,
|
|
429
|
-
{
|
|
430
|
-
filename: `test"quotes.cif`,
|
|
431
|
-
content: `content`,
|
|
432
|
-
is_base64: false,
|
|
433
|
-
},
|
|
434
|
-
],
|
|
435
|
-
[`structure`, { filename: `test.cif`, content: ``, is_base64: false }],
|
|
436
|
-
[
|
|
437
|
-
`structure`,
|
|
438
|
-
{
|
|
439
|
-
filename: `test.cif`,
|
|
440
|
-
content: `<script>alert("xss")</script>`,
|
|
441
|
-
is_base64: false,
|
|
442
|
-
},
|
|
443
|
-
],
|
|
444
|
-
[
|
|
445
|
-
`structure`,
|
|
446
|
-
{
|
|
447
|
-
filename: `large.cif`,
|
|
448
|
-
content: `x`.repeat(100_000),
|
|
449
|
-
is_base64: false,
|
|
450
|
-
},
|
|
451
|
-
],
|
|
452
|
-
] as const)(`HTML generation: %s files`, (type, data) => {
|
|
453
|
-
const webview_data = { type, data, theme: `light` } as const
|
|
454
|
-
const html = create_html(mock_webview, mock_context, webview_data)
|
|
455
|
-
expect(html).toContain(`<!DOCTYPE html>`)
|
|
456
|
-
expect(html).toContain(`Content-Security-Policy`)
|
|
457
|
-
expect(html).toContain(`default-src 'none'`)
|
|
458
|
-
expect(html).toContain(`script-src 'nonce-`)
|
|
459
|
-
expect(html).toMatch(/nonce="[a-zA-Z0-9]{8,32}"/)
|
|
460
|
-
expect(html).toContain(JSON.stringify(webview_data).replace(/<\//g, `<\\/`))
|
|
461
|
-
expect(html).toContain(`matterviz-app`)
|
|
462
|
-
})
|
|
463
|
-
|
|
464
|
-
test.each([
|
|
465
|
-
[{ command: `info`, text: `Test message` }, `showInformationMessage`],
|
|
466
|
-
[{ command: `error`, text: `Error message` }, `showErrorMessage`],
|
|
467
|
-
[{ command: `info`, text: `"><script>alert(1)</script>` }, `showInformationMessage`],
|
|
468
|
-
[{ command: `error`, text: `javascript:alert(1)` }, `showErrorMessage`],
|
|
469
|
-
] as const)(`message handling: %s`, async (message, expected_method) => {
|
|
470
|
-
await handle_msg(message)
|
|
471
|
-
expect(
|
|
472
|
-
mock_vscode.window[expected_method as keyof typeof mock_vscode.window],
|
|
473
|
-
).toHaveBeenCalledWith(message.text)
|
|
474
|
-
})
|
|
475
|
-
|
|
476
|
-
test.each([
|
|
477
|
-
[{ command: `saveAs`, content: `content`, filename: `test.cif` }, true, `Saved: save.cif`],
|
|
478
|
-
[
|
|
479
|
-
{
|
|
480
|
-
command: `saveAs`,
|
|
481
|
-
content: `<script>alert("XSS")</script>`,
|
|
482
|
-
filename: `test.cif`,
|
|
483
|
-
},
|
|
484
|
-
true,
|
|
485
|
-
`Saved: save.cif`,
|
|
486
|
-
],
|
|
487
|
-
] as const)(`saveAs success: %s`, async (message, should_succeed, expected_info) => {
|
|
488
|
-
mock_vscode.window.showSaveDialog.mockResolvedValue({ fsPath: `/test/save.cif` })
|
|
489
|
-
await handle_msg(message)
|
|
490
|
-
if (should_succeed) {
|
|
491
|
-
const enc = new TextEncoder()
|
|
492
|
-
expect(mock_vscode.workspace.fs.writeFile).toHaveBeenCalledWith(
|
|
493
|
-
{ fsPath: `/test/save.cif` },
|
|
494
|
-
enc.encode(message.content),
|
|
495
|
-
)
|
|
496
|
-
expect(mock_vscode.window.showInformationMessage).toHaveBeenCalledWith(expected_info)
|
|
497
|
-
}
|
|
498
|
-
})
|
|
499
|
-
|
|
500
|
-
test.each([
|
|
501
|
-
[
|
|
502
|
-
`PNG image`,
|
|
503
|
-
`data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==`,
|
|
504
|
-
`structure.png`,
|
|
505
|
-
true,
|
|
506
|
-
],
|
|
507
|
-
[
|
|
508
|
-
`JPEG image`,
|
|
509
|
-
`data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8QAFBABAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AP/Z`,
|
|
510
|
-
`plot.jpg`,
|
|
511
|
-
true,
|
|
512
|
-
],
|
|
513
|
-
[
|
|
514
|
-
`PDF document`,
|
|
515
|
-
`data:application/pdf;base64,JVBERi0xLjQKJcOkw7zDtsO8DQoxIDAgb2JqDQo8PA0KL1R5cGUgL0NhdGFsb2cNCi9QYWdlcyAyIDAgUg0KPj4NCmVuZG9iag0KMiAwIG9iag0KPDwNCi9UeXBlIC9QYWdlcw0KL0tpZHMgWzMgMCBSXQ0KL0NvdW50IDENCi9NZWRpYUJveCBbMCAwIDYxMiA3OTJdDQo+Pg0KZW5kb2JqDQozIDAgb2JqDQo8PA0KL1R5cGUgL1BhZ2UNCi9QYXJlbnQgMiAwIFINCi9SZXNvdXJjZXMgPDwNCi9Gb250IDw8DQovRjEgNCAwIFINCj4+DQo+Pg0KL0NvbnRlbnRzIDUgMCBSDQo+Pg0KZW5kb2JqDQo0IDAgb2JqDQo8PA0KL1R5cGUgL0ZvbnQNCi9TdWJ0eXBlIC9UeXBlMQ0KL0Jhc2VGb250IC9IZWx2ZXRpY2ENCi9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nDQo+Pg0KZW5kb2JqDQo1IDAgb2JqDQo8PA0KL0xlbmd0aCA0NA0KPj4NCnN0cmVhbQ0KQlQNCjEyIDAgVGQKL0YxIDEyIFRqDQooSGVsbG8gV29ybGQpIFRqDQpFVA0KZW5kc3RyZWFtDQplbmRvYmoNCnhyZWYNCjAgNg0KMDAwMDAwMDAwMCA2NTUzNSBmDQowMDAwMDAwMDEwIDAwMDAwIG4NCjAwMDAwMDAwNzkgMDAwMDAgbg0KMDAwMDAwMDE3MyAwMDAwMCBuDQowMDAwMDAwMzAxIDAwMDAwIG4NCjAwMDAwMDAzODAgMDAwMDAgbg0KdHJhaWxlcg0KPDwNCi9TaXplIDYNCi9Sb290IDEgMCBSDQo+Pg0Kc3RhcnR4cmVmDQo0OTINCiUlRU9G`,
|
|
516
|
-
`report.pdf`,
|
|
517
|
-
true,
|
|
518
|
-
],
|
|
519
|
-
])(`saveAs binary data: %s`, async (_description, data_url, filename, is_binary) => {
|
|
520
|
-
mock_vscode.window.showSaveDialog.mockResolvedValue({ fsPath: `/test/${filename}` })
|
|
521
|
-
await handle_msg({
|
|
522
|
-
command: `saveAs`,
|
|
523
|
-
content: data_url,
|
|
524
|
-
...msg_args,
|
|
525
|
-
filename,
|
|
526
|
-
is_binary,
|
|
527
|
-
})
|
|
528
|
-
const base64_data = data_url.replace(/^data:[^;]+;base64,/, ``)
|
|
529
|
-
const expected_buffer = Uint8Array.from(Buffer.from(base64_data, `base64`))
|
|
530
|
-
expect(mock_vscode.workspace.fs.writeFile).toHaveBeenCalledWith(
|
|
531
|
-
{ fsPath: `/test/${filename}` },
|
|
532
|
-
expected_buffer,
|
|
533
|
-
)
|
|
534
|
-
expect(mock_vscode.window.showInformationMessage).toHaveBeenCalledWith(
|
|
535
|
-
`Saved: ${filename}`,
|
|
536
|
-
)
|
|
537
|
-
})
|
|
538
|
-
|
|
539
|
-
test(`saveAs error handling`, async () => {
|
|
540
|
-
mock_vscode.window.showSaveDialog.mockResolvedValue({
|
|
541
|
-
fsPath: `/test/save.cif`,
|
|
542
|
-
})
|
|
543
|
-
mock_vscode.workspace.fs.writeFile.mockRejectedValue(new Error(`Write failed`))
|
|
544
|
-
|
|
545
|
-
await handle_msg({
|
|
546
|
-
command: `saveAs`,
|
|
547
|
-
content: `content`,
|
|
548
|
-
...msg_args,
|
|
549
|
-
filename: `test.cif`,
|
|
550
|
-
})
|
|
551
|
-
expect(mock_vscode.window.showErrorMessage).toHaveBeenCalledWith(
|
|
552
|
-
`Failed to save text file: Write failed`,
|
|
553
|
-
)
|
|
554
|
-
})
|
|
555
|
-
|
|
556
|
-
test(`saveAs user cancellation`, async () => {
|
|
557
|
-
mock_vscode.window.showSaveDialog.mockResolvedValue(undefined)
|
|
558
|
-
|
|
559
|
-
await handle_msg({
|
|
560
|
-
command: `saveAs`,
|
|
561
|
-
content: `content`,
|
|
562
|
-
...msg_args,
|
|
563
|
-
filename: `test.cif`,
|
|
564
|
-
})
|
|
565
|
-
expect(mock_vscode.workspace.fs.writeFile).not.toHaveBeenCalled()
|
|
566
|
-
})
|
|
567
|
-
|
|
568
|
-
test(`saveAs binary data validation: empty base64 data`, async () => {
|
|
569
|
-
mock_vscode.window.showSaveDialog.mockResolvedValue({ fsPath: `/test/test.png` })
|
|
570
|
-
|
|
571
|
-
await handle_msg({
|
|
572
|
-
command: `saveAs`,
|
|
573
|
-
content: `data:image/png;base64,`,
|
|
574
|
-
...msg_args,
|
|
575
|
-
filename: `test.png`,
|
|
576
|
-
is_binary: true,
|
|
577
|
-
})
|
|
578
|
-
|
|
579
|
-
expect(mock_vscode.window.showErrorMessage).toHaveBeenCalledWith(
|
|
580
|
-
`Failed to save binary data: Invalid data URL: missing base64 data`,
|
|
581
|
-
)
|
|
582
|
-
expect(mock_vscode.workspace.fs.writeFile).not.toHaveBeenCalled()
|
|
583
|
-
})
|
|
584
|
-
|
|
585
|
-
test.each([[{ command: `info` }], [{ command: `saveAs` }], [{ command: `unknown` }]])(
|
|
586
|
-
`malformed message handling: %s`,
|
|
587
|
-
async (msg) => {
|
|
588
|
-
await expect(
|
|
589
|
-
handle_msg({ ...msg, ...msg_args } as unknown as MessageData),
|
|
590
|
-
).resolves.toBeUndefined()
|
|
591
|
-
},
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
test(`render creates webview panel`, async () => {
|
|
595
|
-
const mock_panel = {
|
|
596
|
-
webview: { ...mock_webview },
|
|
597
|
-
onDidDispose: vi.fn(),
|
|
598
|
-
}
|
|
599
|
-
mock_vscode.window.createWebviewPanel.mockReturnValue(mock_panel)
|
|
600
|
-
mock_vscode.window.activeTextEditor = {
|
|
601
|
-
document: { fileName: `/test/active.cif`, getText: () => `content` },
|
|
602
|
-
} as TextEditor
|
|
603
|
-
|
|
604
|
-
await render(mock_context)
|
|
605
|
-
expect(mock_vscode.window.createWebviewPanel).toHaveBeenCalledWith(
|
|
606
|
-
`matterviz`,
|
|
607
|
-
`MatterViz - active.cif`,
|
|
608
|
-
mock_vscode.ViewColumn.Active,
|
|
609
|
-
expect.any(Object),
|
|
610
|
-
)
|
|
611
|
-
})
|
|
612
|
-
|
|
613
|
-
test(`render handles errors`, async () => {
|
|
614
|
-
mock_vscode.window.activeTextEditor = null
|
|
615
|
-
mock_vscode.window.tabGroups.activeTabGroup.activeTab = null
|
|
616
|
-
await render(mock_context)
|
|
617
|
-
expect(mock_vscode.window.showErrorMessage).toHaveBeenCalledWith(
|
|
618
|
-
`Failed: No file selected. MatterViz needs an active editor to know what to render.`,
|
|
619
|
-
)
|
|
620
|
-
})
|
|
621
|
-
|
|
622
|
-
test(`extension activation`, () => {
|
|
623
|
-
activate(mock_context)
|
|
624
|
-
expect(mock_vscode.commands.registerCommand).toHaveBeenCalledWith(
|
|
625
|
-
`matterviz.open`,
|
|
626
|
-
expect.any(Function),
|
|
627
|
-
)
|
|
628
|
-
expect(mock_vscode.commands.registerCommand).toHaveBeenCalledWith(
|
|
629
|
-
`matterviz.report_bug`,
|
|
630
|
-
expect.any(Function),
|
|
631
|
-
)
|
|
632
|
-
expect(mock_vscode.window.registerCustomEditorProvider).toHaveBeenCalledWith(
|
|
633
|
-
`matterviz.viewer`,
|
|
634
|
-
expect.any(Object),
|
|
635
|
-
expect.any(Object),
|
|
636
|
-
)
|
|
637
|
-
})
|
|
638
|
-
|
|
639
|
-
describe(`Bug Reporting`, () => {
|
|
640
|
-
let mock_opened_document: { content: string; language: string } | null = null
|
|
641
|
-
let report_bug_command: (() => Promise<void>) | null = null
|
|
642
|
-
let mock_env: {
|
|
643
|
-
appName: string
|
|
644
|
-
remoteName: string | undefined
|
|
645
|
-
uiKind: number
|
|
646
|
-
clipboard: {
|
|
647
|
-
writeText: ReturnType<typeof vi.fn>
|
|
648
|
-
readText: ReturnType<typeof vi.fn>
|
|
649
|
-
}
|
|
650
|
-
openExternal: ReturnType<typeof vi.fn>
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
beforeEach(async () => {
|
|
654
|
-
// Reset state
|
|
655
|
-
mock_opened_document = null
|
|
656
|
-
report_bug_command = null
|
|
657
|
-
|
|
658
|
-
// Mock clipboard API (must be set up before activation)
|
|
659
|
-
mock_env = {
|
|
660
|
-
appName: `Cursor`,
|
|
661
|
-
remoteName: undefined,
|
|
662
|
-
uiKind: 1, // Desktop
|
|
663
|
-
clipboard: {
|
|
664
|
-
writeText: vi.fn(() => Promise.resolve()),
|
|
665
|
-
readText: vi.fn(() => Promise.resolve(``)),
|
|
666
|
-
},
|
|
667
|
-
openExternal: vi.fn(() => Promise.resolve(true)),
|
|
668
|
-
}
|
|
669
|
-
mock_vscode.env = mock_env as unknown as typeof mock_vscode.env
|
|
670
|
-
|
|
671
|
-
// Capture the report_bug command during activation
|
|
672
|
-
const command_registry = new Map<string, () => Promise<void>>()
|
|
673
|
-
mock_vscode.commands.registerCommand = vi.fn(
|
|
674
|
-
(command_name: string, callback: () => Promise<void>) => {
|
|
675
|
-
command_registry.set(command_name, callback)
|
|
676
|
-
return { dispose: vi.fn() }
|
|
677
|
-
},
|
|
678
|
-
)
|
|
679
|
-
|
|
680
|
-
// Mock workspace.openTextDocument to capture the document content (BEFORE activation)
|
|
681
|
-
mock_vscode.workspace.openTextDocument = vi.fn(
|
|
682
|
-
(options: { content: string; language: string }) => {
|
|
683
|
-
mock_opened_document = {
|
|
684
|
-
content: options.content,
|
|
685
|
-
language: options.language,
|
|
686
|
-
}
|
|
687
|
-
return Promise.resolve({
|
|
688
|
-
uri: { fsPath: `/tmp/bug-report.md` },
|
|
689
|
-
getText: () => options.content,
|
|
690
|
-
})
|
|
691
|
-
},
|
|
692
|
-
)
|
|
693
|
-
|
|
694
|
-
// Mock window.showTextDocument (BEFORE activation)
|
|
695
|
-
mock_vscode.window.showTextDocument = vi.fn(() => Promise.resolve())
|
|
696
|
-
|
|
697
|
-
// Mock showInformationMessage to return action choices (BEFORE activation)
|
|
698
|
-
mock_vscode.window.showInformationMessage = vi.fn(() => Promise.resolve(undefined))
|
|
699
|
-
|
|
700
|
-
// Activate extension to register commands
|
|
701
|
-
activate(mock_context)
|
|
702
|
-
|
|
703
|
-
// Get the report_bug command
|
|
704
|
-
report_bug_command = command_registry.get(`matterviz.report_bug`) ?? null
|
|
705
|
-
})
|
|
706
|
-
|
|
707
|
-
test(`should generate bug report with environment information`, async () => {
|
|
708
|
-
expect(report_bug_command).not.toBeNull()
|
|
709
|
-
if (!report_bug_command) return
|
|
710
|
-
|
|
711
|
-
await report_bug_command()
|
|
712
|
-
|
|
713
|
-
expect(mock_opened_document).not.toBeNull()
|
|
714
|
-
expect(mock_opened_document?.language).toBe(`markdown`)
|
|
715
|
-
|
|
716
|
-
const content = mock_opened_document?.content ?? ``
|
|
717
|
-
|
|
718
|
-
// Check for main sections
|
|
719
|
-
expect(content).toContain(`### Environment`)
|
|
720
|
-
expect(content).toContain(`### System Resources`)
|
|
721
|
-
expect(content).toContain(`### Active Files & Extension State`)
|
|
722
|
-
expect(content).toContain(`### Console Logs`)
|
|
723
|
-
|
|
724
|
-
// Check environment details
|
|
725
|
-
expect(content).toContain(`- **Editor**: Cursor`)
|
|
726
|
-
expect(content).toContain(`- **MatterViz Version**: ${pkg_json.version}`)
|
|
727
|
-
expect(content).toContain(`- **UI Kind**: Desktop`)
|
|
728
|
-
expect(content).toContain(`- **Remote Session**: No (Local)`)
|
|
729
|
-
|
|
730
|
-
// Check system resources
|
|
731
|
-
expect(content).toContain(`- **Total Memory**:`)
|
|
732
|
-
expect(content).toContain(`- **Free Memory**:`)
|
|
733
|
-
expect(content).toContain(`- **Process RSS**:`)
|
|
734
|
-
expect(content).toContain(`- **Process Heap Used**:`)
|
|
735
|
-
expect(content).toContain(`- **Process Heap Total**:`)
|
|
736
|
-
|
|
737
|
-
// Check console logs instructions
|
|
738
|
-
expect(content).toContain(`**Please check for console errors/warnings:**`)
|
|
739
|
-
expect(content).toContain(`Toggle Developer Tools`)
|
|
740
|
-
|
|
741
|
-
// Check GitHub link
|
|
742
|
-
expect(content).toContain(`https://github.com/janosh/matterviz/issues`)
|
|
743
|
-
|
|
744
|
-
// Check timestamp
|
|
745
|
-
expect(content).toMatch(/\*\*Generated\*\*: \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/)
|
|
746
|
-
})
|
|
747
|
-
|
|
748
|
-
test(`should detect remote session correctly`, async () => {
|
|
749
|
-
// Mock remote session
|
|
750
|
-
mock_env.remoteName = `ssh-remote`
|
|
751
|
-
|
|
752
|
-
expect(report_bug_command).not.toBeNull()
|
|
753
|
-
if (!report_bug_command) return
|
|
754
|
-
|
|
755
|
-
await report_bug_command()
|
|
756
|
-
|
|
757
|
-
const content = mock_opened_document?.content ?? ``
|
|
758
|
-
expect(content).toContain(`- **Remote Session**: Yes (ssh-remote)`)
|
|
759
|
-
})
|
|
760
|
-
|
|
761
|
-
test(`should include active files in report`, async () => {
|
|
762
|
-
// Start watching some files first
|
|
763
|
-
const file1_path = `/test/structure.cif`
|
|
764
|
-
const file2_path = `/test/trajectory.traj`
|
|
765
|
-
|
|
766
|
-
await handle_msg(
|
|
767
|
-
{
|
|
768
|
-
command: `startWatching`,
|
|
769
|
-
file_path: file1_path,
|
|
770
|
-
filename: `structure.cif`,
|
|
771
|
-
request_id: `req1`,
|
|
772
|
-
frame_index: 0,
|
|
773
|
-
} as MessageData,
|
|
774
|
-
mock_webview,
|
|
775
|
-
)
|
|
776
|
-
|
|
777
|
-
await handle_msg(
|
|
778
|
-
{
|
|
779
|
-
command: `startWatching`,
|
|
780
|
-
file_path: file2_path,
|
|
781
|
-
filename: `trajectory.traj`,
|
|
782
|
-
request_id: `req2`,
|
|
783
|
-
frame_index: 0,
|
|
784
|
-
} as MessageData,
|
|
785
|
-
mock_webview,
|
|
786
|
-
)
|
|
787
|
-
|
|
788
|
-
expect(report_bug_command).not.toBeNull()
|
|
789
|
-
if (!report_bug_command) return
|
|
790
|
-
|
|
791
|
-
await report_bug_command()
|
|
792
|
-
|
|
793
|
-
const content = mock_opened_document?.content ?? ``
|
|
794
|
-
|
|
795
|
-
// Should list both files with bold filenames (not headers)
|
|
796
|
-
expect(content).toContain(`**structure.cif**`)
|
|
797
|
-
expect(content).toContain(`**trajectory.traj**`)
|
|
798
|
-
expect(content).toContain(`- **Path**: \`${file1_path}\``)
|
|
799
|
-
expect(content).toContain(`- **Path**: \`${file2_path}\``)
|
|
800
|
-
expect(content).toContain(`- **Has Watcher**: true`)
|
|
801
|
-
|
|
802
|
-
// Check for combined section and extension state counters
|
|
803
|
-
expect(content).toContain(`### Active Files & Extension State`)
|
|
804
|
-
expect(content).toContain(`- **Active Watchers**: 2`)
|
|
805
|
-
})
|
|
806
|
-
|
|
807
|
-
test(`should handle files with no active watchers`, async () => {
|
|
808
|
-
expect(report_bug_command).not.toBeNull()
|
|
809
|
-
if (!report_bug_command) return
|
|
810
|
-
|
|
811
|
-
await report_bug_command()
|
|
812
|
-
|
|
813
|
-
const content = mock_opened_document?.content ?? ``
|
|
814
|
-
expect(content).toContain(`No files currently being watched/rendered.`)
|
|
815
|
-
})
|
|
816
|
-
|
|
817
|
-
test(`should copy to clipboard when user selects that option`, async () => {
|
|
818
|
-
mock_vscode.window.showInformationMessage = vi.fn(() =>
|
|
819
|
-
Promise.resolve(`Copy to Clipboard`),
|
|
820
|
-
)
|
|
821
|
-
|
|
822
|
-
expect(report_bug_command).not.toBeNull()
|
|
823
|
-
if (!report_bug_command) return
|
|
824
|
-
|
|
825
|
-
await report_bug_command()
|
|
826
|
-
|
|
827
|
-
const content = mock_opened_document?.content ?? ``
|
|
828
|
-
|
|
829
|
-
// Should have called clipboard.writeText with the content
|
|
830
|
-
expect(mock_env.clipboard.writeText).toHaveBeenCalledWith(content)
|
|
831
|
-
|
|
832
|
-
// Should show success message
|
|
833
|
-
expect(mock_vscode.window.showInformationMessage).toHaveBeenCalledWith(
|
|
834
|
-
`Debug information copied to clipboard!`,
|
|
835
|
-
)
|
|
836
|
-
})
|
|
837
|
-
|
|
838
|
-
test(`should open GitHub issues when user selects that option`, async () => {
|
|
839
|
-
mock_vscode.window.showInformationMessage = vi.fn(() =>
|
|
840
|
-
Promise.resolve(`Open GitHub Issues`),
|
|
841
|
-
)
|
|
842
|
-
|
|
843
|
-
expect(report_bug_command).not.toBeNull()
|
|
844
|
-
if (!report_bug_command) return
|
|
845
|
-
|
|
846
|
-
await report_bug_command()
|
|
847
|
-
|
|
848
|
-
// Should have opened GitHub issues URL
|
|
849
|
-
expect(mock_env.openExternal).toHaveBeenCalledWith(
|
|
850
|
-
expect.objectContaining({
|
|
851
|
-
toString: expect.any(Function),
|
|
852
|
-
}),
|
|
853
|
-
)
|
|
854
|
-
|
|
855
|
-
// Verify the URL contains the GitHub issues path
|
|
856
|
-
const call_args = mock_env.openExternal.mock.calls[0]
|
|
857
|
-
expect(call_args[0].toString()).toContain(
|
|
858
|
-
`https://github.com/janosh/matterviz/issues/new`,
|
|
859
|
-
)
|
|
860
|
-
})
|
|
861
|
-
|
|
862
|
-
test(`should format file sizes correctly`, async () => {
|
|
863
|
-
// Mock different file sizes
|
|
864
|
-
const test_cases = [
|
|
865
|
-
{ size: 500, expected: `500 B` },
|
|
866
|
-
{ size: 1024, expected: `1.00 KiB` },
|
|
867
|
-
{ size: 1024 * 1024, expected: `1.00 MiB` },
|
|
868
|
-
{ size: 1024 * 1024 * 1024, expected: `1.00 GiB` },
|
|
869
|
-
]
|
|
870
|
-
|
|
871
|
-
// Create a map to track sizes for each file
|
|
872
|
-
const file_sizes = new Map<string, number>()
|
|
873
|
-
|
|
874
|
-
// Set up persistent mock that uses the file_sizes map
|
|
875
|
-
mock_vscode.workspace.fs.stat.mockImplementation((uri) => {
|
|
876
|
-
const size = file_sizes.get(uri.fsPath) ?? 1000
|
|
877
|
-
return Promise.resolve({ size, type: 1 })
|
|
878
|
-
})
|
|
879
|
-
|
|
880
|
-
// Add files to watchers with their sizes
|
|
881
|
-
const watcher_promises = test_cases.map((test_case) => {
|
|
882
|
-
const file_path = `/test/file_${test_case.size}.cif`
|
|
883
|
-
file_sizes.set(file_path, test_case.size)
|
|
884
|
-
|
|
885
|
-
return handle_msg(
|
|
886
|
-
{
|
|
887
|
-
command: `startWatching`,
|
|
888
|
-
file_path,
|
|
889
|
-
filename: `file_${test_case.size}.cif`,
|
|
890
|
-
request_id: `req_${test_case.size}`,
|
|
891
|
-
frame_index: 0,
|
|
892
|
-
} as MessageData,
|
|
893
|
-
mock_webview,
|
|
894
|
-
)
|
|
895
|
-
})
|
|
896
|
-
|
|
897
|
-
await Promise.all(watcher_promises)
|
|
898
|
-
|
|
899
|
-
expect(report_bug_command).not.toBeNull()
|
|
900
|
-
if (!report_bug_command) return
|
|
901
|
-
|
|
902
|
-
await report_bug_command()
|
|
903
|
-
|
|
904
|
-
const content = mock_opened_document?.content ?? ``
|
|
905
|
-
|
|
906
|
-
// Check that sizes are formatted correctly
|
|
907
|
-
for (const test_case of test_cases) {
|
|
908
|
-
if (test_case.size >= 1024) {
|
|
909
|
-
// Only check KB and above (bytes might be rounded)
|
|
910
|
-
expect(content).toContain(test_case.expected)
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
})
|
|
914
|
-
|
|
915
|
-
test(`should handle file stat errors gracefully`, async () => {
|
|
916
|
-
// Mock file that exists but throws error on stat
|
|
917
|
-
const file_path = `/test/error-file.cif`
|
|
918
|
-
|
|
919
|
-
await handle_msg(
|
|
920
|
-
{
|
|
921
|
-
command: `startWatching`,
|
|
922
|
-
file_path,
|
|
923
|
-
filename: `error-file.cif`,
|
|
924
|
-
request_id: `req_error`,
|
|
925
|
-
frame_index: 0,
|
|
926
|
-
} as MessageData,
|
|
927
|
-
mock_webview,
|
|
928
|
-
)
|
|
929
|
-
|
|
930
|
-
// Mock stat to throw error for this specific file
|
|
931
|
-
mock_vscode.workspace.fs.stat.mockRejectedValue(new Error(`File not found`))
|
|
932
|
-
|
|
933
|
-
expect(report_bug_command).not.toBeNull()
|
|
934
|
-
if (!report_bug_command) return
|
|
935
|
-
|
|
936
|
-
await report_bug_command()
|
|
937
|
-
|
|
938
|
-
const content = mock_opened_document?.content ?? ``
|
|
939
|
-
|
|
940
|
-
// Should still include the file but with "Unknown" size
|
|
941
|
-
expect(content).toContain(`**error-file.cif**`)
|
|
942
|
-
expect(content).toContain(`- **Size**: Unknown`)
|
|
943
|
-
})
|
|
944
|
-
|
|
945
|
-
test(`should include extension state counters`, async () => {
|
|
946
|
-
// Start watching multiple files
|
|
947
|
-
await handle_msg(
|
|
948
|
-
{
|
|
949
|
-
command: `startWatching`,
|
|
950
|
-
file_path: `/test/file1.cif`,
|
|
951
|
-
filename: `file1.cif`,
|
|
952
|
-
request_id: `req1`,
|
|
953
|
-
frame_index: 0,
|
|
954
|
-
} as MessageData,
|
|
955
|
-
mock_webview,
|
|
956
|
-
)
|
|
957
|
-
|
|
958
|
-
await handle_msg(
|
|
959
|
-
{
|
|
960
|
-
command: `startWatching`,
|
|
961
|
-
file_path: `/test/file2.cif`,
|
|
962
|
-
filename: `file2.cif`,
|
|
963
|
-
request_id: `req2`,
|
|
964
|
-
frame_index: 0,
|
|
965
|
-
} as MessageData,
|
|
966
|
-
mock_webview,
|
|
967
|
-
)
|
|
968
|
-
|
|
969
|
-
expect(report_bug_command).not.toBeNull()
|
|
970
|
-
if (!report_bug_command) return
|
|
971
|
-
|
|
972
|
-
await report_bug_command()
|
|
973
|
-
|
|
974
|
-
const content = mock_opened_document?.content ?? ``
|
|
975
|
-
|
|
976
|
-
// Check combined Active Files & Extension State section
|
|
977
|
-
expect(content).toContain(`### Active Files & Extension State`)
|
|
978
|
-
expect(content).toContain(`- **Active Watchers**: 2`)
|
|
979
|
-
expect(content).toMatch(/- \*\*Active Frame Loaders\*\*: \d+/)
|
|
980
|
-
expect(content).toMatch(/- \*\*Auto-Render Timers\*\*: \d+/)
|
|
981
|
-
expect(content).toMatch(/- \*\*Active Auto-Render Panels\*\*: \d+/)
|
|
982
|
-
})
|
|
983
|
-
|
|
984
|
-
test(`should handle errors during report generation`, async () => {
|
|
985
|
-
// Mock openTextDocument to throw an error
|
|
986
|
-
mock_vscode.workspace.openTextDocument = vi.fn(() =>
|
|
987
|
-
Promise.reject(new Error(`Failed to create document`)),
|
|
988
|
-
)
|
|
989
|
-
|
|
990
|
-
expect(report_bug_command).not.toBeNull()
|
|
991
|
-
if (!report_bug_command) return
|
|
992
|
-
|
|
993
|
-
await report_bug_command()
|
|
994
|
-
|
|
995
|
-
// Should show error message
|
|
996
|
-
expect(mock_vscode.window.showErrorMessage).toHaveBeenCalledWith(
|
|
997
|
-
expect.stringContaining(`Failed to collect debug information`),
|
|
998
|
-
)
|
|
999
|
-
})
|
|
1000
|
-
|
|
1001
|
-
test(`should include console logs instructions in bug report`, async () => {
|
|
1002
|
-
expect(report_bug_command).not.toBeNull()
|
|
1003
|
-
if (!report_bug_command) return
|
|
1004
|
-
|
|
1005
|
-
await report_bug_command()
|
|
1006
|
-
|
|
1007
|
-
const content = mock_opened_document?.content ?? ``
|
|
1008
|
-
|
|
1009
|
-
// Check for console logs section with instructions
|
|
1010
|
-
expect(content).toContain(`### Console Logs`)
|
|
1011
|
-
expect(content).toContain(`**Please check for console errors/warnings:**`)
|
|
1012
|
-
expect(content).toContain(`Toggle Developer Tools`)
|
|
1013
|
-
expect(content).toContain(`Tip: You can filter console messages`)
|
|
1014
|
-
})
|
|
1015
|
-
})
|
|
1016
|
-
|
|
1017
|
-
test(`performance benchmarks`, () => {
|
|
1018
|
-
// Trajectory detection performance
|
|
1019
|
-
const filenames = Array.from({ length: 10000 }, (_, idx) => `test_${idx}.xyz`)
|
|
1020
|
-
const start = performance.now()
|
|
1021
|
-
filenames.forEach((name) => is_trajectory_file(name))
|
|
1022
|
-
expect(performance.now() - start).toBeLessThan(100)
|
|
1023
|
-
|
|
1024
|
-
// HTML generation performance
|
|
1025
|
-
const large_data = {
|
|
1026
|
-
type: `structure`,
|
|
1027
|
-
data: { filename: `large.cif`, content: `x`.repeat(100_000), is_base64: false },
|
|
1028
|
-
theme: `light`,
|
|
1029
|
-
} as const
|
|
1030
|
-
const html_start = performance.now()
|
|
1031
|
-
create_html(mock_webview, mock_context, large_data)
|
|
1032
|
-
expect(performance.now() - html_start).toBeLessThan(50)
|
|
1033
|
-
})
|
|
1034
|
-
|
|
1035
|
-
test(`nonce uniqueness`, () => {
|
|
1036
|
-
const data = {
|
|
1037
|
-
type: `structure`,
|
|
1038
|
-
data: { filename: `test.cif`, content: `content`, is_base64: false },
|
|
1039
|
-
theme: `light`,
|
|
1040
|
-
} as const
|
|
1041
|
-
const nonces = new Set<string>()
|
|
1042
|
-
|
|
1043
|
-
for (let idx = 0; idx < 1000; idx++) {
|
|
1044
|
-
const html = create_html(mock_webview, mock_context, data)
|
|
1045
|
-
const nonce_match = /nonce="([a-zA-Z0-9]+)"/.exec(html)
|
|
1046
|
-
if (nonce_match) nonces.add(nonce_match[1])
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
expect(nonces.size).toBe(1000)
|
|
1050
|
-
})
|
|
1051
|
-
|
|
1052
|
-
test(`XSS prevention`, () => {
|
|
1053
|
-
const dangerous_payloads = [
|
|
1054
|
-
`<script>alert("XSS")</script>`,
|
|
1055
|
-
`<img src="x" onerror="alert(1)">`,
|
|
1056
|
-
`javascript:alert(1)`,
|
|
1057
|
-
`"><script>alert(1)</script>`,
|
|
1058
|
-
`';alert(1);//`,
|
|
1059
|
-
`</script><script>alert(document.cookie)</script>`,
|
|
1060
|
-
]
|
|
1061
|
-
|
|
1062
|
-
dangerous_payloads.forEach((payload) => {
|
|
1063
|
-
const data = {
|
|
1064
|
-
type: `structure`,
|
|
1065
|
-
data: { filename: `test.cif`, content: payload, is_base64: false },
|
|
1066
|
-
theme: `light`,
|
|
1067
|
-
} as const
|
|
1068
|
-
const html = create_html(mock_webview, mock_context, data)
|
|
1069
|
-
const escaped_json = JSON.stringify(data).replace(/<\//g, `<\\/`)
|
|
1070
|
-
|
|
1071
|
-
expect(html).toContain(escaped_json)
|
|
1072
|
-
// Ensure no raw </script> inside the JSON data breaks out of the script tag
|
|
1073
|
-
const data_script = /window\.matterviz_data=(.*?);/s.exec(html)
|
|
1074
|
-
if (data_script) {
|
|
1075
|
-
expect(data_script[1]).not.toContain(`</script>`)
|
|
1076
|
-
}
|
|
1077
|
-
})
|
|
1078
|
-
})
|
|
1079
|
-
|
|
1080
|
-
test(`concurrent operations`, async () => {
|
|
1081
|
-
const promises = Array.from({ length: 50 }, (_, idx) =>
|
|
1082
|
-
handle_msg({ command: `info`, text: `Message ${idx}`, ...msg_args }),
|
|
1083
|
-
)
|
|
1084
|
-
await Promise.all(promises)
|
|
1085
|
-
expect(mock_vscode.window.showInformationMessage).toHaveBeenCalledTimes(50)
|
|
1086
|
-
})
|
|
1087
|
-
|
|
1088
|
-
describe(`Theme functionality`, () => {
|
|
1089
|
-
test.each([
|
|
1090
|
-
[mock_vscode.ColorThemeKind.Light, `auto`, `light`], // Light VSCode theme, auto setting → light
|
|
1091
|
-
[mock_vscode.ColorThemeKind.Dark, `auto`, `dark`], // Dark VSCode theme, auto setting → dark
|
|
1092
|
-
[mock_vscode.ColorThemeKind.HighContrast, `auto`, `black`], // High contrast VSCode theme, auto setting → black
|
|
1093
|
-
[mock_vscode.ColorThemeKind.HighContrastLight, `auto`, `white`], // High contrast light VSCode theme, auto setting → white
|
|
1094
|
-
[mock_vscode.ColorThemeKind.Light, `light`, `light`], // Light VSCode theme, light setting → light
|
|
1095
|
-
[mock_vscode.ColorThemeKind.Light, `dark`, `dark`], // Light VSCode theme, dark setting → dark
|
|
1096
|
-
[mock_vscode.ColorThemeKind.Light, `white`, `white`], // Light VSCode theme, white setting → white
|
|
1097
|
-
[mock_vscode.ColorThemeKind.Light, `black`, `black`], // Light VSCode theme, black setting → black
|
|
1098
|
-
[mock_vscode.ColorThemeKind.Dark, `light`, `light`], // Dark VSCode theme, light setting → light
|
|
1099
|
-
[mock_vscode.ColorThemeKind.Dark, `dark`, `dark`], // Dark VSCode theme, dark setting → dark
|
|
1100
|
-
[mock_vscode.ColorThemeKind.Dark, `white`, `white`], // Dark VSCode theme, white setting → white
|
|
1101
|
-
[mock_vscode.ColorThemeKind.Dark, `black`, `black`], // Dark VSCode theme, black setting → black
|
|
1102
|
-
] as const)(
|
|
1103
|
-
`theme detection: VSCode theme %i, setting '%s' → '%s'`,
|
|
1104
|
-
(vscode_theme_kind: number, setting: string, expected: ThemeName) => {
|
|
1105
|
-
const mock_config = {
|
|
1106
|
-
get: vi.fn((key: string, default_value?: string) =>
|
|
1107
|
-
key === `theme` ? setting : default_value,
|
|
1108
|
-
),
|
|
1109
|
-
}
|
|
1110
|
-
mock_vscode.workspace.getConfiguration = vi.fn(() => mock_config) as ReturnType<
|
|
1111
|
-
typeof vi.fn
|
|
1112
|
-
>
|
|
1113
|
-
mock_vscode.window.activeColorTheme = { kind: vscode_theme_kind }
|
|
1114
|
-
|
|
1115
|
-
const result = get_theme()
|
|
1116
|
-
expect(result).toBe(expected)
|
|
1117
|
-
},
|
|
1118
|
-
)
|
|
1119
|
-
|
|
1120
|
-
test(`webview data includes theme`, () => {
|
|
1121
|
-
const mock_config = {
|
|
1122
|
-
get: vi.fn((key: string, default_value?: string) =>
|
|
1123
|
-
key === `theme` ? `dark` : default_value,
|
|
1124
|
-
),
|
|
1125
|
-
}
|
|
1126
|
-
mock_vscode.workspace.getConfiguration = vi.fn(() => mock_config) as ReturnType<
|
|
1127
|
-
typeof vi.fn
|
|
1128
|
-
>
|
|
1129
|
-
|
|
1130
|
-
const data = {
|
|
1131
|
-
type: `structure` as const,
|
|
1132
|
-
data: { filename: `test.cif`, content: `content`, is_base64: false },
|
|
1133
|
-
theme: get_theme(),
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
const html = create_html(mock_webview, mock_context, data)
|
|
1137
|
-
|
|
1138
|
-
const parsed_data = JSON.parse(/matterviz_data=(\{[\s\S]*?\});/.exec(html)?.[1] || `{}`)
|
|
1139
|
-
expect(parsed_data.theme).toBe(`dark`)
|
|
1140
|
-
})
|
|
1141
|
-
|
|
1142
|
-
test(`invalid theme setting falls back to auto`, () => {
|
|
1143
|
-
const mock_config = {
|
|
1144
|
-
get: vi.fn((key: string, default_value?: string) =>
|
|
1145
|
-
key === `theme` ? `invalid-theme` : default_value,
|
|
1146
|
-
),
|
|
1147
|
-
}
|
|
1148
|
-
mock_vscode.workspace.getConfiguration = vi.fn(() => mock_config) as ReturnType<
|
|
1149
|
-
typeof vi.fn
|
|
1150
|
-
>
|
|
1151
|
-
mock_vscode.window.activeColorTheme = {
|
|
1152
|
-
kind: mock_vscode.ColorThemeKind.Light,
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
const result = get_theme()
|
|
1156
|
-
expect(result).toBe(`light`) // Should fall back to system theme
|
|
1157
|
-
})
|
|
1158
|
-
|
|
1159
|
-
test(`high contrast themes are mapped correctly`, () => {
|
|
1160
|
-
const mock_config = {
|
|
1161
|
-
get: vi.fn((key: string, default_value?: string) =>
|
|
1162
|
-
key === `theme` ? `auto` : default_value,
|
|
1163
|
-
),
|
|
1164
|
-
}
|
|
1165
|
-
mock_vscode.workspace.getConfiguration = vi.fn(() => mock_config) as ReturnType<
|
|
1166
|
-
typeof vi.fn
|
|
1167
|
-
>
|
|
1168
|
-
|
|
1169
|
-
// Test high contrast dark → black
|
|
1170
|
-
mock_vscode.window.activeColorTheme = {
|
|
1171
|
-
kind: mock_vscode.ColorThemeKind.HighContrast,
|
|
1172
|
-
}
|
|
1173
|
-
expect(get_theme()).toBe(`black`)
|
|
1174
|
-
|
|
1175
|
-
// Test high contrast light → white
|
|
1176
|
-
mock_vscode.window.activeColorTheme = {
|
|
1177
|
-
kind: mock_vscode.ColorThemeKind.HighContrastLight,
|
|
1178
|
-
}
|
|
1179
|
-
expect(get_theme()).toBe(`white`)
|
|
1180
|
-
})
|
|
1181
|
-
})
|
|
1182
|
-
|
|
1183
|
-
describe(`Theme listener cleanup`, () => {
|
|
1184
|
-
const setup_panel = (options = {}) => {
|
|
1185
|
-
const mock_dispose = vi.fn()
|
|
1186
|
-
const mock_panel = {
|
|
1187
|
-
webview: { ...mock_webview },
|
|
1188
|
-
onDidDispose: vi.fn(),
|
|
1189
|
-
visible: true,
|
|
1190
|
-
...options,
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
mock_vscode.window.createWebviewPanel.mockReturnValue(mock_panel)
|
|
1194
|
-
mock_vscode.window.onDidChangeActiveColorTheme.mockReturnValue({
|
|
1195
|
-
dispose: mock_dispose,
|
|
1196
|
-
})
|
|
1197
|
-
mock_vscode.workspace.onDidChangeConfiguration.mockReturnValue({
|
|
1198
|
-
dispose: mock_dispose,
|
|
1199
|
-
})
|
|
1200
|
-
mock_vscode.window.activeTextEditor = {
|
|
1201
|
-
document: { fileName: `/test/active.cif`, getText: () => `content` },
|
|
1202
|
-
} as TextEditor
|
|
1203
|
-
|
|
1204
|
-
return { mock_dispose, mock_panel }
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
test(`sets up and cleans up theme listeners`, async () => {
|
|
1208
|
-
const { mock_dispose, mock_panel } = setup_panel()
|
|
1209
|
-
|
|
1210
|
-
await render(mock_context)
|
|
1211
|
-
|
|
1212
|
-
expect(mock_vscode.window.onDidChangeActiveColorTheme).toHaveBeenCalled()
|
|
1213
|
-
expect(mock_panel.onDidDispose).toHaveBeenCalled()
|
|
1214
|
-
|
|
1215
|
-
// Test cleanup
|
|
1216
|
-
mock_panel.onDidDispose.mock.calls[0][0]()
|
|
1217
|
-
expect(mock_dispose).toHaveBeenCalledTimes(2)
|
|
1218
|
-
})
|
|
1219
|
-
|
|
1220
|
-
test(`respects panel visibility for theme updates`, async () => {
|
|
1221
|
-
const mock_panel = {
|
|
1222
|
-
webview: { ...mock_webview },
|
|
1223
|
-
onDidDispose: vi.fn(),
|
|
1224
|
-
visible: false,
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
mock_vscode.window.createWebviewPanel.mockReturnValue(mock_panel)
|
|
1228
|
-
mock_vscode.window.onDidChangeActiveColorTheme.mockReturnValue({
|
|
1229
|
-
dispose: vi.fn(),
|
|
1230
|
-
})
|
|
1231
|
-
mock_vscode.workspace.onDidChangeConfiguration.mockReturnValue({
|
|
1232
|
-
dispose: vi.fn(),
|
|
1233
|
-
})
|
|
1234
|
-
mock_vscode.window.activeTextEditor = {
|
|
1235
|
-
document: { fileName: `/test/active.cif`, getText: () => `content` },
|
|
1236
|
-
} as TextEditor
|
|
1237
|
-
|
|
1238
|
-
await render(mock_context)
|
|
1239
|
-
|
|
1240
|
-
// Store initial HTML after render (render always sets HTML initially)
|
|
1241
|
-
const initial_html = mock_panel.webview.html
|
|
1242
|
-
|
|
1243
|
-
const theme_calls = mock_vscode.window.onDidChangeActiveColorTheme.mock
|
|
1244
|
-
.calls as unknown as unknown[][]
|
|
1245
|
-
const theme_callback = theme_calls[0]?.[0] as (() => Promise<void>) | undefined
|
|
1246
|
-
expect(theme_callback).toBeDefined()
|
|
1247
|
-
|
|
1248
|
-
// Should not update when invisible
|
|
1249
|
-
await theme_callback?.()
|
|
1250
|
-
expect(mock_panel.webview.html).toBe(initial_html)
|
|
1251
|
-
|
|
1252
|
-
// Should update when visible
|
|
1253
|
-
mock_panel.visible = true
|
|
1254
|
-
await theme_callback?.()
|
|
1255
|
-
expect(mock_panel.webview.html).not.toBe(initial_html)
|
|
1256
|
-
})
|
|
1257
|
-
|
|
1258
|
-
test(`multiple panels dispose independently`, async () => {
|
|
1259
|
-
const dispose1 = vi.fn()
|
|
1260
|
-
const dispose2 = vi.fn()
|
|
1261
|
-
const panel1 = { webview: { ...mock_webview }, onDidDispose: vi.fn() }
|
|
1262
|
-
const panel2 = { webview: { ...mock_webview }, onDidDispose: vi.fn() }
|
|
1263
|
-
|
|
1264
|
-
mock_vscode.window.createWebviewPanel
|
|
1265
|
-
.mockReturnValueOnce(panel1)
|
|
1266
|
-
.mockReturnValueOnce(panel2)
|
|
1267
|
-
mock_vscode.window.onDidChangeActiveColorTheme
|
|
1268
|
-
.mockReturnValueOnce({ dispose: dispose1 })
|
|
1269
|
-
.mockReturnValueOnce({
|
|
1270
|
-
dispose: dispose2,
|
|
1271
|
-
})
|
|
1272
|
-
mock_vscode.workspace.onDidChangeConfiguration
|
|
1273
|
-
.mockReturnValueOnce({ dispose: dispose1 })
|
|
1274
|
-
.mockReturnValueOnce({
|
|
1275
|
-
dispose: dispose2,
|
|
1276
|
-
})
|
|
1277
|
-
|
|
1278
|
-
mock_vscode.window.activeTextEditor = {
|
|
1279
|
-
document: { fileName: `/test/active.cif`, getText: () => `content` },
|
|
1280
|
-
} as TextEditor
|
|
1281
|
-
|
|
1282
|
-
await render(mock_context)
|
|
1283
|
-
await render(mock_context)
|
|
1284
|
-
|
|
1285
|
-
panel1.onDidDispose.mock.calls[0][0]()
|
|
1286
|
-
expect(dispose1).toHaveBeenCalledTimes(2)
|
|
1287
|
-
expect(dispose2).not.toHaveBeenCalled()
|
|
1288
|
-
})
|
|
1289
|
-
})
|
|
1290
|
-
|
|
1291
|
-
describe(`File Watching`, () => {
|
|
1292
|
-
describe(`message handling`, () => {
|
|
1293
|
-
test(`should handle startWatching message`, async () => {
|
|
1294
|
-
const message = {
|
|
1295
|
-
command: `startWatching` as const,
|
|
1296
|
-
...msg_args,
|
|
1297
|
-
file_path: `/test/file.cif`,
|
|
1298
|
-
}
|
|
1299
|
-
await handle_msg(message, mock_webview)
|
|
1300
|
-
|
|
1301
|
-
expect(mock_vscode.workspace.createFileSystemWatcher).toHaveBeenCalledWith(
|
|
1302
|
-
expect.objectContaining({
|
|
1303
|
-
base: expect.anything(),
|
|
1304
|
-
pattern: `file.cif`,
|
|
1305
|
-
}),
|
|
1306
|
-
)
|
|
1307
|
-
expect(mock_file_system_watcher.onDidChange).toHaveBeenCalledWith(expect.any(Function))
|
|
1308
|
-
expect(mock_file_system_watcher.onDidDelete).toHaveBeenCalledWith(expect.any(Function))
|
|
1309
|
-
})
|
|
1310
|
-
|
|
1311
|
-
test(`should handle stopWatching message`, async () => {
|
|
1312
|
-
// First start watching
|
|
1313
|
-
const start_message = {
|
|
1314
|
-
command: `startWatching` as const,
|
|
1315
|
-
...msg_args,
|
|
1316
|
-
file_path: `/test/file.cif`,
|
|
1317
|
-
}
|
|
1318
|
-
await handle_msg(start_message, mock_webview)
|
|
1319
|
-
|
|
1320
|
-
// Then test stopping
|
|
1321
|
-
const stop_message = {
|
|
1322
|
-
command: `stopWatching` as const,
|
|
1323
|
-
...msg_args,
|
|
1324
|
-
file_path: `/test/file.cif`,
|
|
1325
|
-
}
|
|
1326
|
-
await handle_msg(stop_message, mock_webview)
|
|
1327
|
-
|
|
1328
|
-
expect(mock_file_system_watcher.dispose).toHaveBeenCalled()
|
|
1329
|
-
})
|
|
1330
|
-
|
|
1331
|
-
test(`should handle startWatching without webview gracefully`, async () => {
|
|
1332
|
-
const message = {
|
|
1333
|
-
command: `startWatching` as const,
|
|
1334
|
-
...msg_args,
|
|
1335
|
-
file_path: `/test/file.cif`,
|
|
1336
|
-
}
|
|
1337
|
-
|
|
1338
|
-
await expect(handle_msg(message)).resolves.not.toThrow()
|
|
1339
|
-
expect(mock_vscode.workspace.createFileSystemWatcher).not.toHaveBeenCalled()
|
|
1340
|
-
})
|
|
1341
|
-
|
|
1342
|
-
test(`should handle startWatching without file_path gracefully`, async () => {
|
|
1343
|
-
const message = {
|
|
1344
|
-
command: `startWatching` as const,
|
|
1345
|
-
...msg_args,
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
await expect(handle_msg(message, mock_webview)).resolves.not.toThrow()
|
|
1349
|
-
expect(mock_vscode.workspace.createFileSystemWatcher).not.toHaveBeenCalled()
|
|
1350
|
-
})
|
|
1351
|
-
|
|
1352
|
-
test(`should send error message when file watching fails`, async () => {
|
|
1353
|
-
mock_vscode.workspace.createFileSystemWatcher.mockImplementation(() => {
|
|
1354
|
-
throw new Error(`File system watcher creation failed`)
|
|
1355
|
-
})
|
|
1356
|
-
|
|
1357
|
-
const message = {
|
|
1358
|
-
command: `startWatching` as const,
|
|
1359
|
-
...msg_args,
|
|
1360
|
-
file_path: `/test/large-file.cif`,
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
await handle_msg(message, mock_webview)
|
|
1364
|
-
|
|
1365
|
-
expect(mock_webview.postMessage).toHaveBeenCalledWith({
|
|
1366
|
-
command: `error`,
|
|
1367
|
-
text: expect.stringContaining(`Failed to start watching file`),
|
|
1368
|
-
})
|
|
1369
|
-
})
|
|
1370
|
-
})
|
|
1371
|
-
|
|
1372
|
-
describe(`file change notifications`, () => {
|
|
1373
|
-
test(`should send file change notification to webview`, async () => {
|
|
1374
|
-
const message = {
|
|
1375
|
-
command: `startWatching` as const,
|
|
1376
|
-
...msg_args,
|
|
1377
|
-
file_path: `/test/file.cif`,
|
|
1378
|
-
}
|
|
1379
|
-
|
|
1380
|
-
await handle_msg(message, mock_webview)
|
|
1381
|
-
|
|
1382
|
-
// Get the change handler
|
|
1383
|
-
const change_handler = mock_file_system_watcher.onDidChange.mock.calls[0][0]
|
|
1384
|
-
|
|
1385
|
-
// Trigger file change
|
|
1386
|
-
await change_handler()
|
|
1387
|
-
|
|
1388
|
-
// Wait for postMessage to be called (it's async)
|
|
1389
|
-
await vi.waitFor(() => {
|
|
1390
|
-
expect(mock_webview.postMessage).toHaveBeenCalledWith({
|
|
1391
|
-
command: `fileUpdated`,
|
|
1392
|
-
data: expect.objectContaining({
|
|
1393
|
-
filename: `file.cif`,
|
|
1394
|
-
content: `mock content`,
|
|
1395
|
-
is_base64: false,
|
|
1396
|
-
}),
|
|
1397
|
-
type: `structure`,
|
|
1398
|
-
...msg_args,
|
|
1399
|
-
file_path: `/test/file.cif`,
|
|
1400
|
-
theme: `light`,
|
|
1401
|
-
})
|
|
1402
|
-
})
|
|
1403
|
-
})
|
|
1404
|
-
|
|
1405
|
-
test(`should handle file deletion notifications`, async () => {
|
|
1406
|
-
const message = {
|
|
1407
|
-
command: `startWatching` as const,
|
|
1408
|
-
...msg_args,
|
|
1409
|
-
file_path: `/test/file.cif`,
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
await handle_msg(message, mock_webview)
|
|
1413
|
-
|
|
1414
|
-
// Get the delete handler
|
|
1415
|
-
const delete_handler = mock_file_system_watcher.onDidDelete.mock.calls[0][0]
|
|
1416
|
-
|
|
1417
|
-
// Trigger file deletion
|
|
1418
|
-
delete_handler()
|
|
1419
|
-
|
|
1420
|
-
expect(mock_webview.postMessage).toHaveBeenCalledWith(
|
|
1421
|
-
expect.objectContaining({
|
|
1422
|
-
command: `fileDeleted`,
|
|
1423
|
-
file_path: `/test/file.cif`,
|
|
1424
|
-
}),
|
|
1425
|
-
)
|
|
1426
|
-
})
|
|
1427
|
-
})
|
|
1428
|
-
|
|
1429
|
-
describe(`lifecycle management`, () => {
|
|
1430
|
-
test(`should handle activation gracefully`, () => {
|
|
1431
|
-
const mock_context = {
|
|
1432
|
-
extensionUri: { fsPath: `/test/extension` },
|
|
1433
|
-
subscriptions: [],
|
|
1434
|
-
} as unknown as ExtensionContext
|
|
1435
|
-
|
|
1436
|
-
expect(() => activate(mock_context)).not.toThrow()
|
|
1437
|
-
|
|
1438
|
-
expect(mock_vscode.commands.registerCommand).toHaveBeenCalledWith(
|
|
1439
|
-
`matterviz.open`,
|
|
1440
|
-
expect.any(Function),
|
|
1441
|
-
)
|
|
1442
|
-
})
|
|
1443
|
-
})
|
|
1444
|
-
})
|
|
1445
|
-
|
|
1446
|
-
describe(`Auto-Render Functionality`, () => {
|
|
1447
|
-
test.each([
|
|
1448
|
-
// Supported structure files
|
|
1449
|
-
[`structure.cif`, true],
|
|
1450
|
-
[`molecule.xyz`, true],
|
|
1451
|
-
[`crystal.poscar`, true],
|
|
1452
|
-
[`data.json`, false], // "data" is too broad, will not auto-render without structure-specific keywords in filename
|
|
1453
|
-
[`structure.xml`, true],
|
|
1454
|
-
[`molecule.pdb`, true],
|
|
1455
|
-
[`compound.mol`, true],
|
|
1456
|
-
[`structure.mol2`, true],
|
|
1457
|
-
[`data.sdf`, true],
|
|
1458
|
-
[`crystal.mmcif`, true],
|
|
1459
|
-
// Supported trajectory files
|
|
1460
|
-
[`trajectory.traj`, true],
|
|
1461
|
-
[`simulation.h5`, true],
|
|
1462
|
-
[`data.hdf5`, false],
|
|
1463
|
-
[`traj.xtc`, true],
|
|
1464
|
-
// Compressed supported files
|
|
1465
|
-
[`trajectory.xyz.gz`, true],
|
|
1466
|
-
[`data.json.gz`, false], // "data" is too broad, will not auto-render without structure-specific keywords in filename
|
|
1467
|
-
[`structure.cif.gz`, true],
|
|
1468
|
-
// Special filenames
|
|
1469
|
-
[`POSCAR`, true],
|
|
1470
|
-
[`CONTCAR`, true],
|
|
1471
|
-
[`XDATCAR`, true],
|
|
1472
|
-
[`trajectory.dat`, true],
|
|
1473
|
-
[`md.xyz`, true],
|
|
1474
|
-
[`relax.out`, true],
|
|
1475
|
-
[`npt.log`, true],
|
|
1476
|
-
[`nvt.data`, true],
|
|
1477
|
-
[`nve.traj`, true],
|
|
1478
|
-
// Files with special characters
|
|
1479
|
-
[`structure (1).cif`, true],
|
|
1480
|
-
[`trajectory[test].xyz.gz`, true],
|
|
1481
|
-
[`crystal@test.poscar`, true],
|
|
1482
|
-
[`molecule#test.xyz`, true],
|
|
1483
|
-
[`structure$test.json`, true],
|
|
1484
|
-
[`trajectory%test.h5`, true],
|
|
1485
|
-
[`crystal^test.traj`, true],
|
|
1486
|
-
[`molecule&test.extxyz`, true],
|
|
1487
|
-
[`structure*test.xml`, true],
|
|
1488
|
-
[`trajectory+test.pdb`, true],
|
|
1489
|
-
[`crystal=test.mol`, true],
|
|
1490
|
-
[`molecule|test.mol2`, true],
|
|
1491
|
-
[`structure\`test.sdf`, true],
|
|
1492
|
-
[`trajectory~test.mmcif`, true],
|
|
1493
|
-
// Case sensitivity tests
|
|
1494
|
-
[`STRUCTURE.CIF`, true],
|
|
1495
|
-
[`structure.CIF`, true],
|
|
1496
|
-
[`Structure.cif`, true],
|
|
1497
|
-
[`TRAJECTORY.XYZ`, true],
|
|
1498
|
-
[`trajectory.XYZ`, true],
|
|
1499
|
-
[`Trajectory.xyz`, true],
|
|
1500
|
-
[`POSCAR`, true],
|
|
1501
|
-
[`poscar`, true],
|
|
1502
|
-
[`Poscar`, true],
|
|
1503
|
-
[`CONTCAR`, true],
|
|
1504
|
-
[`contcar`, true],
|
|
1505
|
-
[`Contcar`, true],
|
|
1506
|
-
[`XDATCAR`, true],
|
|
1507
|
-
[`xdatcar`, true],
|
|
1508
|
-
[`Xdatcar`, true],
|
|
1509
|
-
// Fermi surface files
|
|
1510
|
-
[`band.bxsf`, true],
|
|
1511
|
-
[`fermi.frmsf`, true],
|
|
1512
|
-
[`BAND.BXSF`, true],
|
|
1513
|
-
[`fermi.FRMSF`, true],
|
|
1514
|
-
[`band.bxsf.gz`, true],
|
|
1515
|
-
[`fermi.frmsf.gz`, true],
|
|
1516
|
-
// Volumetric data files
|
|
1517
|
-
...volumetric_auto_render_filenames,
|
|
1518
|
-
[`DENSITY.CUBE`, true],
|
|
1519
|
-
[`CHGCAR.lobster`, true],
|
|
1520
|
-
// Files that look like structure files but are supported
|
|
1521
|
-
[`structure_copy.cif`, true],
|
|
1522
|
-
[`trajectory_backup.xyz`, true],
|
|
1523
|
-
[`trajectory.log`, true], // Contains "trajectory" keyword
|
|
1524
|
-
// Very long filenames
|
|
1525
|
-
[`structure`.repeat(100) + `.cif`, true],
|
|
1526
|
-
// Unsupported files
|
|
1527
|
-
[`config.yaml`, false],
|
|
1528
|
-
[`simulation.trr`, false], // .trr files not supported
|
|
1529
|
-
[`md.dcd`, false], // .dcd files not supported
|
|
1530
|
-
[`document.txt`, false],
|
|
1531
|
-
[`script.py`, false],
|
|
1532
|
-
[`data.csv`, false],
|
|
1533
|
-
[`image.png`, false],
|
|
1534
|
-
[`archive.zip`, false],
|
|
1535
|
-
[`fake.gz`, false],
|
|
1536
|
-
[`config.ini`, false],
|
|
1537
|
-
[`log.txt`, false],
|
|
1538
|
-
[`README.md`, false],
|
|
1539
|
-
[`readme.md`, false],
|
|
1540
|
-
[`ReadMe.Md`, false],
|
|
1541
|
-
[`vite.config.ts`, false],
|
|
1542
|
-
[`test.spec.ts`, false],
|
|
1543
|
-
[`index.html`, false],
|
|
1544
|
-
[`style.css`, false],
|
|
1545
|
-
[`app.js`, false],
|
|
1546
|
-
[`data.sql`, false],
|
|
1547
|
-
[`backup.tar`, false],
|
|
1548
|
-
[`compressed.7z`, false],
|
|
1549
|
-
[`binary.bin`, false],
|
|
1550
|
-
[`.pre-commit-config.yaml`, false],
|
|
1551
|
-
[`changelog.md`, false],
|
|
1552
|
-
[`.prettierrc`, false],
|
|
1553
|
-
[`.gitignore`, false],
|
|
1554
|
-
[`dockerfile`, false],
|
|
1555
|
-
[`makefile`, false],
|
|
1556
|
-
[`.env`, false],
|
|
1557
|
-
[`.env.local`, false],
|
|
1558
|
-
[`.env.production`, false],
|
|
1559
|
-
[`.github/workflows/ci.yml`, false],
|
|
1560
|
-
[`dist/bundle.js`, false],
|
|
1561
|
-
[`build/index.html`, false],
|
|
1562
|
-
[`coverage/lcov.info`, false],
|
|
1563
|
-
[`.cache/build.js`, false],
|
|
1564
|
-
[`structure.json.bak`, false],
|
|
1565
|
-
[`crystal.poscar.lock`, true],
|
|
1566
|
-
[`simulation.log`, true],
|
|
1567
|
-
[`backup.old`, false],
|
|
1568
|
-
[`original.orig`, false],
|
|
1569
|
-
[`patch.diff`, false],
|
|
1570
|
-
[`structure.txt`, false],
|
|
1571
|
-
[`crystal.md`, false],
|
|
1572
|
-
[`molecule.doc`, false],
|
|
1573
|
-
[`poscar.bak`, true],
|
|
1574
|
-
[`contcar.old`, true],
|
|
1575
|
-
[`document.txt.gz`, false],
|
|
1576
|
-
[`script.py.gz`, false],
|
|
1577
|
-
[`data.csv.gz`, false],
|
|
1578
|
-
[`image.png.gz`, false],
|
|
1579
|
-
[`archive.zip.gz`, false],
|
|
1580
|
-
[`structure.cif.bz2`, false],
|
|
1581
|
-
[`density.cube.bz2`, false],
|
|
1582
|
-
[`PARCHG.bz2`, false],
|
|
1583
|
-
[`myCHGCARfile`, false],
|
|
1584
|
-
[`prefixPARCHGsuffix`, false],
|
|
1585
|
-
[`structure.cif.bak`, false],
|
|
1586
|
-
[`crystal.poscar.old`, true],
|
|
1587
|
-
[`molecule.xyz~`, false],
|
|
1588
|
-
[`structure.cif.swp`, false],
|
|
1589
|
-
[`DOCUMENT.TXT`, false],
|
|
1590
|
-
[`document.TXT`, false],
|
|
1591
|
-
[`Document.txt`, false],
|
|
1592
|
-
[`SCRIPT.PY`, false],
|
|
1593
|
-
[`script.PY`, false],
|
|
1594
|
-
[`Script.py`, false],
|
|
1595
|
-
[`DATA.CSV`, false],
|
|
1596
|
-
[`data.CSV`, false],
|
|
1597
|
-
[`Data.csv`, false],
|
|
1598
|
-
// Configuration files that should never auto-render
|
|
1599
|
-
[`package.json`, false],
|
|
1600
|
-
[`tsconfig.json`, false],
|
|
1601
|
-
[`vite.config.ts`, false],
|
|
1602
|
-
[`webpack.config.js`, false],
|
|
1603
|
-
[`rollup.config.js`, false],
|
|
1604
|
-
[`eslint.config.js`, false],
|
|
1605
|
-
[`prettier.config.js`, false],
|
|
1606
|
-
[`babel.config.js`, false],
|
|
1607
|
-
[`jest.config.js`, false],
|
|
1608
|
-
[`karma.conf.js`, false],
|
|
1609
|
-
[`cypress.json`, false],
|
|
1610
|
-
[`playwright.config.ts`, false],
|
|
1611
|
-
[`.eslintrc.json`, false],
|
|
1612
|
-
[`.prettierrc`, false],
|
|
1613
|
-
[`.babelrc`, false],
|
|
1614
|
-
[`.jest.config.js`, false],
|
|
1615
|
-
[`.karma.conf.js`, false],
|
|
1616
|
-
[`.cypress.json`, false],
|
|
1617
|
-
[`.playwright.config.ts`, false],
|
|
1618
|
-
[`.npmrc`, false],
|
|
1619
|
-
[`.yarnrc`, false],
|
|
1620
|
-
[`.vscode/settings.json`, false],
|
|
1621
|
-
[`.idea/workspace.xml`, false],
|
|
1622
|
-
[`.nyc_output/coverage.json`, false],
|
|
1623
|
-
[`.tmp/temp.json`, false],
|
|
1624
|
-
[`.temp/structure.json`, false],
|
|
1625
|
-
[`node_modules/package.json`, false],
|
|
1626
|
-
// Edge cases
|
|
1627
|
-
[``, false],
|
|
1628
|
-
[` `, false],
|
|
1629
|
-
[`.`, false],
|
|
1630
|
-
[`..`, false],
|
|
1631
|
-
[`/`, false],
|
|
1632
|
-
[`\\`, false],
|
|
1633
|
-
[`a`.repeat(1000) + `.txt`, false],
|
|
1634
|
-
// Null/undefined inputs
|
|
1635
|
-
[null as unknown as string, false],
|
|
1636
|
-
[undefined as unknown as string, false],
|
|
1637
|
-
])(`should detect auto-render for "%s" as %s`, (filename, expected) => {
|
|
1638
|
-
expect(should_auto_render(filename)).toBe(expected)
|
|
1639
|
-
})
|
|
1640
|
-
|
|
1641
|
-
test(`should register auto-render functionality`, () => {
|
|
1642
|
-
const mock_context = {
|
|
1643
|
-
subscriptions: { push: vi.fn() },
|
|
1644
|
-
} as unknown as ExtensionContext
|
|
1645
|
-
activate(mock_context)
|
|
1646
|
-
expect(mock_vscode.workspace.onDidOpenTextDocument).toHaveBeenCalledWith(
|
|
1647
|
-
expect.any(Function),
|
|
1648
|
-
)
|
|
1649
|
-
})
|
|
1650
|
-
|
|
1651
|
-
test(`should handle rapid file detection efficiently`, () => {
|
|
1652
|
-
const filenames = Array.from({ length: 100 }, (_, idx) => `test_${idx}.cif`)
|
|
1653
|
-
const start = performance.now()
|
|
1654
|
-
filenames.forEach(should_auto_render)
|
|
1655
|
-
expect(performance.now() - start).toBeLessThan(10)
|
|
1656
|
-
})
|
|
1657
|
-
|
|
1658
|
-
test(`should not trigger on non-file URIs`, () => {
|
|
1659
|
-
const mock_context = {
|
|
1660
|
-
subscriptions: { push: vi.fn() },
|
|
1661
|
-
} as unknown as ExtensionContext
|
|
1662
|
-
|
|
1663
|
-
activate(mock_context)
|
|
1664
|
-
|
|
1665
|
-
// Get the registered callback
|
|
1666
|
-
const open_doc_calls = mock_vscode.workspace.onDidOpenTextDocument.mock
|
|
1667
|
-
.calls as unknown as unknown[][]
|
|
1668
|
-
const on_did_open_text_document_callback = open_doc_calls[0]?.[0] as
|
|
1669
|
-
| ((doc: unknown) => void)
|
|
1670
|
-
| undefined
|
|
1671
|
-
expect(on_did_open_text_document_callback).toBeDefined()
|
|
1672
|
-
|
|
1673
|
-
// Mock document with non-file URI
|
|
1674
|
-
const mock_document = {
|
|
1675
|
-
uri: { scheme: `untitled` },
|
|
1676
|
-
}
|
|
1677
|
-
|
|
1678
|
-
expect(() => on_did_open_text_document_callback?.(mock_document)).not.toThrow()
|
|
1679
|
-
})
|
|
1680
|
-
|
|
1681
|
-
test(`should respect auto_render configuration setting`, () => {
|
|
1682
|
-
const mock_context = {
|
|
1683
|
-
subscriptions: { push: vi.fn() },
|
|
1684
|
-
} as unknown as ExtensionContext
|
|
1685
|
-
|
|
1686
|
-
// Mock configuration to disable auto_render
|
|
1687
|
-
mock_vscode.workspace.getConfiguration.mockReturnValue({
|
|
1688
|
-
get: vi.fn((key: string, default_val: string) => {
|
|
1689
|
-
if (key === `auto_render`) return false
|
|
1690
|
-
return default_val
|
|
1691
|
-
}),
|
|
1692
|
-
})
|
|
1693
|
-
|
|
1694
|
-
activate(mock_context)
|
|
1695
|
-
|
|
1696
|
-
const open_doc_calls = mock_vscode.workspace.onDidOpenTextDocument.mock
|
|
1697
|
-
.calls as unknown as unknown[][]
|
|
1698
|
-
const on_did_open_text_document_callback = open_doc_calls[0]?.[0] as
|
|
1699
|
-
| ((doc: unknown) => void)
|
|
1700
|
-
| undefined
|
|
1701
|
-
expect(on_did_open_text_document_callback).toBeDefined()
|
|
1702
|
-
|
|
1703
|
-
// Mock document with supported file
|
|
1704
|
-
const mock_document = {
|
|
1705
|
-
uri: { scheme: `file`, fsPath: `/test/structure.cif` },
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
expect(() => on_did_open_text_document_callback?.(mock_document)).not.toThrow()
|
|
1709
|
-
})
|
|
1710
|
-
|
|
1711
|
-
test(`should handle file reading errors gracefully during auto-render`, async () => {
|
|
1712
|
-
const mock_context = {
|
|
1713
|
-
subscriptions: { push: vi.fn() },
|
|
1714
|
-
} as unknown as ExtensionContext
|
|
1715
|
-
|
|
1716
|
-
// Mock vscode.workspace.fs.stat to throw an error
|
|
1717
|
-
mock_vscode.workspace.fs.stat.mockRejectedValue(new Error(`File not found`))
|
|
1718
|
-
|
|
1719
|
-
// Enable auto_render in config
|
|
1720
|
-
mock_vscode.workspace.getConfiguration.mockReturnValue({
|
|
1721
|
-
get: vi.fn((_key: string, default_val: string) =>
|
|
1722
|
-
_key === `auto_render` ? `true` : default_val,
|
|
1723
|
-
),
|
|
1724
|
-
})
|
|
1725
|
-
|
|
1726
|
-
activate(mock_context)
|
|
1727
|
-
|
|
1728
|
-
const open_doc_calls = mock_vscode.workspace.onDidOpenTextDocument.mock
|
|
1729
|
-
.calls as unknown as unknown[][]
|
|
1730
|
-
const on_did_open_text_document_callback = open_doc_calls[0]?.[0] as
|
|
1731
|
-
| ((doc: unknown) => void)
|
|
1732
|
-
| undefined
|
|
1733
|
-
expect(on_did_open_text_document_callback).toBeDefined()
|
|
1734
|
-
|
|
1735
|
-
// Mock document with supported file
|
|
1736
|
-
const mock_document = {
|
|
1737
|
-
uri: { scheme: `file`, fsPath: `/test/structure.cif` },
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
// Should show error message when file reading fails
|
|
1741
|
-
expect(() => on_did_open_text_document_callback?.(mock_document)).not.toThrow()
|
|
1742
|
-
|
|
1743
|
-
await vi.waitFor(() => {
|
|
1744
|
-
expect(mock_vscode.window.showErrorMessage).toHaveBeenCalledWith(
|
|
1745
|
-
expect.stringContaining(`MatterViz auto-render failed:`),
|
|
1746
|
-
)
|
|
1747
|
-
})
|
|
1748
|
-
})
|
|
1749
|
-
})
|
|
1750
|
-
|
|
1751
|
-
describe(`Multi-frame xyz/extxyz handling`, () => {
|
|
1752
|
-
test(`should correctly identify multi-frame XYZ as trajectory using content`, () => {
|
|
1753
|
-
// Multi-frame XYZ content (2 frames)
|
|
1754
|
-
const multi_frame_xyz_content = `3
|
|
1755
|
-
frame 1
|
|
1756
|
-
H 0.0 0.0 0.0
|
|
1757
|
-
O 0.0 0.0 1.0
|
|
1758
|
-
H 0.0 1.0 0.0
|
|
1759
|
-
3
|
|
1760
|
-
frame 2
|
|
1761
|
-
H 0.1 0.0 0.0
|
|
1762
|
-
O 0.0 0.1 1.0
|
|
1763
|
-
H 0.0 1.0 0.1`
|
|
1764
|
-
|
|
1765
|
-
// Single-frame XYZ content
|
|
1766
|
-
const single_frame_xyz_content = `3
|
|
1767
|
-
water molecule
|
|
1768
|
-
H 0.0 0.0 0.0
|
|
1769
|
-
O 0.0 0.0 1.0
|
|
1770
|
-
H 0.0 1.0 0.0`
|
|
1771
|
-
|
|
1772
|
-
// Test 1: Verify is_trajectory_file directly detects multi-frame content
|
|
1773
|
-
expect(is_trajectory_file(`multi-frame.xyz`, multi_frame_xyz_content)).toBe(true)
|
|
1774
|
-
expect(is_trajectory_file(`single-frame.xyz`, single_frame_xyz_content)).toBe(false)
|
|
1775
|
-
|
|
1776
|
-
// Test 2: Verify filename-only detection doesn't identify .xyz as trajectory
|
|
1777
|
-
expect(is_trajectory_file(`multi-frame.xyz`)).toBe(false) // filename-only should be false
|
|
1778
|
-
expect(is_trajectory_file(`single-frame.xyz`)).toBe(false) // filename-only should be false
|
|
1779
|
-
|
|
1780
|
-
// Test 3: Test with FileData objects (simulating what infer_view_type receives)
|
|
1781
|
-
const multi_frame_file: FileData = {
|
|
1782
|
-
filename: `multi-frame.xyz`,
|
|
1783
|
-
content: multi_frame_xyz_content,
|
|
1784
|
-
is_base64: false,
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
const single_frame_file: FileData = {
|
|
1788
|
-
filename: `single-frame.xyz`,
|
|
1789
|
-
content: single_frame_xyz_content,
|
|
1790
|
-
is_base64: false,
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
const compressed_file: FileData = {
|
|
1794
|
-
filename: `trajectory.xyz.gz`,
|
|
1795
|
-
content: `base64encodedcontent`,
|
|
1796
|
-
is_base64: true,
|
|
1797
|
-
}
|
|
1798
|
-
|
|
1799
|
-
// Test what infer_view_type logic would do:
|
|
1800
|
-
// For non-compressed files, pass content
|
|
1801
|
-
expect(is_trajectory_file(multi_frame_file.filename, multi_frame_file.content)).toBe(
|
|
1802
|
-
true,
|
|
1803
|
-
)
|
|
1804
|
-
expect(is_trajectory_file(single_frame_file.filename, single_frame_file.content)).toBe(
|
|
1805
|
-
false,
|
|
1806
|
-
)
|
|
1807
|
-
|
|
1808
|
-
// For compressed files, don't pass content (falls back to filename-only)
|
|
1809
|
-
expect(is_trajectory_file(compressed_file.filename)).toBe(true) // .xyz.gz with trajectory keyword is detected as trajectory by filename
|
|
1810
|
-
|
|
1811
|
-
// Test 4: Test webview creation scenario directly with content-based detection
|
|
1812
|
-
const multi_frame_html = create_html(mock_webview, mock_context, {
|
|
1813
|
-
type: is_trajectory_file(multi_frame_file.filename, multi_frame_file.content)
|
|
1814
|
-
? `trajectory`
|
|
1815
|
-
: `structure`,
|
|
1816
|
-
data: multi_frame_file,
|
|
1817
|
-
theme: `light`,
|
|
1818
|
-
})
|
|
1819
|
-
|
|
1820
|
-
const multi_frame_parsed_data = JSON.parse(
|
|
1821
|
-
/matterviz_data=(\{[\s\S]*?\});/.exec(multi_frame_html)?.[1] ?? `{}`,
|
|
1822
|
-
)
|
|
1823
|
-
|
|
1824
|
-
expect(multi_frame_parsed_data.type).toBe(`trajectory`)
|
|
1825
|
-
expect(multi_frame_parsed_data.data.filename).toBe(`multi-frame.xyz`)
|
|
1826
|
-
expect(multi_frame_parsed_data.data.content).toBe(multi_frame_xyz_content)
|
|
1827
|
-
|
|
1828
|
-
// Test 5: Test single-frame for comparison
|
|
1829
|
-
const single_frame_html = create_html(mock_webview, mock_context, {
|
|
1830
|
-
type: is_trajectory_file(single_frame_file.filename, single_frame_file.content)
|
|
1831
|
-
? `trajectory`
|
|
1832
|
-
: `structure`,
|
|
1833
|
-
data: single_frame_file,
|
|
1834
|
-
theme: `light`,
|
|
1835
|
-
})
|
|
1836
|
-
|
|
1837
|
-
const single_frame_parsed_data = JSON.parse(
|
|
1838
|
-
/matterviz_data=(\{[\s\S]*?\});/.exec(single_frame_html)?.[1] ?? `{}`,
|
|
1839
|
-
)
|
|
1840
|
-
|
|
1841
|
-
expect(single_frame_parsed_data.type).toBe(`structure`)
|
|
1842
|
-
|
|
1843
|
-
// Test 6: Test compressed file falls back correctly
|
|
1844
|
-
const compressed_html = create_html(mock_webview, mock_context, {
|
|
1845
|
-
type: is_trajectory_file(compressed_file.filename) ? `trajectory` : `structure`,
|
|
1846
|
-
data: compressed_file,
|
|
1847
|
-
theme: `light`,
|
|
1848
|
-
})
|
|
1849
|
-
|
|
1850
|
-
const compressed_parsed_data = JSON.parse(
|
|
1851
|
-
/matterviz_data=(\{[\s\S]*?\});/.exec(compressed_html)?.[1] ?? `{}`,
|
|
1852
|
-
)
|
|
1853
|
-
|
|
1854
|
-
expect(compressed_parsed_data.type).toBe(`trajectory`) // Should be trajectory since filename contains trajectory keyword
|
|
1855
|
-
})
|
|
1856
|
-
|
|
1857
|
-
test(`should handle compressed XYZ files by falling back to filename-only detection`, () => {
|
|
1858
|
-
// Test compressed file (should fall back to filename-only detection)
|
|
1859
|
-
const compressed_file = {
|
|
1860
|
-
filename: `trajectory.xyz.gz`,
|
|
1861
|
-
content: `base64encodedcontent`, // This is binary/compressed
|
|
1862
|
-
is_base64: true,
|
|
1863
|
-
}
|
|
1864
|
-
|
|
1865
|
-
// For compressed files, infer_view_type should fall back to filename-only detection
|
|
1866
|
-
// Since .xyz.gz with trajectory keyword is detected as trajectory by filename, it should be 'trajectory'
|
|
1867
|
-
expect(is_trajectory_file(compressed_file.filename)).toBe(true) // filename-only detection
|
|
1868
|
-
|
|
1869
|
-
// Test the HTML generation scenario
|
|
1870
|
-
const html = create_html(mock_webview, mock_context, {
|
|
1871
|
-
type: is_trajectory_file(compressed_file.filename) ? `trajectory` : `structure`,
|
|
1872
|
-
data: compressed_file,
|
|
1873
|
-
theme: `light`,
|
|
1874
|
-
})
|
|
1875
|
-
|
|
1876
|
-
const parsed_data = JSON.parse(/matterviz_data=(\{[\s\S]*?\});/.exec(html)?.[1] ?? `{}`)
|
|
1877
|
-
|
|
1878
|
-
// Should be 'trajectory' since filename contains trajectory keyword
|
|
1879
|
-
expect(parsed_data.type).toBe(`trajectory`)
|
|
1880
|
-
})
|
|
1881
|
-
})
|
|
1882
|
-
|
|
1883
|
-
describe(`Default Settings`, () => {
|
|
1884
|
-
// Helper to create mock config and test setting
|
|
1885
|
-
const test_setting = (
|
|
1886
|
-
result_path: string,
|
|
1887
|
-
expected_value: unknown,
|
|
1888
|
-
config_key: string,
|
|
1889
|
-
) => {
|
|
1890
|
-
const parts = config_key.split(`.`)
|
|
1891
|
-
|
|
1892
|
-
const mock_config = {
|
|
1893
|
-
get: vi.fn((key: string, default_val?: unknown): unknown => {
|
|
1894
|
-
if (parts.length === 2 && key === parts[0]) {
|
|
1895
|
-
return { [parts[1]]: expected_value }
|
|
1896
|
-
} else if (parts.length === 1 && key === parts[0]) return expected_value
|
|
1897
|
-
return default_val
|
|
1898
|
-
}),
|
|
1899
|
-
}
|
|
1900
|
-
// @ts-expect-error: Mock type override needed for testing
|
|
1901
|
-
mock_vscode.workspace.getConfiguration.mockReturnValue(mock_config)
|
|
1902
|
-
|
|
1903
|
-
const result = get_defaults()
|
|
1904
|
-
const value = result_path
|
|
1905
|
-
.split(`.`)
|
|
1906
|
-
.reduce(
|
|
1907
|
-
(obj: Record<string, unknown>, key: string) => obj?.[key] as Record<string, unknown>,
|
|
1908
|
-
result,
|
|
1909
|
-
)
|
|
1910
|
-
|
|
1911
|
-
return Array.isArray(expected_value)
|
|
1912
|
-
? expect(value).toEqual(expected_value)
|
|
1913
|
-
: expect(value).toBe(expected_value)
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
test(`should merge user settings with defaults`, () => {
|
|
1917
|
-
const user_config = {
|
|
1918
|
-
structure: { atom_radius: 1.5, show_bonds: `always`, bond_color: `#ff0000` },
|
|
1919
|
-
trajectory: { auto_play: true },
|
|
1920
|
-
}
|
|
1921
|
-
const mock_config = {
|
|
1922
|
-
get: vi.fn((key: string, default_val?: unknown) => {
|
|
1923
|
-
if (key === `structure`) return user_config.structure
|
|
1924
|
-
if (key === `trajectory`) return user_config.trajectory
|
|
1925
|
-
return default_val
|
|
1926
|
-
}),
|
|
1927
|
-
}
|
|
1928
|
-
// @ts-expect-error: Mock type override needed for testing
|
|
1929
|
-
mock_vscode.workspace.getConfiguration.mockReturnValue(mock_config)
|
|
1930
|
-
|
|
1931
|
-
const result = get_defaults()
|
|
1932
|
-
|
|
1933
|
-
expect(result.structure.atom_radius).toBe(1.5)
|
|
1934
|
-
expect(result.structure.show_bonds).toBe(`always`)
|
|
1935
|
-
expect(result.structure.bond_color).toBe(`#ff0000`)
|
|
1936
|
-
expect(result.trajectory.auto_play).toBe(true)
|
|
1937
|
-
expect(result.structure.same_size_atoms).toBe(false) // Falls back to default
|
|
1938
|
-
})
|
|
1939
|
-
|
|
1940
|
-
test.each([
|
|
1941
|
-
// Numbers
|
|
1942
|
-
[`structure.atom_radius`, 1.5],
|
|
1943
|
-
[`structure.sphere_segments`, 24],
|
|
1944
|
-
[`structure.bond_thickness`, 0.2],
|
|
1945
|
-
[`structure.rotation_damping`, 0.2],
|
|
1946
|
-
[`structure.zoom_speed`, 1.0],
|
|
1947
|
-
[`structure.pan_speed`, 1.0],
|
|
1948
|
-
[`structure.auto_rotate`, 2.0],
|
|
1949
|
-
[`structure.site_label_size`, 14],
|
|
1950
|
-
[`structure.site_label_padding`, 4],
|
|
1951
|
-
[`structure.ambient_light`, 0.6],
|
|
1952
|
-
[`structure.directional_light`, 0.8],
|
|
1953
|
-
[`structure.vector_scale`, 2.0],
|
|
1954
|
-
[`structure.vector_origin_gap`, 0.25],
|
|
1955
|
-
[`structure.cell_edge_opacity`, 0.5],
|
|
1956
|
-
[`structure.cell_surface_opacity`, 0.2],
|
|
1957
|
-
[`background_opacity`, 0.8],
|
|
1958
|
-
[`trajectory.fps`, 10],
|
|
1959
|
-
[`trajectory.step_labels`, 10],
|
|
1960
|
-
|
|
1961
|
-
// Booleans
|
|
1962
|
-
[`structure.same_size_atoms`, true],
|
|
1963
|
-
[`structure.show_atoms`, false],
|
|
1964
|
-
[`structure.show_bonds`, `always`],
|
|
1965
|
-
[`structure.show_site_labels`, true],
|
|
1966
|
-
[`structure.show_cell`, true],
|
|
1967
|
-
[`structure.show_cell_vectors`, true],
|
|
1968
|
-
[`structure.show_image_atoms`, true],
|
|
1969
|
-
[`structure.show_gizmo`, false],
|
|
1970
|
-
[`trajectory.auto_play`, true],
|
|
1971
|
-
[`trajectory.show_controls`, false],
|
|
1972
|
-
|
|
1973
|
-
// Colors (strings)
|
|
1974
|
-
[`structure.bond_color`, `#ff0000`],
|
|
1975
|
-
[`structure.site_label_color`, `#00ff00`],
|
|
1976
|
-
[`structure.site_label_bg_color`, `#333333`],
|
|
1977
|
-
[`structure.cell_edge_color`, `#aaaaaa`],
|
|
1978
|
-
[`structure.cell_surface_color`, `#bbbbbb`],
|
|
1979
|
-
[`structure.vector_color`, `#ffff00`],
|
|
1980
|
-
[`background_color`, `#111111`],
|
|
1981
|
-
|
|
1982
|
-
// String enums
|
|
1983
|
-
[`structure.bonding_strategy`, `solid_angle`],
|
|
1984
|
-
[`structure.camera_projection`, `orthographic`],
|
|
1985
|
-
[`color_scheme`, `Jmol`],
|
|
1986
|
-
[`composition.color_scheme`, `Alloy`],
|
|
1987
|
-
[`trajectory.display_mode`, `scatter`],
|
|
1988
|
-
[`trajectory.layout`, `vertical`],
|
|
1989
|
-
[`composition.display_mode`, `bar`],
|
|
1990
|
-
|
|
1991
|
-
// Arrays
|
|
1992
|
-
[`structure.camera_position`, [1, 2, 3]],
|
|
1993
|
-
[`structure.site_label_offset`, [0.5, 1.0, 0]],
|
|
1994
|
-
[`trajectory.fps_range`, [0.5, 60]],
|
|
1995
|
-
])(`should handle setting: %s = %s`, (result_path, expected_value) => {
|
|
1996
|
-
test_setting(result_path, expected_value, result_path)
|
|
1997
|
-
})
|
|
1998
|
-
|
|
1999
|
-
test.each([
|
|
2000
|
-
[{ get: vi.fn(() => undefined) }, `missing config`],
|
|
2001
|
-
[
|
|
2002
|
-
{
|
|
2003
|
-
get: vi.fn((key: string, default_val?: unknown) =>
|
|
2004
|
-
key === `defaults`
|
|
2005
|
-
? {
|
|
2006
|
-
structure: {
|
|
2007
|
-
atom_radius: `invalid`,
|
|
2008
|
-
show_bonds: `invalid-value`,
|
|
2009
|
-
bond_color: 123,
|
|
2010
|
-
},
|
|
2011
|
-
}
|
|
2012
|
-
: default_val,
|
|
2013
|
-
),
|
|
2014
|
-
},
|
|
2015
|
-
`invalid values`,
|
|
2016
|
-
],
|
|
2017
|
-
])(`should handle %s gracefully`, (mock_config, _description) => {
|
|
2018
|
-
// @ts-expect-error: Mock type override needed for testing
|
|
2019
|
-
mock_vscode.workspace.getConfiguration.mockReturnValue(mock_config)
|
|
2020
|
-
|
|
2021
|
-
expect(() => get_defaults()).not.toThrow()
|
|
2022
|
-
const result = get_defaults()
|
|
2023
|
-
|
|
2024
|
-
expect(result).toEqual(
|
|
2025
|
-
expect.objectContaining({
|
|
2026
|
-
structure: expect.any(Object),
|
|
2027
|
-
trajectory: expect.any(Object),
|
|
2028
|
-
composition: expect.any(Object),
|
|
2029
|
-
}),
|
|
2030
|
-
)
|
|
2031
|
-
})
|
|
2032
|
-
|
|
2033
|
-
test(`should handle workspace config errors`, () => {
|
|
2034
|
-
mock_vscode.workspace.getConfiguration.mockImplementation(() => {
|
|
2035
|
-
throw new Error(`Config access failed`)
|
|
2036
|
-
})
|
|
2037
|
-
|
|
2038
|
-
expect(() => get_defaults()).not.toThrow()
|
|
2039
|
-
})
|
|
2040
|
-
})
|
|
2041
|
-
})
|