@jbrowse/core 5.0.0-beta.1 → 5.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1709 -390
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.d.ts +3 -2
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +5 -5
- package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts +3 -5
- package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.js +34 -29
- package/esm/BaseFeatureWidget/BaseFeatureDetail/BaseCard.js +1 -4
- package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.d.ts +11 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.js +37 -14
- package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.d.ts +1 -1
- package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.js +15 -31
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +4 -3
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.js +12 -25
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetailsFrame.d.ts +11 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetailsFrame.js +11 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.d.ts +8 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.js +24 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/Formatter.js +6 -4
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.d.ts +3 -2
- package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.js +5 -3
- package/esm/BaseFeatureWidget/BaseFeatureDetail/index.d.ts +6 -2
- package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +7 -18
- package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.d.ts +16 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +49 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/util.d.ts +0 -8
- package/esm/BaseFeatureWidget/BaseFeatureDetail/util.js +6 -29
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceContents.js +7 -34
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceName.js +2 -2
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/TranscriptSelector.js +3 -1
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/model.d.ts +12 -0
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/model.js +12 -5
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/useSequenceData.js +8 -5
- package/esm/BaseFeatureWidget/configSchema.d.ts +1 -1
- package/esm/BaseFeatureWidget/formatDetails.d.ts +13 -29
- package/esm/BaseFeatureWidget/formatDetails.js +62 -83
- package/esm/BaseFeatureWidget/index.d.ts +2 -1
- package/esm/BaseFeatureWidget/stateModelFactory.d.ts +42 -29
- package/esm/BaseFeatureWidget/stateModelFactory.js +98 -98
- package/esm/BaseFeatureWidget/types.d.ts +12 -6
- package/esm/BaseFeatureWidget/util.d.ts +0 -10
- package/esm/BaseFeatureWidget/util.js +0 -17
- package/esm/CorePlugin.js +34 -3
- package/esm/PluginLoader.d.ts +24 -13
- package/esm/PluginLoader.js +167 -51
- package/esm/PluginManager.d.ts +130 -24
- package/esm/PluginManager.js +180 -32
- package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
- package/esm/ReExports/MuiDataGridReExports.js +2 -2
- package/esm/ReExports/coreModules.generated.d.ts +2 -0
- package/esm/ReExports/coreModules.generated.js +530 -0
- package/esm/ReExports/coreWorkerModules.generated.d.ts +2 -0
- package/esm/ReExports/coreWorkerModules.generated.js +490 -0
- package/esm/ReExports/frameworkModules.d.ts +2 -0
- package/esm/ReExports/frameworkModules.js +68 -0
- package/esm/ReExports/frameworkShared.d.ts +12 -0
- package/esm/ReExports/frameworkShared.js +16 -0
- package/esm/ReExports/frameworkWorkerModules.generated.d.ts +2 -0
- package/esm/ReExports/frameworkWorkerModules.generated.js +130 -0
- package/esm/ReExports/list.js +528 -79
- package/esm/ReExports/modules.d.ts +1 -1
- package/esm/ReExports/modules.js +10 -165
- package/esm/ReExports/registry.d.ts +1 -0
- package/esm/ReExports/registry.js +23 -5
- package/esm/ReExports/uiStub.d.ts +3 -0
- package/esm/ReExports/uiStub.js +33 -0
- package/esm/ReExports/workerModules.d.ts +2 -0
- package/esm/ReExports/workerModules.js +11 -0
- package/esm/TextSearch/TextSearchManager.d.ts +27 -13
- package/esm/TextSearch/TextSearchManager.js +77 -36
- package/esm/TextSearch/places.d.ts +12 -0
- package/esm/TextSearch/places.js +94 -0
- package/esm/assemblyManager/assembly.d.ts +21 -19
- package/esm/assemblyManager/assembly.js +28 -26
- package/esm/assemblyManager/assemblyAdapters.d.ts +1 -1
- package/esm/assemblyManager/assemblyAdapters.js +8 -2
- package/esm/assemblyManager/assemblyConfigSchema.d.ts +31 -90
- package/esm/assemblyManager/assemblyConfigSchema.js +35 -47
- package/esm/assemblyManager/assemblyManager.d.ts +35 -180
- package/esm/assemblyManager/assemblyManager.js +47 -51
- package/esm/assemblyManager/expandAssemblyConfigShorthand.d.ts +25 -18
- package/esm/assemblyManager/expandAssemblyConfigShorthand.js +78 -49
- package/esm/assemblyManager/geneticCodes.js +2 -5
- package/esm/assemblyManager/getSequenceAdapterConfig.d.ts +10 -0
- package/esm/assemblyManager/getSequenceAdapterConfig.js +10 -0
- package/esm/assemblyManager/indexAssemblyNames.d.ts +9 -0
- package/esm/assemblyManager/indexAssemblyNames.js +22 -0
- package/esm/assemblyManager/loadRefNameMap.d.ts +1 -1
- package/esm/assemblyManager/loadRefNameMap.js +4 -9
- package/esm/assemblyManager/refNameMapKey.d.ts +7 -0
- package/esm/assemblyManager/refNameMapKey.js +12 -0
- package/esm/checkPlugins.d.ts +2 -0
- package/esm/checkPlugins.js +38 -17
- package/esm/configuration/bamIndexFields.d.ts +49 -0
- package/esm/configuration/bamIndexFields.js +41 -0
- package/esm/configuration/configurationSchema.d.ts +101 -71
- package/esm/configuration/configurationSchema.js +207 -134
- package/esm/configuration/configurationSchemaUnion.d.ts +39 -0
- package/esm/configuration/configurationSchemaUnion.js +56 -0
- package/esm/configuration/configurationSlot.d.ts +150 -60
- package/esm/configuration/configurationSlot.js +103 -75
- package/esm/configuration/fillLocations.d.ts +14 -0
- package/esm/configuration/fillLocations.js +14 -0
- package/esm/configuration/formatAboutConfigSchema.d.ts +7 -21
- package/esm/configuration/formatDetailsConfigSchema.d.ts +11 -37
- package/esm/configuration/formatDetailsConfigSchema.js +10 -13
- package/esm/configuration/fullConfSnapshot.d.ts +4 -19
- package/esm/configuration/fullConfSnapshot.js +30 -52
- package/esm/configuration/getConf.d.ts +45 -41
- package/esm/configuration/getConf.js +111 -44
- package/esm/configuration/index.d.ts +26 -11
- package/esm/configuration/index.js +16 -7
- package/esm/configuration/indexType.d.ts +26 -0
- package/esm/configuration/indexType.js +38 -0
- package/esm/configuration/mergeFormatCallbacks.d.ts +6 -7
- package/esm/configuration/mergeFormatCallbacks.js +13 -10
- package/esm/configuration/plot.d.ts +61 -0
- package/esm/configuration/plot.js +142 -0
- package/esm/configuration/readConfObject.d.ts +2 -24
- package/esm/configuration/readConfObject.js +20 -63
- package/esm/configuration/requirements.d.ts +37 -0
- package/esm/configuration/requirements.js +88 -0
- package/esm/configuration/schemaRegistry.d.ts +32 -15
- package/esm/configuration/schemaRegistry.js +33 -35
- package/esm/configuration/schemaTypes.d.ts +21 -5
- package/esm/configuration/schemaTypes.js +66 -55
- package/esm/configuration/slotFacade.d.ts +12 -29
- package/esm/configuration/slotFacade.js +44 -23
- package/esm/configuration/snapshotPreprocess.d.ts +43 -0
- package/esm/configuration/snapshotPreprocess.js +161 -0
- package/esm/configuration/tabixIndexFields.d.ts +30 -4
- package/esm/configuration/tabixIndexFields.js +21 -4
- package/esm/configuration/tabixShorthand.d.ts +34 -17
- package/esm/configuration/tabixShorthand.js +49 -22
- package/esm/configuration/types.d.ts +182 -43
- package/esm/configuration/uriShorthand.d.ts +9 -0
- package/esm/configuration/uriShorthand.js +16 -0
- package/esm/data_adapters/BaseAdapter/BaseAdapter.d.ts +13 -19
- package/esm/data_adapters/BaseAdapter/BaseAdapter.js +12 -19
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +40 -2
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +68 -5
- package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +40 -0
- package/esm/data_adapters/BaseAdapter/featureDensity.js +31 -0
- package/esm/data_adapters/BaseAdapter/index.d.ts +23 -3
- package/esm/data_adapters/BaseAdapter/index.js +1 -0
- package/esm/data_adapters/BaseAdapter/rowSources.d.ts +37 -0
- package/esm/data_adapters/BaseAdapter/rowSources.js +7 -0
- package/esm/data_adapters/BaseAdapter/stats.d.ts +33 -1
- package/esm/data_adapters/BaseAdapter/stats.js +52 -13
- package/esm/data_adapters/BaseAdapter/types.d.ts +8 -12
- package/esm/data_adapters/BaseAdapter/zoomRange.d.ts +10 -0
- package/esm/data_adapters/CytobandAdapter/CytobandAdapter.js +1 -1
- package/esm/data_adapters/CytobandAdapter/configSchema.d.ts +7 -11
- package/esm/data_adapters/CytobandAdapter/configSchema.js +3 -17
- package/esm/data_adapters/dataAdapterCache.d.ts +19 -2
- package/esm/data_adapters/dataAdapterCache.js +44 -10
- package/esm/data_adapters/getFeatureAdapter.d.ts +6 -4
- package/esm/data_adapters/getFeatureAdapter.js +8 -8
- package/esm/data_adapters/getSequenceSubAdapter.d.ts +7 -9
- package/esm/data_adapters/getSequenceSubAdapter.js +8 -10
- package/esm/pluggableElementTypes/AdapterType.d.ts +8 -8
- package/esm/pluggableElementTypes/AdapterType.js +1 -1
- package/esm/pluggableElementTypes/DisplayType.d.ts +53 -16
- package/esm/pluggableElementTypes/DisplayType.js +28 -12
- package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +32 -0
- package/esm/pluggableElementTypes/LazyStateModelElement.js +77 -0
- package/esm/pluggableElementTypes/PluggableElementBase.d.ts +3 -5
- package/esm/pluggableElementTypes/PluggableElementBase.js +3 -5
- package/esm/pluggableElementTypes/RpcMethodType.d.ts +11 -1
- package/esm/pluggableElementTypes/RpcMethodType.js +25 -9
- package/esm/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions.d.ts +1 -2
- package/esm/pluggableElementTypes/TextSearchAdapterType.d.ts +7 -7
- package/esm/pluggableElementTypes/ViewType.d.ts +20 -4
- package/esm/pluggableElementTypes/ViewType.js +32 -4
- package/esm/pluggableElementTypes/WidgetType.d.ts +6 -0
- package/esm/pluggableElementTypes/WidgetType.js +6 -0
- package/esm/pluggableElementTypes/addMenuItems.d.ts +3 -2
- package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
- package/esm/pluggableElementTypes/extendElementType.js +9 -5
- package/esm/pluggableElementTypes/index.d.ts +2 -1
- package/esm/pluggableElementTypes/index.js +2 -9
- package/esm/pluggableElementTypes/models/BaseConnectionModelFactory.d.ts +19 -9
- package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +122 -28
- package/esm/pluggableElementTypes/models/BaseDisplayModel.js +155 -11
- package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +65 -16
- package/esm/pluggableElementTypes/models/BaseTrackModel.js +179 -117
- package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +87 -18
- package/esm/pluggableElementTypes/models/BaseViewModel.js +54 -11
- package/esm/pluggableElementTypes/models/InternetAccountModel.d.ts +26 -16
- package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +15 -11
- package/esm/pluggableElementTypes/models/assertDisplayContract.js +25 -32
- package/esm/pluggableElementTypes/models/baseConnectionConfig.d.ts +22 -18
- package/esm/pluggableElementTypes/models/baseConnectionConfig.js +5 -5
- package/esm/pluggableElementTypes/models/baseInternetAccountConfig.d.ts +26 -31
- package/esm/pluggableElementTypes/models/baseTrackConfig.d.ts +108 -147
- package/esm/pluggableElementTypes/models/baseTrackConfig.js +96 -73
- package/esm/pluggableElementTypes/models/components/SaveTrackData.js +4 -6
- package/esm/pluggableElementTypes/models/components/fetchTrackData.d.ts +3 -4
- package/esm/pluggableElementTypes/models/components/fetchTrackData.js +3 -3
- package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.d.ts +23 -13
- package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.js +80 -48
- package/esm/pluggableElementTypes/models/index.d.ts +2 -3
- package/esm/pluggableElementTypes/models/index.js +2 -3
- package/esm/pluggableElementTypes/models/migrateTrackConfig.d.ts +15 -1
- package/esm/pluggableElementTypes/models/migrateTrackConfig.js +85 -25
- package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.d.ts +4 -3
- package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.js +141 -19
- package/esm/pluggableElementTypes/models/saveTrackFileTypes/types.d.ts +3 -3
- package/esm/pluginDefinitions.d.ts +34 -7
- package/esm/pluginDefinitions.js +54 -20
- package/esm/rpc/BaseRpcDriver.d.ts +2 -2
- package/esm/rpc/BaseRpcDriver.js +25 -30
- package/esm/rpc/MainThreadRpcDriver.d.ts +2 -2
- package/esm/rpc/MainThreadRpcDriver.js +13 -8
- package/esm/rpc/RpcClient.d.ts +18 -6
- package/esm/rpc/RpcClient.js +51 -16
- package/esm/rpc/RpcManager.d.ts +14 -10
- package/esm/rpc/RpcManager.js +11 -1
- package/esm/rpc/RpcRegistry.d.ts +40 -7
- package/esm/rpc/RpcServer.d.ts +3 -1
- package/esm/rpc/RpcServer.js +19 -12
- package/esm/rpc/WebWorkerRpcDriver.d.ts +11 -4
- package/esm/rpc/WebWorkerRpcDriver.js +64 -68
- package/esm/rpc/byteBudget.d.ts +20 -5
- package/esm/rpc/byteBudget.js +16 -5
- package/esm/rpc/configSchema.d.ts +7 -21
- package/esm/rpc/coreRpcMethods.d.ts +4 -0
- package/esm/rpc/coreRpcMethods.js +4 -0
- package/esm/rpc/methods/CoreGetEncodedFeature.d.ts +13 -0
- package/esm/rpc/methods/CoreGetEncodedFeature.js +32 -0
- package/esm/rpc/methods/CoreGetEncodedLayers.d.ts +16 -0
- package/esm/rpc/methods/CoreGetEncodedLayers.js +59 -0
- package/esm/rpc/methods/CoreGetExportData.js +3 -4
- package/esm/rpc/methods/CoreGetFeatureDensity.d.ts +11 -0
- package/esm/rpc/methods/CoreGetFeatureDensity.js +22 -0
- package/esm/rpc/methods/CoreGetFeatures.js +3 -5
- package/esm/rpc/methods/CoreGetRefNames.js +2 -12
- package/esm/rpc/methods/CoreGetRegionByteEstimate.js +1 -1
- package/esm/rpc/methods/CoreGetSequence.js +2 -2
- package/esm/rpc/methods/CoreLoadAdapterCode.d.ts +13 -0
- package/esm/rpc/methods/CoreLoadAdapterCode.js +16 -0
- package/esm/rpc/methods/layerFeatures.d.ts +33 -0
- package/esm/rpc/methods/layerFeatures.js +29 -0
- package/esm/svg/SvgExport.js +6 -7
- package/esm/svg/SvgThemeProviders.d.ts +12 -0
- package/esm/svg/SvgThemeProviders.js +15 -0
- package/esm/svg/exportViewSvg.d.ts +28 -0
- package/esm/svg/exportViewSvg.js +13 -0
- package/esm/svg/normalizeSvgMarkup.d.ts +7 -0
- package/esm/svg/normalizeSvgMarkup.js +99 -0
- package/esm/svg/serializeSvg.d.ts +7 -0
- package/esm/svg/serializeSvg.js +11 -0
- package/esm/svg/svgId.d.ts +1 -1
- package/esm/svg/svgId.js +1 -1
- package/esm/svg/svgReady.d.ts +9 -7
- package/esm/svg/svgReady.js +8 -7
- package/esm/svg/trackNames.d.ts +7 -5
- package/esm/svg/trackNames.js +12 -9
- package/esm/svg/wrapSvgExport.js +6 -74
- package/esm/ui/AddCustomPluginDialog.js +3 -8
- package/esm/ui/AppReadyMarker.d.ts +45 -0
- package/esm/ui/AppReadyMarker.js +89 -0
- package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
- package/esm/ui/CascadingMenu.js +181 -104
- package/esm/ui/DropDownMenu.js +2 -1
- package/esm/ui/ErrorBanner.js +1 -1
- package/esm/ui/ErrorBoundary.d.ts +2 -2
- package/esm/ui/ErrorMessageStackTraceContents.js +2 -1
- package/esm/ui/ErrorMessageStackTraceDialog.js +5 -11
- package/esm/ui/ExportSvgDialog.d.ts +1 -1
- package/esm/ui/FileDropZone.js +2 -1
- package/esm/ui/FileSelector/useInternetAccounts.d.ts +156 -96
- package/esm/ui/HoverMenu.d.ts +1 -2
- package/esm/ui/HoverMenu.js +6 -3
- package/esm/ui/JexlFilterDialog.d.ts +13 -10
- package/esm/ui/JexlFilterDialog.js +122 -50
- package/esm/ui/JexlFilterRowEditors.d.ts +15 -0
- package/esm/ui/JexlFilterRowEditors.js +90 -0
- package/esm/ui/LazyBaseTooltip.d.ts +4 -0
- package/esm/ui/LazyBaseTooltip.js +9 -0
- package/esm/ui/LegendSwatchGlyph.js +26 -21
- package/esm/ui/LoadingOverlay.d.ts +14 -0
- package/esm/ui/LoadingOverlay.js +4 -2
- package/esm/ui/MenuTypes.d.ts +23 -53
- package/esm/ui/MenuTypes.js +3 -0
- package/esm/ui/MonospaceTextField.d.ts +2 -1
- package/esm/ui/MonospaceTextField.js +23 -20
- package/esm/ui/PaletteContext.d.ts +10 -5
- package/esm/ui/PaletteContext.js +44 -6
- package/esm/ui/RefNameAutocomplete/SearchOption.d.ts +13 -0
- package/esm/ui/RefNameAutocomplete/SearchOption.js +45 -0
- package/esm/ui/RefNameAutocomplete/index.d.ts +1 -2
- package/esm/ui/RefNameAutocomplete/index.js +8 -2
- package/esm/ui/RefNameAutocomplete/util.d.ts +13 -0
- package/esm/ui/RefNameAutocomplete/util.js +42 -1
- package/esm/ui/ResizeHandle.d.ts +3 -1
- package/esm/ui/ResizeHandle.js +44 -11
- package/esm/ui/ScrollChrome.d.ts +13 -0
- package/esm/ui/ScrollChrome.js +11 -0
- package/esm/ui/ScrollEdgeShadow.d.ts +6 -9
- package/esm/ui/ScrollEdgeShadow.js +14 -35
- package/esm/ui/ScrollZoomToggle.d.ts +4 -27
- package/esm/ui/ScrollZoomToggle.js +34 -51
- package/esm/ui/SessionJsonPanel.d.ts +3 -0
- package/esm/ui/SessionJsonPanel.js +14 -0
- package/esm/ui/SettingsChangesTable.d.ts +1 -0
- package/esm/ui/SettingsChangesTable.js +49 -11
- package/esm/ui/ShareLinkField.d.ts +1 -3
- package/esm/ui/ShareLinkField.js +13 -40
- package/esm/ui/SizeSliderRow.d.ts +1 -3
- package/esm/ui/SizeSliderRow.js +4 -6
- package/esm/ui/SnackbarModel.js +79 -67
- package/esm/ui/StatusProgressBar.js +2 -2
- package/esm/ui/SvgColorLegend.d.ts +9 -4
- package/esm/ui/SvgColorLegend.js +82 -41
- package/esm/ui/VerticalScrollbar.d.ts +13 -34
- package/esm/ui/VerticalScrollbar.js +29 -83
- package/esm/ui/ViewLoadingScreen.d.ts +5 -4
- package/esm/ui/ViewLoadingScreen.js +8 -32
- package/esm/ui/colorScale.d.ts +92 -0
- package/esm/ui/colorScale.js +72 -0
- package/esm/ui/colors.d.ts +64 -0
- package/esm/ui/colors.js +230 -1
- package/esm/ui/hoverBoxStyle.d.ts +14 -2
- package/esm/ui/hoverBoxStyle.js +17 -2
- package/esm/ui/index.d.ts +12 -12
- package/esm/ui/index.js +14 -22
- package/esm/ui/launchViewMenu.js +15 -5
- package/esm/ui/legendMenuItem.d.ts +10 -32
- package/esm/ui/legendMenuItem.js +9 -36
- package/esm/ui/legendSpec.d.ts +15 -8
- package/esm/ui/legendSpec.js +14 -23
- package/esm/ui/makeSizeMenu.d.ts +0 -6
- package/esm/ui/makeSizeMenu.js +6 -30
- package/esm/ui/measureLegendText.js +1 -1
- package/esm/ui/menuItemAdornment.d.ts +9 -20
- package/esm/ui/menuItemAdornment.js +10 -32
- package/esm/ui/menuItems.d.ts +2 -7
- package/esm/ui/menuItems.js +1 -6
- package/esm/ui/multiTrackMenuItems.d.ts +6 -0
- package/esm/ui/palette.d.ts +118 -116
- package/esm/ui/palette.js +114 -75
- package/esm/ui/replaceViewAction.d.ts +1 -1
- package/esm/ui/replaceViewAction.js +1 -1
- package/esm/ui/theme.d.ts +43 -119
- package/esm/ui/theme.js +62 -78
- package/esm/ui/toggleMenuItems.d.ts +1 -3
- package/esm/ui/toggleMenuItems.js +6 -5
- package/esm/ui/useAssemblySelection.d.ts +4 -4
- package/esm/ui/viewHeaderHeight.d.ts +1 -0
- package/esm/ui/viewHeaderHeight.js +1 -0
- package/esm/util/Base1DUtils.d.ts +5 -3
- package/esm/util/Base1DUtils.js +14 -6
- package/esm/util/Base1DViewModel.d.ts +2 -1
- package/esm/util/Base1DViewModel.js +3 -2
- package/esm/util/SvgCanvas.d.ts +15 -13
- package/esm/util/SvgCanvas.js +76 -56
- package/esm/util/TimeTraveller.d.ts +3 -0
- package/esm/util/TimeTraveller.js +34 -2
- package/esm/util/aborting.d.ts +39 -0
- package/esm/util/aborting.js +88 -6
- package/esm/util/adapterMetadata.d.ts +1 -1
- package/esm/util/adapterMetadata.js +6 -5
- package/esm/util/addAndShowTrack.d.ts +2 -5
- package/esm/util/addAndShowTrack.js +5 -1
- package/esm/util/addRelativeUris.d.ts +17 -5
- package/esm/util/addRelativeUris.js +46 -10
- package/esm/util/addTrackFromWidget.d.ts +2 -5
- package/esm/util/addTrackFromWidget.js +5 -4
- package/esm/util/aggregateFieldName.d.ts +10 -0
- package/esm/util/aggregateFieldName.js +8 -0
- package/esm/util/analytics.js +46 -13
- package/esm/util/animationAllowed.d.ts +9 -0
- package/esm/util/animationAllowed.js +13 -0
- package/esm/util/applyRowResizeWheel.d.ts +10 -5
- package/esm/util/applyRowResizeWheel.js +10 -21
- package/esm/util/bandHeight.d.ts +10 -0
- package/esm/util/bandHeight.js +29 -0
- package/esm/util/bandLayout.d.ts +4 -4
- package/esm/util/bandLayout.js +4 -4
- package/esm/util/baseDisplayConfig.d.ts +8 -0
- package/esm/util/baseDisplayConfig.js +27 -0
- package/esm/util/bezierConnector.d.ts +4 -3
- package/esm/util/bezierConnector.js +38 -45
- package/esm/util/bgzfWorkerPool.d.ts +20 -74
- package/esm/util/bgzfWorkerPool.js +20 -74
- package/esm/util/binnedAggregate.d.ts +17 -0
- package/esm/util/binnedAggregate.js +275 -0
- package/esm/util/cacheBudgets.d.ts +22 -19
- package/esm/util/cacheBudgets.js +22 -19
- package/esm/util/cachedSetup.d.ts +16 -6
- package/esm/util/cachedSetup.js +108 -38
- package/esm/util/categoricalField.d.ts +56 -0
- package/esm/util/categoricalField.js +73 -0
- package/esm/util/cellMatches.d.ts +23 -0
- package/esm/util/cellMatches.js +264 -0
- package/esm/util/cellsStep.d.ts +29 -0
- package/esm/util/cellsStep.js +437 -0
- package/esm/util/clampToContig.d.ts +17 -0
- package/esm/util/clampToContig.js +19 -0
- package/esm/util/coarseStripHTML.js +1 -2
- package/esm/util/color/cssColorsLevel4.d.ts +1 -0
- package/esm/util/color/cssColorsLevel4.js +1 -0
- package/esm/util/color/index.d.ts +5 -3
- package/esm/util/color/index.js +7 -4
- package/esm/util/colorBits.d.ts +3 -3
- package/esm/util/colorBits.js +19 -44
- package/esm/util/colorRamp.d.ts +49 -5
- package/esm/util/colorRamp.js +169 -18
- package/esm/util/colorScale.d.ts +156 -0
- package/esm/util/colorScale.js +243 -0
- package/esm/util/colorSchemes.d.ts +21 -0
- package/esm/util/colorSchemes.js +30 -0
- package/esm/util/copyToClipboard.js +8 -1
- package/esm/util/{createStopTokenRotation.d.ts → createAbortRotation.d.ts} +21 -23
- package/esm/util/{createStopTokenRotation.js → createAbortRotation.js} +21 -52
- package/esm/util/createSvgRasterCanvas.d.ts +10 -0
- package/esm/util/cssColorParse.d.ts +15 -0
- package/esm/util/cssColorParse.js +53 -0
- package/esm/util/diagonalizeRegions.d.ts +2 -3
- package/esm/util/diagonalizeRegions.js +8 -13
- package/esm/util/expandLooseSearchIndex.d.ts +19 -0
- package/esm/util/expandLooseSearchIndex.js +29 -0
- package/esm/util/featureTable.d.ts +224 -0
- package/esm/util/featureTable.js +366 -0
- package/esm/util/featureTransforms.d.ts +81 -0
- package/esm/util/featureTransforms.js +1231 -0
- package/esm/util/featureTypes.d.ts +24 -0
- package/esm/util/featureTypes.js +35 -0
- package/esm/util/fetchAndMaybeUnzip.js +16 -9
- package/esm/util/fetchContext.d.ts +7 -8
- package/esm/util/fetchContext.js +3 -3
- package/esm/util/fetchHub.d.ts +4 -2
- package/esm/util/fetchHub.js +2 -2
- package/esm/util/fetchPhases.d.ts +10 -10
- package/esm/util/fetchSeq.d.ts +2 -3
- package/esm/util/fetchSeq.js +2 -2
- package/esm/util/fieldReader.d.ts +17 -0
- package/esm/util/fieldReader.js +62 -0
- package/esm/util/formatBytes.js +1 -1
- package/esm/util/formatGuessers.d.ts +25 -14
- package/esm/util/formatGuessers.js +42 -27
- package/esm/util/formatRelativeTime.js +1 -1
- package/esm/util/freezeDeep.d.ts +8 -10
- package/esm/util/freezeDeep.js +8 -10
- package/esm/util/getLocationUri.d.ts +2 -1
- package/esm/util/getLocationUri.js +8 -2
- package/esm/util/groupKeys.d.ts +76 -0
- package/esm/util/groupKeys.js +156 -0
- package/esm/util/highlights.d.ts +10 -6
- package/esm/util/highlights.js +12 -25
- package/esm/util/hooks.d.ts +31 -2
- package/esm/util/hooks.js +72 -3
- package/esm/util/index.d.ts +11 -11
- package/esm/util/index.js +11 -10
- package/esm/util/indexCandidates.d.ts +1 -31
- package/esm/util/indexCandidates.js +5 -63
- package/esm/util/installFetch.d.ts +77 -37
- package/esm/util/installFetch.js +65 -38
- package/esm/util/installInitAutorun.d.ts +14 -13
- package/esm/util/installInitAutorun.js +17 -17
- package/esm/util/installPrerequisiteFetch.d.ts +115 -0
- package/esm/util/installPrerequisiteFetch.js +111 -0
- package/esm/util/intervals.js +9 -4
- package/esm/util/io/index.js +22 -15
- package/esm/util/isDataCurrent.d.ts +7 -5
- package/esm/util/isDataCurrent.js +9 -6
- package/esm/util/isTextEntryFocused.d.ts +7 -0
- package/esm/util/isTextEntryFocused.js +16 -0
- package/esm/util/jexl.js +24 -21
- package/esm/util/jexlFilterRows.d.ts +89 -0
- package/esm/util/jexlFilterRows.js +252 -0
- package/esm/util/jexlFilters.d.ts +32 -57
- package/esm/util/jexlFilters.js +31 -29
- package/esm/util/jexlStrings.d.ts +3 -4
- package/esm/util/jexlStrings.js +2 -3
- package/esm/util/layouts/GranularRectLayout.d.ts +8 -1
- package/esm/util/layouts/GranularRectLayout.js +25 -8
- package/esm/util/lazyAfterAttach.d.ts +13 -0
- package/esm/util/lazyAfterAttach.js +31 -0
- package/esm/util/lazyWithPreload.d.ts +19 -0
- package/esm/util/lazyWithPreload.js +27 -0
- package/esm/util/legendCandidates.d.ts +72 -0
- package/esm/util/legendCandidates.js +138 -0
- package/esm/util/locString.js +5 -2
- package/esm/util/localStorage.js +4 -4
- package/esm/util/markEncoding.d.ts +150 -0
- package/esm/util/markEncoding.js +885 -0
- package/esm/util/markEncodingTypes.d.ts +595 -0
- package/esm/util/markEncodingTypes.js +8 -0
- package/esm/util/mst-reflection.d.ts +2 -20
- package/esm/util/mst-reflection.js +3 -53
- package/esm/util/mstUtils.d.ts +31 -23
- package/esm/util/mstUtils.js +39 -24
- package/esm/util/numericUtils.d.ts +7 -0
- package/esm/util/numericUtils.js +16 -0
- package/esm/util/numericValue.d.ts +14 -0
- package/esm/util/numericValue.js +34 -0
- package/esm/util/openFeatureWidget.d.ts +5 -0
- package/esm/util/openFeatureWidget.js +2 -2
- package/esm/util/openViews.d.ts +17 -0
- package/esm/util/openViews.js +22 -0
- package/esm/util/parentWalk.d.ts +1 -1
- package/esm/util/parentWalk.js +1 -1
- package/esm/util/parseLineByLine.d.ts +4 -5
- package/esm/util/parseLineByLine.js +8 -14
- package/esm/util/pluginStore.d.ts +6 -8
- package/esm/util/pluginStore.js +17 -16
- package/esm/util/preloadComponent.d.ts +5 -0
- package/esm/util/preloadComponent.js +11 -0
- package/esm/util/progress.d.ts +22 -22
- package/esm/util/progress.js +27 -26
- package/esm/util/quantileExtent.d.ts +49 -0
- package/esm/util/quantileExtent.js +162 -0
- package/esm/util/range.d.ts +13 -9
- package/esm/util/range.js +17 -8
- package/esm/util/renameRegions.d.ts +26 -6
- package/esm/util/renameRegions.js +68 -54
- package/esm/util/renderToStaticMarkup.js +24 -14
- package/esm/util/rxjs.d.ts +23 -8
- package/esm/util/rxjs.js +61 -15
- package/esm/util/samplesTsv.d.ts +49 -0
- package/esm/util/samplesTsv.js +86 -0
- package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
- package/esm/util/scheduleDetachedDestroy.js +24 -0
- package/esm/util/scrollLatch.d.ts +1 -0
- package/esm/util/scrollLatch.js +8 -0
- package/esm/util/selectEncodedFeature.d.ts +16 -0
- package/esm/util/selectEncodedFeature.js +34 -0
- package/esm/util/sessionSharing.d.ts +7 -5
- package/esm/util/sessionSharing.js +23 -23
- package/esm/util/shapeNameList.d.ts +2 -0
- package/esm/util/shapeNameList.js +6 -0
- package/esm/util/shapeNames.d.ts +7 -0
- package/esm/util/shapeNames.js +11 -0
- package/esm/util/simpleFeature.d.ts +0 -1
- package/esm/util/springAnimate.js +1 -1
- package/esm/util/starFusion.d.ts +26 -0
- package/esm/util/starFusion.js +37 -0
- package/esm/util/stepTables.d.ts +96 -0
- package/esm/util/stepTables.js +277 -0
- package/esm/util/svAlt.d.ts +145 -0
- package/esm/util/svAlt.js +364 -0
- package/esm/util/svgColorProps.d.ts +11 -0
- package/esm/util/svgColorProps.js +28 -1
- package/esm/util/systemColorScheme.d.ts +12 -0
- package/esm/util/systemColorScheme.js +27 -0
- package/esm/util/tabix.d.ts +19 -10
- package/esm/util/tabix.js +19 -14
- package/esm/util/thresholdScale.d.ts +91 -0
- package/esm/util/thresholdScale.js +166 -0
- package/esm/util/timeGate.d.ts +4 -5
- package/esm/util/timeGate.js +4 -5
- package/esm/util/trackConfigDelta.d.ts +26 -26
- package/esm/util/trackConfigDelta.js +63 -47
- package/esm/util/tracks.d.ts +120 -66
- package/esm/util/tracks.js +501 -151
- package/esm/util/translateTranscript.d.ts +44 -0
- package/esm/util/translateTranscript.js +102 -0
- package/esm/util/types/data.d.ts +0 -2
- package/esm/util/types/index.d.ts +121 -22
- package/esm/util/types/index.js +9 -0
- package/esm/util/types/mst.d.ts +3 -0
- package/esm/util/types/mst.js +4 -0
- package/esm/util/types/renameIds.d.ts +1 -0
- package/esm/util/types/renameIds.js +29 -0
- package/esm/util/types/services.d.ts +1 -1
- package/esm/util/unknownSnapshotKeys.d.ts +53 -0
- package/esm/util/unknownSnapshotKeys.js +76 -0
- package/esm/util/useFeatureSequence.js +5 -5
- package/esm/util/useFetch.d.ts +3 -4
- package/esm/util/useFetch.js +19 -10
- package/esm/util/useFetchPlugins.d.ts +6 -2
- package/esm/util/useFetchPlugins.js +7 -3
- package/esm/util/usePanZoom.js +10 -3
- package/esm/util/usePanelVirtualScroll.d.ts +7 -35
- package/esm/util/usePanelVirtualScroll.js +9 -36
- package/esm/util/useRafCommit.js +1 -0
- package/esm/util/useRowVirtualScroll.d.ts +6 -29
- package/esm/util/useRowVirtualScroll.js +8 -49
- package/esm/util/useVirtualScrollWheel.d.ts +20 -4
- package/esm/util/useVirtualScrollWheel.js +40 -74
- package/esm/util/viewHighlights.d.ts +3 -0
- package/esm/util/viewHighlights.js +5 -0
- package/esm/util/viewStatus.d.ts +47 -15
- package/esm/util/viewStatus.js +34 -0
- package/esm/util/wheelZoom.d.ts +7 -1
- package/esm/util/wheelZoom.js +85 -19
- package/esm/util/whenViewSettled.d.ts +55 -8
- package/esm/util/whenViewSettled.js +56 -7
- package/esm/util/withFeatureDetails.js +4 -0
- package/esm/util/withLaunchInput.d.ts +174 -0
- package/esm/util/withLaunchInput.js +274 -0
- package/package.json +75 -24
- package/esm/BaseFeatureWidget/BaseFeatureDetail/Position.d.ts +0 -2
- package/esm/BaseFeatureWidget/BaseFeatureDetail/Position.js +0 -8
- package/esm/BaseFeatureWidget/BaseFeatureDetail/types.d.ts +0 -8
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.d.ts +0 -80
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.js +0 -583
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +0 -141
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.js +0 -1116
- package/esm/ReExports/BaseFeatureDetails.d.ts +0 -1
- package/esm/ReExports/BaseFeatureDetails.js +0 -10
- package/esm/ReExports/index.d.ts +0 -1
- package/esm/ReExports/index.js +0 -1
- package/esm/ReExports/publicUtil.d.ts +0 -1
- package/esm/ReExports/publicUtil.js +0 -28
- package/esm/configuration/promotableDefaults.d.ts +0 -199
- package/esm/configuration/promotableDefaults.js +0 -326
- package/esm/configuration/promotablePin.d.ts +0 -55
- package/esm/configuration/promotablePin.js +0 -1
- package/esm/configuration/promotableResolve.d.ts +0 -108
- package/esm/configuration/promotableResolve.js +0 -117
- package/esm/configuration/promotableSlots.d.ts +0 -12
- package/esm/configuration/promotableSlots.js +0 -45
- package/esm/configuration/slotShape.d.ts +0 -12
- package/esm/configuration/slotShape.js +0 -84
- package/esm/pluggableElementTypes/models/HighlightsMixin.d.ts +0 -51
- package/esm/pluggableElementTypes/models/HighlightsMixin.js +0 -78
- package/esm/ui/PinAdornment.d.ts +0 -5
- package/esm/ui/PinAdornment.js +0 -79
- package/esm/ui/SvgGradientLegend.d.ts +0 -26
- package/esm/ui/SvgGradientLegend.js +0 -26
- package/esm/ui/highlightChipReveal.d.ts +0 -32
- package/esm/ui/highlightChipReveal.js +0 -39
- package/esm/ui/promotableMenuItems.d.ts +0 -19
- package/esm/ui/promotableMenuItems.js +0 -89
- package/esm/ui/promotablePinCoverage.d.ts +0 -44
- package/esm/ui/promotablePinCoverage.js +0 -87
- package/esm/util/applyInitSettings.d.ts +0 -79
- package/esm/util/applyInitSettings.js +0 -91
- package/esm/util/openDisplays.d.ts +0 -23
- package/esm/util/openDisplays.js +0 -79
- package/esm/util/stopToken.d.ts +0 -211
- package/esm/util/stopToken.js +0 -438
- /package/esm/{BaseFeatureWidget/BaseFeatureDetail/types.js → data_adapters/BaseAdapter/zoomRange.js} +0 -0
|
@@ -0,0 +1,1231 @@
|
|
|
1
|
+
import { binnedAggregate, fusesBinAggregate } from './binnedAggregate.js';
|
|
2
|
+
import { categoricalField } from './categoricalField.js';
|
|
3
|
+
import { binnedCellMatches, fusesAfterCells, fusesCellMatches, } from './cellMatches.js';
|
|
4
|
+
import { cells } from './cellsStep.js';
|
|
5
|
+
import { DerivedTable, NO_COLUMN, WithTable, asTable, numberReaderOf, readerOf, selectRows, throughIndex, valueAt, withColumns, } from './featureTable.js';
|
|
6
|
+
import { fieldReader, isPlainFieldRef } from './fieldReader.js';
|
|
7
|
+
import { isJexl, stringToJexlExpression } from './jexlStrings.js';
|
|
8
|
+
import SimpleFeature, { buildJexlContext } from './simpleFeature.js';
|
|
9
|
+
import { BIN_OVERLAP_FIELD, DEFAULT_BIN_AS, FannedTable, MadeTable, OpSums, binSize, boundsThrough, groupKey, intervalsOf, isWeighted, madeGroups, stepNumberReader, stepReader, } from './stepTables.js';
|
|
10
|
+
import { junctionEnds, svClassOfAlt, svClassOfToken } from './svAlt.js';
|
|
11
|
+
export { BIN_OVERLAP_FIELD, DEFAULT_BIN_AS } from './stepTables.js';
|
|
12
|
+
export const DEFAULT_BIN_FIELD = 'start';
|
|
13
|
+
export const DEFAULT_FLATTEN_FIELD = 'subfeatures';
|
|
14
|
+
export { DEFAULT_CELLS_FIELD } from './cellsStep.js';
|
|
15
|
+
export const DEFAULT_COVERAGE_AS = 'coverage';
|
|
16
|
+
export const DEFAULT_PILEUP_AS = 'row';
|
|
17
|
+
export const DEFAULT_PILEUP_FIELDS = ['start', 'end'];
|
|
18
|
+
function oneSection(n) {
|
|
19
|
+
return Uint32Array.of(0, n);
|
|
20
|
+
}
|
|
21
|
+
function expression(expr, jexl) {
|
|
22
|
+
if (!jexl) {
|
|
23
|
+
throw new Error(`a jexl transform needs a jexl instance (${expr})`);
|
|
24
|
+
}
|
|
25
|
+
return stringToJexlExpression(expr, jexl);
|
|
26
|
+
}
|
|
27
|
+
class RowsBuilder {
|
|
28
|
+
data = new Uint32Array(256);
|
|
29
|
+
length = 0;
|
|
30
|
+
push(v) {
|
|
31
|
+
if (this.length === this.data.length) {
|
|
32
|
+
const next = new Uint32Array(this.data.length * 2);
|
|
33
|
+
next.set(this.data);
|
|
34
|
+
this.data = next;
|
|
35
|
+
}
|
|
36
|
+
this.data[this.length++] = v;
|
|
37
|
+
}
|
|
38
|
+
finish() {
|
|
39
|
+
return this.data.slice(0, this.length);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function filter({ table, bounds }, expr, jexl) {
|
|
43
|
+
const compiled = expression(expr, jexl);
|
|
44
|
+
const kept = new RowsBuilder();
|
|
45
|
+
for (let i = 0; i < table.length; i++) {
|
|
46
|
+
if (compiled.eval(buildJexlContext({ feature: table.row(i) }))) {
|
|
47
|
+
kept.push(i);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const parentRow = kept.finish();
|
|
51
|
+
return {
|
|
52
|
+
table: selectRows(table, parentRow),
|
|
53
|
+
bounds: boundsThrough(bounds, parentRow),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function formula({ table, bounds }, expr, as, jexl) {
|
|
57
|
+
const compiled = expression(expr, jexl);
|
|
58
|
+
const values = new Array(table.length);
|
|
59
|
+
for (let i = 0; i < table.length; i++) {
|
|
60
|
+
values[i] = compiled.eval(buildJexlContext({ feature: table.row(i) }));
|
|
61
|
+
}
|
|
62
|
+
const column = { kind: 'value', read: i => values[i] };
|
|
63
|
+
return { table: new WithTable(table, new Map([[as, column]])), bounds };
|
|
64
|
+
}
|
|
65
|
+
function isFeature(item) {
|
|
66
|
+
return typeof item?.get === 'function';
|
|
67
|
+
}
|
|
68
|
+
// An array's elements in order, or a record's entries keyed by name; a
|
|
69
|
+
// feature standing in the field is neither.
|
|
70
|
+
function fannedEntries(items) {
|
|
71
|
+
if (Array.isArray(items)) {
|
|
72
|
+
return [...items.entries()];
|
|
73
|
+
}
|
|
74
|
+
return typeof items === 'object' && items !== null && !isFeature(items)
|
|
75
|
+
? Object.entries(items)
|
|
76
|
+
: [];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The entries a `flatten` fanned out of a list or record a row holds. An
|
|
80
|
+
* entry answers a field it carries — a feature its own, a record its own key,
|
|
81
|
+
* a plain value the fanned field — and the container answers the rest,
|
|
82
|
+
* except the fanned field itself, so an entry never reads back its siblings.
|
|
83
|
+
*/
|
|
84
|
+
class FlatTable extends FannedTable {
|
|
85
|
+
field;
|
|
86
|
+
items;
|
|
87
|
+
at;
|
|
88
|
+
position;
|
|
89
|
+
indexField;
|
|
90
|
+
keyField;
|
|
91
|
+
constructor(parent, parentRow, field, items, at, position, step) {
|
|
92
|
+
super(parent, parentRow);
|
|
93
|
+
this.field = field;
|
|
94
|
+
this.items = items;
|
|
95
|
+
this.at = at;
|
|
96
|
+
this.position = position;
|
|
97
|
+
this.indexField = step.index;
|
|
98
|
+
this.keyField = step.key;
|
|
99
|
+
}
|
|
100
|
+
isKept(i) {
|
|
101
|
+
return this.at[i] === undefined;
|
|
102
|
+
}
|
|
103
|
+
get hasKept() {
|
|
104
|
+
return this.at.includes(undefined);
|
|
105
|
+
}
|
|
106
|
+
// An entry's value for a field, `undefined` where it states none.
|
|
107
|
+
entryValue(i, name) {
|
|
108
|
+
if (this.at[i] === undefined) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
const item = this.items[i];
|
|
112
|
+
if (isFeature(item)) {
|
|
113
|
+
return item.get(name);
|
|
114
|
+
}
|
|
115
|
+
if (typeof item === 'object' && item !== null) {
|
|
116
|
+
return name === 'uniqueId'
|
|
117
|
+
? this.id(i)
|
|
118
|
+
: item[name];
|
|
119
|
+
}
|
|
120
|
+
return name === this.field ? item : undefined;
|
|
121
|
+
}
|
|
122
|
+
isOwnKey(i) {
|
|
123
|
+
return this.keyField !== undefined && typeof this.at[i] === 'string';
|
|
124
|
+
}
|
|
125
|
+
// The key as codes into the names met, where every row is an entry keyed
|
|
126
|
+
// by name: a record's species or samples, which a facet then splits on
|
|
127
|
+
// once per name.
|
|
128
|
+
keyCategory() {
|
|
129
|
+
const codes = new Uint32Array(this.length);
|
|
130
|
+
const labels = [];
|
|
131
|
+
const codeOf = new Map();
|
|
132
|
+
for (let i = 0; i < this.length; i++) {
|
|
133
|
+
const at = this.at[i];
|
|
134
|
+
if (typeof at !== 'string') {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
let code = codeOf.get(at);
|
|
138
|
+
if (code === undefined) {
|
|
139
|
+
code = labels.length;
|
|
140
|
+
codeOf.set(at, code);
|
|
141
|
+
labels.push(at);
|
|
142
|
+
}
|
|
143
|
+
codes[i] = code;
|
|
144
|
+
}
|
|
145
|
+
return { kind: 'category', codes, labels, at: undefined };
|
|
146
|
+
}
|
|
147
|
+
own(name) {
|
|
148
|
+
const read = readerOf(this.inherited(name));
|
|
149
|
+
const fanned = name === this.field;
|
|
150
|
+
const entryThenContainer = (i) => {
|
|
151
|
+
const v = this.entryValue(i, name);
|
|
152
|
+
return v === undefined && (!fanned || this.isKept(i)) ? read(i) : v;
|
|
153
|
+
};
|
|
154
|
+
if (name === this.indexField) {
|
|
155
|
+
const { position } = this;
|
|
156
|
+
return {
|
|
157
|
+
kind: 'value',
|
|
158
|
+
read: i => this.at[i] === undefined ? entryThenContainer(i) : position[i],
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (name === this.keyField) {
|
|
162
|
+
return (this.keyCategory() ?? {
|
|
163
|
+
kind: 'value',
|
|
164
|
+
read: i => (this.isOwnKey(i) ? this.at[i] : entryThenContainer(i)),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
return { kind: 'value', read: entryThenContainer };
|
|
168
|
+
}
|
|
169
|
+
id(i) {
|
|
170
|
+
const at = this.at[i];
|
|
171
|
+
const container = this.parent.row(this.parentOf(i));
|
|
172
|
+
if (at === undefined) {
|
|
173
|
+
return container.id();
|
|
174
|
+
}
|
|
175
|
+
const item = this.items[i];
|
|
176
|
+
return isFeature(item) ? item.id() : `${container.id()}#${at}`;
|
|
177
|
+
}
|
|
178
|
+
json(i) {
|
|
179
|
+
const containerRow = this.parent.row(this.parentOf(i));
|
|
180
|
+
const at = this.at[i];
|
|
181
|
+
const own = {};
|
|
182
|
+
if (this.indexField !== undefined && at !== undefined) {
|
|
183
|
+
own[this.indexField] = this.position[i];
|
|
184
|
+
}
|
|
185
|
+
if (this.keyField !== undefined && this.isOwnKey(i)) {
|
|
186
|
+
own[this.keyField] = at;
|
|
187
|
+
}
|
|
188
|
+
if (at === undefined) {
|
|
189
|
+
return { ...containerRow.toJSON(), ...own };
|
|
190
|
+
}
|
|
191
|
+
const item = this.items[i];
|
|
192
|
+
if (!isFeature(item) && (typeof item !== 'object' || item === null)) {
|
|
193
|
+
return { ...containerRow.toJSON(), [this.field]: item, ...own };
|
|
194
|
+
}
|
|
195
|
+
const { [this.field]: _siblings, ...container } = containerRow.toJSON();
|
|
196
|
+
const entry = isFeature(item)
|
|
197
|
+
? item.toJSON()
|
|
198
|
+
: new SimpleFeature({
|
|
199
|
+
refName: containerRow.get('refName'),
|
|
200
|
+
start: containerRow.get('start'),
|
|
201
|
+
end: containerRow.get('end'),
|
|
202
|
+
...item,
|
|
203
|
+
uniqueId: this.id(i),
|
|
204
|
+
}).toJSON();
|
|
205
|
+
return { ...container, ...entry, ...own };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* The entries a `flatten` fanned out of a list column, which are the list's
|
|
210
|
+
* own rows: an entry reads the fields its list holds straight off the list's
|
|
211
|
+
* lanes, and the container the rest. A keyed entry is a record filed under
|
|
212
|
+
* its name, any other a feature of its own.
|
|
213
|
+
*/
|
|
214
|
+
class ListFlatTable extends FannedTable {
|
|
215
|
+
field;
|
|
216
|
+
list;
|
|
217
|
+
entryRow;
|
|
218
|
+
position;
|
|
219
|
+
kept;
|
|
220
|
+
indexField;
|
|
221
|
+
keyField;
|
|
222
|
+
constructor(parent, parentRow, field, list, entryRow, position, kept, step) {
|
|
223
|
+
super(parent, parentRow);
|
|
224
|
+
this.field = field;
|
|
225
|
+
this.list = list;
|
|
226
|
+
this.entryRow = entryRow;
|
|
227
|
+
this.position = position;
|
|
228
|
+
this.kept = kept;
|
|
229
|
+
this.indexField = step.index;
|
|
230
|
+
this.keyField = step.key;
|
|
231
|
+
}
|
|
232
|
+
isKept(i) {
|
|
233
|
+
return this.kept?.[i] === 1;
|
|
234
|
+
}
|
|
235
|
+
get hasKept() {
|
|
236
|
+
return this.kept !== undefined;
|
|
237
|
+
}
|
|
238
|
+
entryOf(i) {
|
|
239
|
+
return this.entryRow ? this.entryRow[i] : i;
|
|
240
|
+
}
|
|
241
|
+
throughEntries(column) {
|
|
242
|
+
return this.entryRow ? throughIndex(column, this.entryRow) : column;
|
|
243
|
+
}
|
|
244
|
+
entryColumn(name) {
|
|
245
|
+
const { keys, entries } = this.list;
|
|
246
|
+
if (name === this.indexField) {
|
|
247
|
+
return { kind: 'number', values: this.position, at: undefined };
|
|
248
|
+
}
|
|
249
|
+
if (name === this.keyField && keys) {
|
|
250
|
+
return this.throughEntries(keys);
|
|
251
|
+
}
|
|
252
|
+
if (name === this.field) {
|
|
253
|
+
return NO_COLUMN;
|
|
254
|
+
}
|
|
255
|
+
if (name === 'uniqueId' && keys) {
|
|
256
|
+
return { kind: 'value', read: i => this.id(i) };
|
|
257
|
+
}
|
|
258
|
+
const column = entries.column(name);
|
|
259
|
+
return column.kind === 'none' ? undefined : this.throughEntries(column);
|
|
260
|
+
}
|
|
261
|
+
own(name) {
|
|
262
|
+
const column = this.entryColumn(name);
|
|
263
|
+
const { kept } = this;
|
|
264
|
+
if (!kept || column === undefined) {
|
|
265
|
+
return column;
|
|
266
|
+
}
|
|
267
|
+
const entry = readerOf(column);
|
|
268
|
+
const container = readerOf(this.inherited(name));
|
|
269
|
+
return { kind: 'value', read: i => (kept[i] ? container(i) : entry(i)) };
|
|
270
|
+
}
|
|
271
|
+
id(i) {
|
|
272
|
+
const container = this.parent.row(this.parentOf(i));
|
|
273
|
+
if (this.isKept(i)) {
|
|
274
|
+
return container.id();
|
|
275
|
+
}
|
|
276
|
+
const { keys, entries } = this.list;
|
|
277
|
+
const j = this.entryOf(i);
|
|
278
|
+
return keys
|
|
279
|
+
? `${container.id()}#${String(valueAt(keys, j))}`
|
|
280
|
+
: entries.id(j);
|
|
281
|
+
}
|
|
282
|
+
json(i) {
|
|
283
|
+
const containerRow = this.parent.row(this.parentOf(i));
|
|
284
|
+
if (this.isKept(i)) {
|
|
285
|
+
return containerRow.toJSON();
|
|
286
|
+
}
|
|
287
|
+
const { keys, entries } = this.list;
|
|
288
|
+
const j = this.entryOf(i);
|
|
289
|
+
const own = {};
|
|
290
|
+
if (this.indexField !== undefined) {
|
|
291
|
+
own[this.indexField] = this.position[i];
|
|
292
|
+
}
|
|
293
|
+
if (this.keyField !== undefined && keys) {
|
|
294
|
+
own[this.keyField] = valueAt(keys, j);
|
|
295
|
+
}
|
|
296
|
+
const { [this.field]: _siblings, ...container } = containerRow.toJSON();
|
|
297
|
+
const entry = keys
|
|
298
|
+
? {
|
|
299
|
+
refName: containerRow.get('refName'),
|
|
300
|
+
start: containerRow.get('start'),
|
|
301
|
+
end: containerRow.get('end'),
|
|
302
|
+
...entries.record(j),
|
|
303
|
+
uniqueId: this.id(i),
|
|
304
|
+
}
|
|
305
|
+
: entries.json(j);
|
|
306
|
+
return { ...container, ...entry, ...own };
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// A list column fanned out: each row's entries in order, their positions and
|
|
310
|
+
// the entry rows they are, with no entry read.
|
|
311
|
+
function flattenList({ table, bounds }, step, field, list) {
|
|
312
|
+
const { start, at } = list;
|
|
313
|
+
const n = table.length;
|
|
314
|
+
let size = 0;
|
|
315
|
+
let empty = 0;
|
|
316
|
+
for (let i = 0; i < n; i++) {
|
|
317
|
+
const r = at ? at[i] : i;
|
|
318
|
+
const count = start[r + 1] - start[r];
|
|
319
|
+
size += count;
|
|
320
|
+
if (count === 0) {
|
|
321
|
+
empty++;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
const total = size + (step.keepEmpty ? empty : 0);
|
|
325
|
+
const parentRow = new Uint32Array(total);
|
|
326
|
+
const position = new Uint32Array(total);
|
|
327
|
+
const entryRow = new Uint32Array(total);
|
|
328
|
+
const kept = total > size ? new Uint8Array(total) : undefined;
|
|
329
|
+
let k = 0;
|
|
330
|
+
let inOrder = true;
|
|
331
|
+
for (let i = 0; i < n; i++) {
|
|
332
|
+
const r = at ? at[i] : i;
|
|
333
|
+
const from = start[r];
|
|
334
|
+
const to = start[r + 1];
|
|
335
|
+
if (from === to && kept) {
|
|
336
|
+
parentRow[k] = i;
|
|
337
|
+
kept[k] = 1;
|
|
338
|
+
inOrder = false;
|
|
339
|
+
k++;
|
|
340
|
+
}
|
|
341
|
+
for (let j = from; j < to; j++) {
|
|
342
|
+
parentRow[k] = i;
|
|
343
|
+
position[k] = j - from;
|
|
344
|
+
entryRow[k] = j;
|
|
345
|
+
inOrder &&= j === k;
|
|
346
|
+
k++;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
table: new ListFlatTable(table, parentRow, field, list, inOrder ? undefined : entryRow, position, kept, step),
|
|
351
|
+
bounds: boundsThrough(bounds, parentRow),
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
function flatten(staged, step) {
|
|
355
|
+
const { field = DEFAULT_FLATTEN_FIELD } = step;
|
|
356
|
+
const column = isPlainFieldRef(field) ? staged.table.column(field) : undefined;
|
|
357
|
+
return column?.kind === 'list'
|
|
358
|
+
? flattenList(staged, step, field, column)
|
|
359
|
+
: flattenValues(staged, step);
|
|
360
|
+
}
|
|
361
|
+
function flattenValues({ table, bounds }, step) {
|
|
362
|
+
const { field = DEFAULT_FLATTEN_FIELD, keepEmpty } = step;
|
|
363
|
+
const read = stepReader(table, field, 'a flatten');
|
|
364
|
+
const parentRow = new RowsBuilder();
|
|
365
|
+
const position = new RowsBuilder();
|
|
366
|
+
const items = [];
|
|
367
|
+
const at = [];
|
|
368
|
+
for (let i = 0; i < table.length; i++) {
|
|
369
|
+
const entries = fannedEntries(read(i));
|
|
370
|
+
if (entries.length === 0) {
|
|
371
|
+
if (keepEmpty) {
|
|
372
|
+
parentRow.push(i);
|
|
373
|
+
position.push(0);
|
|
374
|
+
items.push(undefined);
|
|
375
|
+
at.push(undefined);
|
|
376
|
+
}
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
for (const [p, [key, item]] of entries.entries()) {
|
|
380
|
+
parentRow.push(i);
|
|
381
|
+
position.push(p);
|
|
382
|
+
items.push(item);
|
|
383
|
+
at.push(key);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const rows = parentRow.finish();
|
|
387
|
+
return {
|
|
388
|
+
table: new FlatTable(table, rows, field, items, at, position.finish(), step),
|
|
389
|
+
bounds: boundsThrough(bounds, rows),
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function statedMate(f) {
|
|
393
|
+
const mate = f.get('mate');
|
|
394
|
+
return mate?.refName !== undefined && mate.start !== undefined
|
|
395
|
+
? {
|
|
396
|
+
refName: mate.refName,
|
|
397
|
+
start: mate.start,
|
|
398
|
+
end: mate.end ?? mate.start + 1,
|
|
399
|
+
mateDirection: mate.mateDirection ?? 0,
|
|
400
|
+
}
|
|
401
|
+
: undefined;
|
|
402
|
+
}
|
|
403
|
+
function mateFields(f, alt, mate, ownDirection, alleleIndex = 0) {
|
|
404
|
+
const info = f.get('INFO');
|
|
405
|
+
const svType = alt === undefined
|
|
406
|
+
? svClassOfToken(String(info?.SVTYPE?.[0] ?? ''))
|
|
407
|
+
: svClassOfAlt(alt, {
|
|
408
|
+
ref: f.get('REF'),
|
|
409
|
+
info,
|
|
410
|
+
alleleIndex,
|
|
411
|
+
});
|
|
412
|
+
return {
|
|
413
|
+
mate,
|
|
414
|
+
mateDirection: ownDirection,
|
|
415
|
+
...(alt === undefined ? {} : { alt }),
|
|
416
|
+
...(svType ? { svType } : {}),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
// A paired read's mate, where the file places one: the sequence and position
|
|
420
|
+
// its next segment aligns to, one base of it.
|
|
421
|
+
function pairedMate(f) {
|
|
422
|
+
const refName = f.get('next_ref');
|
|
423
|
+
const pos = f.get('next_pos');
|
|
424
|
+
return typeof refName === 'string' && typeof pos === 'number' && pos >= 0
|
|
425
|
+
? { refName, start: pos, end: pos + 1, mateDirection: 0 }
|
|
426
|
+
: undefined;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* #api
|
|
430
|
+
* How a record states its other end, or undefined where it states none: the
|
|
431
|
+
* `mate` a paired adapter fills (BEDPE, STAR-Fusion), an `ALT` the breakend
|
|
432
|
+
* and symbolic-SV readers resolve, or a read's `next_ref` and `next_pos`. The
|
|
433
|
+
* `mate` step admits exactly the features this names one for, so a caller
|
|
434
|
+
* deciding whether links are the picture a track wants asks here rather than
|
|
435
|
+
* re-reading the fields.
|
|
436
|
+
*/
|
|
437
|
+
export function matedBy(f) {
|
|
438
|
+
if (statedMate(f)) {
|
|
439
|
+
return 'mate';
|
|
440
|
+
}
|
|
441
|
+
const alts = f.get('ALT');
|
|
442
|
+
if (Array.isArray(alts) &&
|
|
443
|
+
alts.some((alt, i) => junctionEnds(f, alt, i))) {
|
|
444
|
+
return 'alt';
|
|
445
|
+
}
|
|
446
|
+
return pairedMate(f) ? 'pair' : undefined;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* The ends a `mate` step admitted: each a row of the record it came from, with
|
|
450
|
+
* its mate's fields beside the record's, an allele of a record with several
|
|
451
|
+
* named by its position.
|
|
452
|
+
*/
|
|
453
|
+
class MateTable extends DerivedTable {
|
|
454
|
+
fields;
|
|
455
|
+
ids;
|
|
456
|
+
constructor(parent, parentRow, fields, ids) {
|
|
457
|
+
super(parent, parentRow);
|
|
458
|
+
this.fields = fields;
|
|
459
|
+
this.ids = ids;
|
|
460
|
+
}
|
|
461
|
+
own(name) {
|
|
462
|
+
if (!this.fields.some(f => name in f)) {
|
|
463
|
+
return undefined;
|
|
464
|
+
}
|
|
465
|
+
const read = readerOf(this.inherited(name));
|
|
466
|
+
return {
|
|
467
|
+
kind: 'value',
|
|
468
|
+
read: i => (name in this.fields[i] ? this.fields[i][name] : read(i)),
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
id(i) {
|
|
472
|
+
return this.ids[i] ?? super.id(i);
|
|
473
|
+
}
|
|
474
|
+
json(i) {
|
|
475
|
+
return { ...super.json(i), ...this.fields[i] };
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function mates({ table, bounds }) {
|
|
479
|
+
const parentRow = new RowsBuilder();
|
|
480
|
+
const fields = [];
|
|
481
|
+
const ids = [];
|
|
482
|
+
const out = new Uint32Array(bounds.length);
|
|
483
|
+
for (let s = 0; s + 1 < bounds.length; s++) {
|
|
484
|
+
out[s] = parentRow.length;
|
|
485
|
+
const seen = new Set();
|
|
486
|
+
const admit = (i, here, there, written, id) => {
|
|
487
|
+
const key = here < there ? `${here}|${there}` : `${there}|${here}`;
|
|
488
|
+
if (!seen.has(key)) {
|
|
489
|
+
seen.add(key);
|
|
490
|
+
parentRow.push(i);
|
|
491
|
+
fields.push(written);
|
|
492
|
+
ids.push(id);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
const span = (f, mate) => [
|
|
496
|
+
`${f.get('refName')}:${f.get('start')}-${f.get('end')}`,
|
|
497
|
+
`${mate.refName}:${mate.start}-${mate.end}`,
|
|
498
|
+
];
|
|
499
|
+
for (let i = bounds[s]; i < bounds[s + 1]; i++) {
|
|
500
|
+
const f = table.row(i);
|
|
501
|
+
const stated = statedMate(f);
|
|
502
|
+
if (stated) {
|
|
503
|
+
const ends = junctionEnds(f);
|
|
504
|
+
const mate = { ...stated, mateDirection: ends.mate.keeps };
|
|
505
|
+
admit(i, ...span(f, mate), mateFields(f, undefined, mate, ends.own.keeps));
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
const alts = f.get('ALT');
|
|
509
|
+
if (!Array.isArray(alts)) {
|
|
510
|
+
// each read of a pair names the other's start, so the pair is one key
|
|
511
|
+
const pair = pairedMate(f);
|
|
512
|
+
if (pair) {
|
|
513
|
+
admit(i, `${f.get('refName')}:${f.get('start')}`, `${pair.refName}:${pair.start}`, { mate: pair, mateDirection: 0 });
|
|
514
|
+
}
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
for (const [a, alt] of alts.entries()) {
|
|
518
|
+
const ends = junctionEnds(f, alt, a);
|
|
519
|
+
if (!ends) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
const mate = {
|
|
523
|
+
refName: ends.mate.refName,
|
|
524
|
+
start: ends.mate.pos,
|
|
525
|
+
end: ends.mate.pos + 1,
|
|
526
|
+
mateDirection: ends.mate.keeps,
|
|
527
|
+
};
|
|
528
|
+
admit(i, ...span(f, mate), mateFields(f, alt, mate, ends.own.keeps, a), alts.length > 1 ? `${f.id()}#${a}` : undefined);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
out[bounds.length - 1] = parentRow.length;
|
|
533
|
+
return {
|
|
534
|
+
table: new MateTable(table, parentRow.finish(), fields, ids),
|
|
535
|
+
bounds: out,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
function bin(staged, step) {
|
|
539
|
+
return step.fields
|
|
540
|
+
? binIntervals(staged, step, step.fields)
|
|
541
|
+
: binPoints(staged, step);
|
|
542
|
+
}
|
|
543
|
+
function binPoints({ table, bounds }, step) {
|
|
544
|
+
const { field = DEFAULT_BIN_FIELD } = step;
|
|
545
|
+
const size = binSize(step);
|
|
546
|
+
const [asStart, asEnd] = step.as ?? DEFAULT_BIN_AS;
|
|
547
|
+
const read = stepNumberReader(table, field, 'a bin');
|
|
548
|
+
const n = table.length;
|
|
549
|
+
const starts = new Float64Array(n);
|
|
550
|
+
const ends = new Float64Array(n);
|
|
551
|
+
for (let i = 0; i < n; i++) {
|
|
552
|
+
const s = Math.floor(read(i) / size) * size;
|
|
553
|
+
starts[i] = s;
|
|
554
|
+
ends[i] = s + size;
|
|
555
|
+
}
|
|
556
|
+
const written = new Map([
|
|
557
|
+
[asStart, { kind: 'number', values: starts, at: undefined }],
|
|
558
|
+
[asEnd, { kind: 'number', values: ends, at: undefined }],
|
|
559
|
+
]);
|
|
560
|
+
return { table: new WithTable(table, written), bounds };
|
|
561
|
+
}
|
|
562
|
+
function binIntervals({ table, bounds }, step, fields) {
|
|
563
|
+
const size = binSize(step);
|
|
564
|
+
const [asStart, asEnd] = step.as ?? DEFAULT_BIN_AS;
|
|
565
|
+
const iv = intervalsOf(table, fields, size, bounds);
|
|
566
|
+
const { pieces } = iv;
|
|
567
|
+
const parentRow = new Uint32Array(pieces);
|
|
568
|
+
const binStart = new Float64Array(pieces);
|
|
569
|
+
const binEnd = new Float64Array(pieces);
|
|
570
|
+
const overlap = new Float64Array(pieces);
|
|
571
|
+
let k = 0;
|
|
572
|
+
for (let i = 0; i < table.length; i++) {
|
|
573
|
+
const first = iv.first[i];
|
|
574
|
+
if (Number.isNaN(first)) {
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
577
|
+
const s = iv.start[i];
|
|
578
|
+
const e = iv.end[i];
|
|
579
|
+
for (let b = first; b <= iv.last[i]; b++) {
|
|
580
|
+
const lo = b * size;
|
|
581
|
+
const hi = lo + size;
|
|
582
|
+
parentRow[k] = i;
|
|
583
|
+
binStart[k] = lo;
|
|
584
|
+
binEnd[k] = hi;
|
|
585
|
+
overlap[k] = Math.min(e, hi) - Math.max(s, lo);
|
|
586
|
+
k++;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const written = new Map([
|
|
590
|
+
[asStart, { kind: 'number', values: binStart, at: undefined }],
|
|
591
|
+
[asEnd, { kind: 'number', values: binEnd, at: undefined }],
|
|
592
|
+
[BIN_OVERLAP_FIELD, { kind: 'number', values: overlap, at: undefined }],
|
|
593
|
+
]);
|
|
594
|
+
return {
|
|
595
|
+
table: new WithTable(table, written, parentRow),
|
|
596
|
+
bounds: boundsThrough(bounds, parentRow),
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
// Each row's group, numbered in the order groups are first met, a section
|
|
600
|
+
// being the outermost level: the groups keyed by their raw values, one Map
|
|
601
|
+
// level per groupby field, where a string key built per row was the
|
|
602
|
+
// aggregate's whole cost.
|
|
603
|
+
function groupRows(n, bounds, reads, normalize) {
|
|
604
|
+
const groupOf = new Uint32Array(n);
|
|
605
|
+
const firstRow = [];
|
|
606
|
+
const sectionOf = [];
|
|
607
|
+
const last = reads.length - 1;
|
|
608
|
+
for (let s = 0; s + 1 < bounds.length; s++) {
|
|
609
|
+
const root = new Map();
|
|
610
|
+
for (let i = bounds[s]; i < bounds[s + 1]; i++) {
|
|
611
|
+
let g;
|
|
612
|
+
if (reads.length === 0) {
|
|
613
|
+
g =
|
|
614
|
+
firstRow.length > 0 && sectionOf.at(-1) === s
|
|
615
|
+
? firstRow.length - 1
|
|
616
|
+
: -1;
|
|
617
|
+
if (g < 0) {
|
|
618
|
+
g = firstRow.length;
|
|
619
|
+
firstRow.push(i);
|
|
620
|
+
sectionOf.push(s);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
let node = root;
|
|
625
|
+
for (let l = 0; l < last; l++) {
|
|
626
|
+
const raw = reads[l](i);
|
|
627
|
+
const v = normalize && typeof raw !== 'object' ? raw : groupKey(raw);
|
|
628
|
+
let next = node.get(v);
|
|
629
|
+
if (!next) {
|
|
630
|
+
next = new Map();
|
|
631
|
+
node.set(v, next);
|
|
632
|
+
}
|
|
633
|
+
node = next;
|
|
634
|
+
}
|
|
635
|
+
const raw = reads[last](i);
|
|
636
|
+
const v = normalize && typeof raw !== 'object' ? raw : groupKey(raw);
|
|
637
|
+
let at = node.get(v);
|
|
638
|
+
if (at === undefined) {
|
|
639
|
+
at = firstRow.length;
|
|
640
|
+
node.set(v, at);
|
|
641
|
+
firstRow.push(i);
|
|
642
|
+
sectionOf.push(s);
|
|
643
|
+
}
|
|
644
|
+
g = at;
|
|
645
|
+
}
|
|
646
|
+
groupOf[i] = g;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return { groupOf, firstRow, sectionOf };
|
|
650
|
+
}
|
|
651
|
+
function aggregate({ table, bounds }, step) {
|
|
652
|
+
const { groupby = [], ops } = step;
|
|
653
|
+
const n = table.length;
|
|
654
|
+
const keyed = groupby.some(field => !isPlainFieldRef(field));
|
|
655
|
+
const reads = groupby.map(field => keyed
|
|
656
|
+
? stepReader(table, field, 'an aggregate')
|
|
657
|
+
: readerOf(table.column(field)));
|
|
658
|
+
const { groupOf, firstRow, sectionOf } = groupRows(n, bounds, reads, !keyed);
|
|
659
|
+
const groups = firstRow.length;
|
|
660
|
+
const readStart = readerOf(table.column('start'));
|
|
661
|
+
const readEnd = readerOf(table.column('end'));
|
|
662
|
+
const readRefName = readerOf(table.column('refName'));
|
|
663
|
+
const start = new Float64Array(groups).fill(Infinity);
|
|
664
|
+
const end = new Float64Array(groups).fill(-Infinity);
|
|
665
|
+
for (let i = 0; i < n; i++) {
|
|
666
|
+
const g = groupOf[i];
|
|
667
|
+
start[g] = Math.min(start[g], readStart(i));
|
|
668
|
+
end[g] = Math.max(end[g], readEnd(i));
|
|
669
|
+
}
|
|
670
|
+
return madeGroups({
|
|
671
|
+
groups,
|
|
672
|
+
keys: groupby.map((field, f) => {
|
|
673
|
+
const read = reads[f];
|
|
674
|
+
return [field, firstRow.map(i => groupKey(read(i)))];
|
|
675
|
+
}),
|
|
676
|
+
ops: ops.map(agg => aggregateColumn(table, agg, groupOf, groups)),
|
|
677
|
+
step,
|
|
678
|
+
refNames: firstRow.map(i => readRefName(i)),
|
|
679
|
+
start,
|
|
680
|
+
end,
|
|
681
|
+
sectionOf,
|
|
682
|
+
sections: bounds.length,
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
function aggregateColumn(table, agg, groupOf, groups) {
|
|
686
|
+
const n = table.length;
|
|
687
|
+
const sums = new OpSums(agg, groups);
|
|
688
|
+
const { field, weight } = agg;
|
|
689
|
+
const readValue = agg.op === 'count' || field === undefined
|
|
690
|
+
? () => Number.NaN
|
|
691
|
+
: stepNumberReader(table, field, 'an aggregate');
|
|
692
|
+
const readWeight = weight !== undefined && isWeighted(agg)
|
|
693
|
+
? stepNumberReader(table, weight, 'an aggregate')
|
|
694
|
+
: () => 1;
|
|
695
|
+
for (let i = 0; i < n; i++) {
|
|
696
|
+
sums.add(groupOf[i], readValue(i), readWeight(i));
|
|
697
|
+
}
|
|
698
|
+
return sums.column(groups);
|
|
699
|
+
}
|
|
700
|
+
// Rows in start order, ties in the order they came: a start and a row packed
|
|
701
|
+
// into one double and sorted without a comparator, which leaves the typed
|
|
702
|
+
// sort's fast path only where the packing could not be exact.
|
|
703
|
+
function sortByStart(rows, starts) {
|
|
704
|
+
const n = rows.length;
|
|
705
|
+
let lo = Infinity;
|
|
706
|
+
let hi = -Infinity;
|
|
707
|
+
let whole = true;
|
|
708
|
+
for (let k = 0; k < n; k++) {
|
|
709
|
+
const v = starts[rows[k]];
|
|
710
|
+
if (v < lo) {
|
|
711
|
+
lo = v;
|
|
712
|
+
}
|
|
713
|
+
if (v > hi) {
|
|
714
|
+
hi = v;
|
|
715
|
+
}
|
|
716
|
+
whole &&= Number.isInteger(v);
|
|
717
|
+
}
|
|
718
|
+
if (whole && (hi - lo + 1) * n < Number.MAX_SAFE_INTEGER) {
|
|
719
|
+
const keys = new Float64Array(n);
|
|
720
|
+
for (let k = 0; k < n; k++) {
|
|
721
|
+
keys[k] = (starts[rows[k]] - lo) * n + k;
|
|
722
|
+
}
|
|
723
|
+
keys.sort();
|
|
724
|
+
const placed = Uint32Array.from(rows);
|
|
725
|
+
for (let k = 0; k < n; k++) {
|
|
726
|
+
rows[k] = placed[keys[k] % n];
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
rows.sort((a, b) => starts[a] - starts[b] || a - b);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* The lowest row each row fits on, greedy first fit in start order within its
|
|
735
|
+
* section, as a step in front of the encoder rather than a packer behind it.
|
|
736
|
+
* The rows come out in start order, as the packing met them.
|
|
737
|
+
*/
|
|
738
|
+
function pileup({ table, bounds }, step) {
|
|
739
|
+
const as = step.as ?? DEFAULT_PILEUP_AS;
|
|
740
|
+
const [startField, endField] = step.fields ?? DEFAULT_PILEUP_FIELDS;
|
|
741
|
+
const padding = step.padding ?? 0;
|
|
742
|
+
const n = table.length;
|
|
743
|
+
const readStart = stepNumberReader(table, startField, 'a pileup');
|
|
744
|
+
const readEnd = stepNumberReader(table, endField, 'a pileup');
|
|
745
|
+
const starts = new Float64Array(n);
|
|
746
|
+
const ends = new Float64Array(n);
|
|
747
|
+
for (let i = 0; i < n; i++) {
|
|
748
|
+
starts[i] = readStart(i);
|
|
749
|
+
ends[i] = readEnd(i);
|
|
750
|
+
}
|
|
751
|
+
const order = new Uint32Array(n);
|
|
752
|
+
const packed = new Float64Array(n);
|
|
753
|
+
for (let s = 0; s + 1 < bounds.length; s++) {
|
|
754
|
+
const lo = bounds[s];
|
|
755
|
+
const hi = bounds[s + 1];
|
|
756
|
+
let inOrder = true;
|
|
757
|
+
for (let i = lo + 1; i < hi; i++) {
|
|
758
|
+
inOrder &&= starts[i] >= starts[i - 1];
|
|
759
|
+
}
|
|
760
|
+
// Any unreadable start leaves the section out of order. Read as Infinity,
|
|
761
|
+
// it sorts last and packs where it claims no row a readable one could
|
|
762
|
+
// want, where NaN left the sort without an order and a row's end
|
|
763
|
+
// unreadable.
|
|
764
|
+
if (!inOrder) {
|
|
765
|
+
for (let i = lo; i < hi; i++) {
|
|
766
|
+
if (Number.isNaN(starts[i])) {
|
|
767
|
+
starts[i] = Infinity;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
for (let i = lo; i < hi; i++) {
|
|
772
|
+
order[i] = i;
|
|
773
|
+
}
|
|
774
|
+
if (!inOrder) {
|
|
775
|
+
sortByStart(order.subarray(lo, hi), starts);
|
|
776
|
+
}
|
|
777
|
+
const rowEnds = [];
|
|
778
|
+
for (let k = lo; k < hi; k++) {
|
|
779
|
+
const i = order[k];
|
|
780
|
+
const start = starts[i];
|
|
781
|
+
const end = ends[i];
|
|
782
|
+
let row = 0;
|
|
783
|
+
while (row < rowEnds.length && rowEnds[row] > start) {
|
|
784
|
+
row++;
|
|
785
|
+
}
|
|
786
|
+
rowEnds[row] = (end > start ? end : start) + padding;
|
|
787
|
+
packed[k] = row;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
const written = new Map([
|
|
791
|
+
[as, { kind: 'number', values: packed, at: undefined }],
|
|
792
|
+
]);
|
|
793
|
+
return { table: withColumns(table, written, order), bounds };
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Piecewise-constant depth over the rows' spans, per section: one row per run
|
|
797
|
+
* of equal depth, where the depth is not zero. A sweep over the sorted edges,
|
|
798
|
+
* so the input need not be sorted.
|
|
799
|
+
*/
|
|
800
|
+
function coverage({ table, bounds }, step) {
|
|
801
|
+
const as = step.as ?? DEFAULT_COVERAGE_AS;
|
|
802
|
+
const readStart = numberReaderOf(table.column('start'));
|
|
803
|
+
const readEnd = numberReaderOf(table.column('end'));
|
|
804
|
+
const readRefName = readerOf(table.column('refName'));
|
|
805
|
+
// Each edge opens or closes one run at most, so two a row bounds the runs.
|
|
806
|
+
const capacity = 2 * table.length;
|
|
807
|
+
const outStart = new Float64Array(capacity);
|
|
808
|
+
const outEnd = new Float64Array(capacity);
|
|
809
|
+
const outDepth = new Float64Array(capacity);
|
|
810
|
+
const outSection = new Uint32Array(capacity);
|
|
811
|
+
const sectionRef = [];
|
|
812
|
+
const out = new Uint32Array(bounds.length);
|
|
813
|
+
let k = 0;
|
|
814
|
+
for (let s = 0; s + 1 < bounds.length; s++) {
|
|
815
|
+
out[s] = k;
|
|
816
|
+
const lo = bounds[s];
|
|
817
|
+
const hi = bounds[s + 1];
|
|
818
|
+
const spanStarts = new Float64Array(hi - lo);
|
|
819
|
+
const spanEnds = new Float64Array(hi - lo);
|
|
820
|
+
let n = 0;
|
|
821
|
+
for (let i = lo; i < hi; i++) {
|
|
822
|
+
const start = readStart(i);
|
|
823
|
+
const end = readEnd(i);
|
|
824
|
+
if (Number.isFinite(start) && Number.isFinite(end)) {
|
|
825
|
+
spanStarts[n] = start;
|
|
826
|
+
spanEnds[n] = end;
|
|
827
|
+
n++;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
sectionRef.push(n > 0 ? readRefName(lo) : undefined);
|
|
831
|
+
if (n === 0) {
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
const starts = spanStarts.subarray(0, n).sort();
|
|
835
|
+
const ends = spanEnds.subarray(0, n).sort();
|
|
836
|
+
const first = k;
|
|
837
|
+
let depth = 0;
|
|
838
|
+
let runStart = starts[0];
|
|
839
|
+
let si = 0;
|
|
840
|
+
let ei = 0;
|
|
841
|
+
while (si < n || ei < n) {
|
|
842
|
+
const nextStart = si < n ? starts[si] : Infinity;
|
|
843
|
+
const nextEnd = ei < n ? ends[ei] : Infinity;
|
|
844
|
+
const at = Math.min(nextStart, nextEnd);
|
|
845
|
+
if (depth > 0 && at > runStart) {
|
|
846
|
+
if (k > first &&
|
|
847
|
+
outEnd[k - 1] === runStart &&
|
|
848
|
+
outDepth[k - 1] === depth) {
|
|
849
|
+
outEnd[k - 1] = at;
|
|
850
|
+
}
|
|
851
|
+
else {
|
|
852
|
+
outStart[k] = runStart;
|
|
853
|
+
outEnd[k] = at;
|
|
854
|
+
outDepth[k] = depth;
|
|
855
|
+
outSection[k] = s;
|
|
856
|
+
k++;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
runStart = at;
|
|
860
|
+
while (si < n && starts[si] === at) {
|
|
861
|
+
depth++;
|
|
862
|
+
si++;
|
|
863
|
+
}
|
|
864
|
+
while (ei < n && ends[ei] === at) {
|
|
865
|
+
depth--;
|
|
866
|
+
ei++;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
out[bounds.length - 1] = k;
|
|
871
|
+
const section = outSection.slice(0, k);
|
|
872
|
+
const columns = new Map([
|
|
873
|
+
['refName', { kind: 'value', read: i => sectionRef[section[i]] }],
|
|
874
|
+
['start', { kind: 'number', values: outStart.slice(0, k), at: undefined }],
|
|
875
|
+
['end', { kind: 'number', values: outEnd.slice(0, k), at: undefined }],
|
|
876
|
+
[as, { kind: 'number', values: outDepth.slice(0, k), at: undefined }],
|
|
877
|
+
]);
|
|
878
|
+
return {
|
|
879
|
+
table: new MadeTable(k, columns, () => ''),
|
|
880
|
+
bounds: out,
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
function runStep(staged, step, jexl) {
|
|
884
|
+
switch (step.type) {
|
|
885
|
+
case 'filter': {
|
|
886
|
+
return filter(staged, step.expr, jexl);
|
|
887
|
+
}
|
|
888
|
+
case 'formula': {
|
|
889
|
+
return formula(staged, step.expr, step.as, jexl);
|
|
890
|
+
}
|
|
891
|
+
case 'flatten': {
|
|
892
|
+
return flatten(staged, step);
|
|
893
|
+
}
|
|
894
|
+
case 'cells': {
|
|
895
|
+
return cells(staged, step);
|
|
896
|
+
}
|
|
897
|
+
case 'bin': {
|
|
898
|
+
return bin(staged, step);
|
|
899
|
+
}
|
|
900
|
+
case 'aggregate': {
|
|
901
|
+
return aggregate(staged, step);
|
|
902
|
+
}
|
|
903
|
+
case 'coverage': {
|
|
904
|
+
return coverage(staged, step);
|
|
905
|
+
}
|
|
906
|
+
case 'pileup': {
|
|
907
|
+
return pileup(staged, step);
|
|
908
|
+
}
|
|
909
|
+
case 'mate': {
|
|
910
|
+
return mates(staged);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
function runSteps(staged, steps, jexl) {
|
|
915
|
+
let current = staged;
|
|
916
|
+
const list = steps ?? [];
|
|
917
|
+
for (let k = 0; k < list.length; k++) {
|
|
918
|
+
const step = list[k];
|
|
919
|
+
const next = list[k + 1];
|
|
920
|
+
const after = list[k + 2];
|
|
921
|
+
const matches = step.type === 'cells' &&
|
|
922
|
+
next?.type === 'bin' &&
|
|
923
|
+
after?.type === 'aggregate' &&
|
|
924
|
+
fusesCellMatches(step, next, after)
|
|
925
|
+
? binnedCellMatches(current, step, next, after)
|
|
926
|
+
: undefined;
|
|
927
|
+
const fused = !matches &&
|
|
928
|
+
step.type === 'bin' &&
|
|
929
|
+
next?.type === 'aggregate' &&
|
|
930
|
+
fusesBinAggregate(step, next)
|
|
931
|
+
? binnedAggregate(current, step, next)
|
|
932
|
+
: undefined;
|
|
933
|
+
if (matches) {
|
|
934
|
+
current = matches;
|
|
935
|
+
k += 2;
|
|
936
|
+
}
|
|
937
|
+
else if (fused) {
|
|
938
|
+
current = fused;
|
|
939
|
+
k++;
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
current = runStep(current, step, jexl);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return current;
|
|
946
|
+
}
|
|
947
|
+
/**
|
|
948
|
+
* Each layer's steps over `steps` run once for all of them. A trailing
|
|
949
|
+
* `cells` runs inside each layer whose own steps start with the bin and
|
|
950
|
+
* aggregate it fuses with, so `runSteps` meets the three together, and once
|
|
951
|
+
* for the other layers.
|
|
952
|
+
*/
|
|
953
|
+
function runLayers(staged, steps, layers, jexl, keep = s => s) {
|
|
954
|
+
const list = steps ?? [];
|
|
955
|
+
const last = list.at(-1);
|
|
956
|
+
const trailing = last?.type === 'cells' && layers.some(own => fusesAfterCells(last, own))
|
|
957
|
+
? last
|
|
958
|
+
: undefined;
|
|
959
|
+
if (!trailing) {
|
|
960
|
+
const shared = keep(runSteps(staged, list, jexl), list);
|
|
961
|
+
return layers.map(own => keep(runSteps(shared, own, jexl), own));
|
|
962
|
+
}
|
|
963
|
+
const ahead = runSteps(staged, list.slice(0, -1), jexl);
|
|
964
|
+
let shared;
|
|
965
|
+
return layers.map(own => fusesAfterCells(trailing, own)
|
|
966
|
+
? keep(runSteps(ahead, [trailing, ...own], jexl), [...list, ...own])
|
|
967
|
+
: keep(runSteps((shared ??= keep(runStep(ahead, trailing, jexl), list)), own, jexl), own));
|
|
968
|
+
}
|
|
969
|
+
function rowOf(value) {
|
|
970
|
+
const row = Number(value);
|
|
971
|
+
return row > 0 ? Math.floor(row) : 0;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* A section's rows behind a step that made them from nothing, a coverage's
|
|
975
|
+
* runs or an aggregate's groups, still answer the field their section was
|
|
976
|
+
* split on, as a ggplot2 stat keeps its facet variable: one column of each
|
|
977
|
+
* section's key, built the first time a channel reads it, and a parent that
|
|
978
|
+
* carries the field itself is read instead.
|
|
979
|
+
*/
|
|
980
|
+
class SectionTable extends DerivedTable {
|
|
981
|
+
field;
|
|
982
|
+
labels;
|
|
983
|
+
bounds;
|
|
984
|
+
constructor(parent, field, labels, bounds) {
|
|
985
|
+
super(parent, undefined);
|
|
986
|
+
this.field = field;
|
|
987
|
+
this.labels = labels;
|
|
988
|
+
this.bounds = bounds;
|
|
989
|
+
}
|
|
990
|
+
own(field) {
|
|
991
|
+
if (field !== this.field || this.parent.column(field).kind !== 'none') {
|
|
992
|
+
return undefined;
|
|
993
|
+
}
|
|
994
|
+
const { labels } = this;
|
|
995
|
+
const codes = new Uint32Array(this.length);
|
|
996
|
+
for (let s = 0; s < labels.length; s++) {
|
|
997
|
+
codes.fill(s, this.bounds[s], this.bounds[s + 1]);
|
|
998
|
+
}
|
|
999
|
+
// the section of the rows with nothing in the field answers nothing
|
|
1000
|
+
return labels.includes('')
|
|
1001
|
+
? { kind: 'value', read: i => labels[codes[i]] || undefined }
|
|
1002
|
+
: { kind: 'category', codes, labels, at: undefined };
|
|
1003
|
+
}
|
|
1004
|
+
json(i) {
|
|
1005
|
+
const out = super.json(i);
|
|
1006
|
+
const label = valueAt(this.column(this.field), i);
|
|
1007
|
+
return label === undefined || this.field in out
|
|
1008
|
+
? out
|
|
1009
|
+
: { ...out, [this.field]: label };
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
function makesRows(steps) {
|
|
1013
|
+
return steps?.some(s => s.type === 'aggregate' || s.type === 'coverage');
|
|
1014
|
+
}
|
|
1015
|
+
// The staged rows still naming their section's value where a step made them
|
|
1016
|
+
function keepingSection(staged, steps, field, labels) {
|
|
1017
|
+
return !isJexl(field) && makesRows(steps)
|
|
1018
|
+
? {
|
|
1019
|
+
...staged,
|
|
1020
|
+
table: new SectionTable(staged.table, field, labels, staged.bounds),
|
|
1021
|
+
}
|
|
1022
|
+
: staged;
|
|
1023
|
+
}
|
|
1024
|
+
/**
|
|
1025
|
+
* #api
|
|
1026
|
+
* A faceted request's layers: the rows split on the facet's field, the
|
|
1027
|
+
* facet's own steps and then each layer's run over each section alone, and
|
|
1028
|
+
* the sections stacked — a section's rows start where the one above it ends,
|
|
1029
|
+
* and it is as tall as the tallest layer packed it. Every layer's rows come
|
|
1030
|
+
* back in section order beside their stacked rows, so a faceted display is
|
|
1031
|
+
* the unfaceted one drawn once per section, and a row is handed on as its
|
|
1032
|
+
* steps left it. A layer naming no `row` field stands on each section's first
|
|
1033
|
+
* row, the answer the unfaceted encoder gives it.
|
|
1034
|
+
*
|
|
1035
|
+
* The split is a counting sort into section order rather than a list per
|
|
1036
|
+
* section: every step runs once over the ordered rows, keeping section order,
|
|
1037
|
+
* and one that groups rows groups within a section.
|
|
1038
|
+
*/
|
|
1039
|
+
export function facetLayers(input, facet, layers, jexl) {
|
|
1040
|
+
const table = asTable(input);
|
|
1041
|
+
const { field, transform: sectionSteps } = facet;
|
|
1042
|
+
const categories = categoricalField(field);
|
|
1043
|
+
const n = table.length;
|
|
1044
|
+
const sectionOfKey = new Map();
|
|
1045
|
+
const keyOfRow = new Uint32Array(n);
|
|
1046
|
+
const keys = [];
|
|
1047
|
+
const keyIndex = (key) => {
|
|
1048
|
+
let k = sectionOfKey.get(key);
|
|
1049
|
+
if (k === undefined) {
|
|
1050
|
+
k = keys.length;
|
|
1051
|
+
sectionOfKey.set(key, k);
|
|
1052
|
+
keys.push(key);
|
|
1053
|
+
}
|
|
1054
|
+
return k;
|
|
1055
|
+
};
|
|
1056
|
+
const column = isPlainFieldRef(field) ? table.column(field) : undefined;
|
|
1057
|
+
if (column?.kind === 'category') {
|
|
1058
|
+
// A label's key is filed once, and each row looks its code up.
|
|
1059
|
+
const { codes, labels, at } = column;
|
|
1060
|
+
const ofCode = new Int32Array(labels.length).fill(-1);
|
|
1061
|
+
for (let i = 0; i < n; i++) {
|
|
1062
|
+
const code = codes[at ? at[i] : i];
|
|
1063
|
+
let k = ofCode[code];
|
|
1064
|
+
if (k < 0) {
|
|
1065
|
+
k = keyIndex(categories.key(labels[code]));
|
|
1066
|
+
ofCode[code] = k;
|
|
1067
|
+
}
|
|
1068
|
+
keyOfRow[i] = k;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
else {
|
|
1072
|
+
const read = column
|
|
1073
|
+
? readerOf(column)
|
|
1074
|
+
: (() => {
|
|
1075
|
+
const r = fieldReader(field, jexl);
|
|
1076
|
+
return (i) => r(table.row(i));
|
|
1077
|
+
})();
|
|
1078
|
+
for (let i = 0; i < n; i++) {
|
|
1079
|
+
keyOfRow[i] = keyIndex(categories.key(read(i)));
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
const ordered = [...keys.keys()].sort((a, b) => categories.compare(keys[a], keys[b]));
|
|
1083
|
+
const sectionOf = new Uint32Array(keys.length);
|
|
1084
|
+
for (const [s, k] of ordered.entries()) {
|
|
1085
|
+
sectionOf[k] = s;
|
|
1086
|
+
}
|
|
1087
|
+
const bounds = new Uint32Array(keys.length + 1);
|
|
1088
|
+
for (let i = 0; i < n; i++) {
|
|
1089
|
+
bounds[sectionOf[keyOfRow[i]] + 1]++;
|
|
1090
|
+
}
|
|
1091
|
+
for (let s = 0; s < keys.length; s++) {
|
|
1092
|
+
bounds[s + 1] = bounds[s + 1] + bounds[s];
|
|
1093
|
+
}
|
|
1094
|
+
const next = bounds.slice(0, keys.length);
|
|
1095
|
+
const order = new Uint32Array(n);
|
|
1096
|
+
for (let i = 0; i < n; i++) {
|
|
1097
|
+
order[next[sectionOf[keyOfRow[i]]]++] = i;
|
|
1098
|
+
}
|
|
1099
|
+
const labels = ordered.map(k => keys[k]);
|
|
1100
|
+
const layered = runLayers({ table: selectRows(table, order), bounds }, sectionSteps, layers.map(({ transform }) => transform), jexl, (staged, steps) => keepingSection(staged, steps, field, labels));
|
|
1101
|
+
const placed = layers.map(({ row }, l) => {
|
|
1102
|
+
const out = layered[l];
|
|
1103
|
+
const readRow = row === undefined
|
|
1104
|
+
? undefined
|
|
1105
|
+
: isPlainFieldRef(row)
|
|
1106
|
+
? readerOf(out.table.column(row))
|
|
1107
|
+
: (() => {
|
|
1108
|
+
const r = fieldReader(row, jexl);
|
|
1109
|
+
return (i) => r(out.table.row(i));
|
|
1110
|
+
})();
|
|
1111
|
+
const local = new Uint32Array(out.table.length);
|
|
1112
|
+
if (readRow) {
|
|
1113
|
+
for (let i = 0; i < local.length; i++) {
|
|
1114
|
+
local[i] = rowOf(readRow(i));
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
return { ...out, local };
|
|
1118
|
+
});
|
|
1119
|
+
const rowCount = new Uint32Array(keys.length).fill(1);
|
|
1120
|
+
for (const { bounds: b, local } of placed) {
|
|
1121
|
+
for (let s = 0; s < keys.length; s++) {
|
|
1122
|
+
for (let i = b[s]; i < b[s + 1]; i++) {
|
|
1123
|
+
if (local[i] + 1 > rowCount[s]) {
|
|
1124
|
+
rowCount[s] = local[i] + 1;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
const sections = [];
|
|
1130
|
+
const firstRow = new Uint32Array(keys.length);
|
|
1131
|
+
let stacked = 0;
|
|
1132
|
+
for (const [s, k] of ordered.entries()) {
|
|
1133
|
+
firstRow[s] = stacked;
|
|
1134
|
+
sections.push({ key: keys[k], firstRow: stacked, rowCount: rowCount[s] });
|
|
1135
|
+
stacked += rowCount[s];
|
|
1136
|
+
}
|
|
1137
|
+
return {
|
|
1138
|
+
layers: placed.map(({ table: t, bounds: b, local }) => {
|
|
1139
|
+
const rows = new Uint32Array(t.length);
|
|
1140
|
+
for (let s = 0; s < keys.length; s++) {
|
|
1141
|
+
for (let i = b[s]; i < b[s + 1]; i++) {
|
|
1142
|
+
rows[i] = firstRow[s] + local[i];
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return { table: t, rows };
|
|
1146
|
+
}),
|
|
1147
|
+
sections,
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* #api
|
|
1152
|
+
* Run the transform steps over a feature list or a table, in order, in the
|
|
1153
|
+
* worker. The table a step answers is what the next one reads, and the last
|
|
1154
|
+
* one is what the encoder walks.
|
|
1155
|
+
*/
|
|
1156
|
+
export function runTransforms(input, steps, jexl) {
|
|
1157
|
+
const table = asTable(input);
|
|
1158
|
+
return runSteps({ table, bounds: oneSection(table.length) }, steps, jexl)
|
|
1159
|
+
.table;
|
|
1160
|
+
}
|
|
1161
|
+
// The fields a step writes onto its rows, which a partition on one of them
|
|
1162
|
+
// has to wait for; none for a step that must see every row at once.
|
|
1163
|
+
function writes(step) {
|
|
1164
|
+
switch (step.type) {
|
|
1165
|
+
case 'filter': {
|
|
1166
|
+
return [];
|
|
1167
|
+
}
|
|
1168
|
+
case 'formula': {
|
|
1169
|
+
return [step.as];
|
|
1170
|
+
}
|
|
1171
|
+
case 'bin': {
|
|
1172
|
+
const as = step.as ?? DEFAULT_BIN_AS;
|
|
1173
|
+
return step.fields ? [...as, BIN_OVERLAP_FIELD] : as;
|
|
1174
|
+
}
|
|
1175
|
+
case 'cells': {
|
|
1176
|
+
return ['start', 'end', 'state', 'base', 'match', 'length'];
|
|
1177
|
+
}
|
|
1178
|
+
default: {
|
|
1179
|
+
return undefined;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* How many of `steps` must run before rows can be split on `field`: the rest
|
|
1185
|
+
* each read a row and answer rows of it in order without writing `field`, so
|
|
1186
|
+
* running them after the split answers the same rows in the same order. A step
|
|
1187
|
+
* that groups rows, fans a row out into entries that may carry their own
|
|
1188
|
+
* `field`, or pairs rows up must run before it, and so must everything ahead
|
|
1189
|
+
* of it.
|
|
1190
|
+
*/
|
|
1191
|
+
function partitionPoint(steps, field) {
|
|
1192
|
+
if (!isPlainFieldRef(field)) {
|
|
1193
|
+
return steps.length;
|
|
1194
|
+
}
|
|
1195
|
+
let at = steps.length;
|
|
1196
|
+
while (at > 0 && writes(steps[at - 1])?.includes(field) === false) {
|
|
1197
|
+
at--;
|
|
1198
|
+
}
|
|
1199
|
+
return at;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* #api
|
|
1203
|
+
* A layered request's rows: the shared steps, the facet's split where it
|
|
1204
|
+
* names one, and each layer's own steps, with the row each layer's rows stand
|
|
1205
|
+
* in — the field it names, or under a facet each row's stacked row. The split
|
|
1206
|
+
* comes as early as it can: after the last shared step that must see every
|
|
1207
|
+
* row, so the steps that follow it read the rows already in section order.
|
|
1208
|
+
*/
|
|
1209
|
+
export function layerTables(input, request, jexl) {
|
|
1210
|
+
const { transform = [], facet, layers } = request;
|
|
1211
|
+
if (!facet) {
|
|
1212
|
+
const table = asTable(input);
|
|
1213
|
+
const layered = runLayers({ table, bounds: oneSection(table.length) }, transform, layers.map(layer => layer.transform), jexl);
|
|
1214
|
+
return {
|
|
1215
|
+
layers: layers.map((layer, l) => ({
|
|
1216
|
+
table: layered[l].table,
|
|
1217
|
+
row: layer.row,
|
|
1218
|
+
})),
|
|
1219
|
+
sections: undefined,
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
const at = partitionPoint(transform, facet.field);
|
|
1223
|
+
const split = facetLayers(runTransforms(input, transform.slice(0, at), jexl), {
|
|
1224
|
+
...facet,
|
|
1225
|
+
transform: [...transform.slice(at), ...(facet.transform ?? [])],
|
|
1226
|
+
}, layers, jexl);
|
|
1227
|
+
return {
|
|
1228
|
+
layers: split.layers.map(({ table, rows }) => ({ table, row: rows })),
|
|
1229
|
+
sections: split.sections,
|
|
1230
|
+
};
|
|
1231
|
+
}
|