@jbrowse/core 5.0.0-beta.8 → 5.0.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) hide show
  1. package/README.md +427 -130
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.d.ts +3 -2
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +5 -3
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts +3 -5
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.js +8 -9
  6. package/esm/BaseFeatureWidget/BaseFeatureDetail/CoreDetails.js +8 -13
  7. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -1
  8. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.js +3 -3
  9. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.d.ts +8 -0
  10. package/esm/BaseFeatureWidget/BaseFeatureDetail/FieldActionsButton.js +24 -0
  11. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.d.ts +3 -2
  12. package/esm/BaseFeatureWidget/BaseFeatureDetail/SimpleField.js +5 -3
  13. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.d.ts +1 -0
  14. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +1 -4
  15. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.d.ts +16 -0
  16. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +53 -0
  17. package/esm/BaseFeatureWidget/BaseFeatureDetail/util.d.ts +0 -8
  18. package/esm/BaseFeatureWidget/BaseFeatureDetail/util.js +0 -16
  19. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceContents.js +7 -34
  20. package/esm/BaseFeatureWidget/configSchema.d.ts +1 -1
  21. package/esm/BaseFeatureWidget/formatDetails.d.ts +13 -29
  22. package/esm/BaseFeatureWidget/formatDetails.js +46 -79
  23. package/esm/BaseFeatureWidget/index.d.ts +1 -0
  24. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +35 -28
  25. package/esm/BaseFeatureWidget/stateModelFactory.js +94 -102
  26. package/esm/BaseFeatureWidget/types.d.ts +3 -0
  27. package/esm/BaseFeatureWidget/util.d.ts +0 -3
  28. package/esm/BaseFeatureWidget/util.js +0 -17
  29. package/esm/PluginLoader.d.ts +14 -9
  30. package/esm/PluginLoader.js +34 -26
  31. package/esm/PluginManager.d.ts +4 -4
  32. package/esm/PluginManager.js +1 -1
  33. package/esm/ReExports/coreModules.generated.d.ts +2 -0
  34. package/esm/ReExports/coreModules.generated.js +492 -0
  35. package/esm/ReExports/coreWorkerModules.generated.d.ts +2 -0
  36. package/esm/ReExports/coreWorkerModules.generated.js +453 -0
  37. package/esm/ReExports/frameworkModules.d.ts +2 -0
  38. package/esm/ReExports/frameworkModules.js +67 -0
  39. package/esm/ReExports/frameworkShared.d.ts +12 -0
  40. package/esm/ReExports/frameworkShared.js +16 -0
  41. package/esm/ReExports/frameworkWorkerModules.generated.d.ts +2 -0
  42. package/esm/ReExports/frameworkWorkerModules.generated.js +130 -0
  43. package/esm/ReExports/list.js +493 -79
  44. package/esm/ReExports/modules.d.ts +1 -1
  45. package/esm/ReExports/modules.js +10 -87
  46. package/esm/ReExports/registry.d.ts +1 -0
  47. package/esm/ReExports/registry.js +23 -5
  48. package/esm/ReExports/uiStub.d.ts +2 -1
  49. package/esm/ReExports/uiStub.js +24 -2
  50. package/esm/ReExports/workerModules.js +8 -12
  51. package/esm/TextSearch/TextSearchManager.d.ts +3 -12
  52. package/esm/TextSearch/TextSearchManager.js +22 -10
  53. package/esm/assemblyManager/assembly.d.ts +10 -14
  54. package/esm/assemblyManager/assembly.js +10 -14
  55. package/esm/assemblyManager/assemblyConfigSchema.d.ts +23 -81
  56. package/esm/assemblyManager/assemblyManager.d.ts +10 -16
  57. package/esm/assemblyManager/assemblyManager.js +7 -10
  58. package/esm/assemblyManager/loadRefNameMap.js +3 -3
  59. package/esm/configuration/configurationSchema.d.ts +75 -31
  60. package/esm/configuration/configurationSchema.js +74 -40
  61. package/esm/configuration/configurationSchemaUnion.d.ts +39 -0
  62. package/esm/configuration/configurationSchemaUnion.js +59 -0
  63. package/esm/configuration/configurationSlot.d.ts +37 -12
  64. package/esm/configuration/configurationSlot.js +83 -22
  65. package/esm/configuration/formatAboutConfigSchema.d.ts +7 -21
  66. package/esm/configuration/formatDetailsConfigSchema.d.ts +11 -37
  67. package/esm/configuration/formatDetailsConfigSchema.js +10 -13
  68. package/esm/configuration/getConf.d.ts +17 -9
  69. package/esm/configuration/getConf.js +52 -7
  70. package/esm/configuration/index.d.ts +11 -4
  71. package/esm/configuration/index.js +7 -4
  72. package/esm/configuration/mergeFormatCallbacks.d.ts +6 -7
  73. package/esm/configuration/mergeFormatCallbacks.js +13 -10
  74. package/esm/configuration/readConfObject.d.ts +2 -22
  75. package/esm/configuration/readConfObject.js +15 -49
  76. package/esm/configuration/requirements.d.ts +37 -0
  77. package/esm/configuration/requirements.js +88 -0
  78. package/esm/configuration/schemaRegistry.d.ts +21 -1
  79. package/esm/configuration/schemaRegistry.js +11 -0
  80. package/esm/configuration/schemaTypes.d.ts +3 -0
  81. package/esm/configuration/schemaTypes.js +10 -0
  82. package/esm/configuration/slotFacade.d.ts +35 -4
  83. package/esm/configuration/slotFacade.js +96 -9
  84. package/esm/configuration/snapshotPreprocess.d.ts +27 -0
  85. package/esm/configuration/snapshotPreprocess.js +102 -0
  86. package/esm/configuration/types.d.ts +161 -22
  87. package/esm/data_adapters/BaseAdapter/BaseAdapter.d.ts +2 -2
  88. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +11 -2
  89. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +12 -1
  90. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +2 -3
  91. package/esm/data_adapters/BaseAdapter/featureDensity.js +2 -3
  92. package/esm/data_adapters/BaseAdapter/index.d.ts +22 -3
  93. package/esm/data_adapters/BaseAdapter/types.d.ts +3 -4
  94. package/esm/data_adapters/BaseAdapter/zoomRange.d.ts +10 -0
  95. package/esm/data_adapters/BaseAdapter/zoomRange.js +1 -0
  96. package/esm/data_adapters/CytobandAdapter/configSchema.d.ts +9 -11
  97. package/esm/data_adapters/getSequenceSubAdapter.d.ts +1 -3
  98. package/esm/data_adapters/getSequenceSubAdapter.js +1 -3
  99. package/esm/pluggableElementTypes/AdapterType.d.ts +7 -7
  100. package/esm/pluggableElementTypes/RpcMethodType.d.ts +1 -1
  101. package/esm/pluggableElementTypes/RpcMethodType.js +3 -8
  102. package/esm/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions.d.ts +1 -2
  103. package/esm/pluggableElementTypes/TextSearchAdapterType.d.ts +7 -7
  104. package/esm/pluggableElementTypes/index.d.ts +1 -1
  105. package/esm/pluggableElementTypes/index.js +1 -1
  106. package/esm/pluggableElementTypes/models/BaseConnectionModelFactory.d.ts +17 -7
  107. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +45 -48
  108. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +40 -36
  109. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +10 -13
  110. package/esm/pluggableElementTypes/models/BaseTrackModel.js +6 -6
  111. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +37 -17
  112. package/esm/pluggableElementTypes/models/BaseViewModel.js +25 -10
  113. package/esm/pluggableElementTypes/models/InternetAccountModel.d.ts +26 -16
  114. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +1 -1
  115. package/esm/pluggableElementTypes/models/baseConnectionConfig.d.ts +22 -18
  116. package/esm/pluggableElementTypes/models/baseConnectionConfig.js +5 -5
  117. package/esm/pluggableElementTypes/models/baseInternetAccountConfig.d.ts +26 -31
  118. package/esm/pluggableElementTypes/models/baseTrackConfig.d.ts +57 -141
  119. package/esm/pluggableElementTypes/models/baseTrackConfig.js +22 -26
  120. package/esm/pluggableElementTypes/models/components/SaveTrackData.js +2 -2
  121. package/esm/pluggableElementTypes/models/components/fetchTrackData.d.ts +3 -4
  122. package/esm/pluggableElementTypes/models/components/fetchTrackData.js +3 -3
  123. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.d.ts +15 -7
  124. package/esm/pluggableElementTypes/models/expandTrackConfigShorthand.js +38 -29
  125. package/esm/pluggableElementTypes/models/index.d.ts +1 -2
  126. package/esm/pluggableElementTypes/models/index.js +1 -2
  127. package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.d.ts +3 -3
  128. package/esm/pluggableElementTypes/models/saveTrackFileTypes/genbank.js +4 -4
  129. package/esm/pluggableElementTypes/models/saveTrackFileTypes/types.d.ts +3 -3
  130. package/esm/rpc/BaseRpcDriver.d.ts +1 -2
  131. package/esm/rpc/BaseRpcDriver.js +23 -30
  132. package/esm/rpc/MainThreadRpcDriver.d.ts +2 -2
  133. package/esm/rpc/MainThreadRpcDriver.js +13 -8
  134. package/esm/rpc/RpcClient.d.ts +17 -6
  135. package/esm/rpc/RpcClient.js +42 -12
  136. package/esm/rpc/RpcManager.d.ts +8 -10
  137. package/esm/rpc/RpcManager.js +1 -1
  138. package/esm/rpc/RpcRegistry.d.ts +8 -2
  139. package/esm/rpc/RpcServer.d.ts +3 -1
  140. package/esm/rpc/RpcServer.js +19 -12
  141. package/esm/rpc/WebWorkerRpcDriver.d.ts +3 -3
  142. package/esm/rpc/WebWorkerRpcDriver.js +9 -47
  143. package/esm/rpc/byteBudget.d.ts +3 -5
  144. package/esm/rpc/byteBudget.js +4 -4
  145. package/esm/rpc/configSchema.d.ts +7 -21
  146. package/esm/rpc/coreRpcMethods.d.ts +1 -0
  147. package/esm/rpc/coreRpcMethods.js +1 -0
  148. package/esm/rpc/methods/CoreEncodeFeatures.d.ts +6 -5
  149. package/esm/rpc/methods/CoreEncodeFeatures.js +26 -31
  150. package/esm/rpc/methods/CoreGetEncodedFeature.d.ts +13 -0
  151. package/esm/rpc/methods/CoreGetEncodedFeature.js +31 -0
  152. package/esm/rpc/methods/CoreGetExportData.js +2 -2
  153. package/esm/rpc/methods/CoreGetFeatureDensity.js +2 -2
  154. package/esm/rpc/methods/CoreGetFeatures.js +2 -2
  155. package/esm/rpc/methods/CoreGetSequence.js +2 -2
  156. package/esm/rpc/methods/layerFeatures.d.ts +26 -0
  157. package/esm/rpc/methods/layerFeatures.js +40 -0
  158. package/esm/svg/SvgExport.js +3 -4
  159. package/esm/svg/SvgThemeProviders.d.ts +12 -0
  160. package/esm/svg/SvgThemeProviders.js +15 -0
  161. package/esm/svg/exportViewSvg.d.ts +32 -0
  162. package/esm/svg/exportViewSvg.js +13 -0
  163. package/esm/svg/normalizeSvgMarkup.d.ts +7 -0
  164. package/esm/svg/normalizeSvgMarkup.js +99 -0
  165. package/esm/svg/serializeSvg.d.ts +7 -0
  166. package/esm/svg/serializeSvg.js +11 -0
  167. package/esm/svg/svgReady.d.ts +8 -7
  168. package/esm/svg/svgReady.js +8 -7
  169. package/esm/svg/trackNames.d.ts +5 -5
  170. package/esm/svg/trackNames.js +6 -6
  171. package/esm/svg/wrapSvgExport.js +6 -74
  172. package/esm/ui/CascadingMenu.js +83 -86
  173. package/esm/ui/ErrorMessageStackTraceDialog.js +0 -5
  174. package/esm/ui/FileSelector/useInternetAccounts.d.ts +156 -96
  175. package/esm/ui/HoverMenu.d.ts +1 -2
  176. package/esm/ui/HoverMenu.js +6 -3
  177. package/esm/ui/JexlFilterDialog.d.ts +13 -10
  178. package/esm/ui/JexlFilterDialog.js +122 -49
  179. package/esm/ui/JexlFilterRowEditors.d.ts +15 -0
  180. package/esm/ui/JexlFilterRowEditors.js +90 -0
  181. package/esm/ui/LazyBaseTooltip.d.ts +4 -0
  182. package/esm/ui/LazyBaseTooltip.js +9 -0
  183. package/esm/ui/LoadingOverlay.js +3 -1
  184. package/esm/ui/MonospaceTextField.d.ts +2 -1
  185. package/esm/ui/MonospaceTextField.js +21 -19
  186. package/esm/ui/PaletteContext.d.ts +7 -9
  187. package/esm/ui/PaletteContext.js +24 -10
  188. package/esm/ui/RefNameAutocomplete/index.d.ts +1 -2
  189. package/esm/ui/RefNameAutocomplete/index.js +1 -1
  190. package/esm/ui/ScrollChrome.d.ts +6 -9
  191. package/esm/ui/ScrollChrome.js +5 -6
  192. package/esm/ui/ScrollEdgeShadow.d.ts +6 -9
  193. package/esm/ui/ScrollEdgeShadow.js +9 -24
  194. package/esm/ui/SettingsChangesTable.js +3 -3
  195. package/esm/ui/VerticalScrollbar.d.ts +13 -34
  196. package/esm/ui/VerticalScrollbar.js +29 -83
  197. package/esm/ui/ViewLoadingScreen.d.ts +2 -2
  198. package/esm/ui/ViewLoadingScreen.js +3 -3
  199. package/esm/ui/colorScale.d.ts +26 -1
  200. package/esm/ui/colorScale.js +28 -5
  201. package/esm/ui/colors.d.ts +49 -1
  202. package/esm/ui/colors.js +139 -4
  203. package/esm/ui/hoverBoxStyle.d.ts +14 -2
  204. package/esm/ui/hoverBoxStyle.js +17 -2
  205. package/esm/ui/index.d.ts +5 -3
  206. package/esm/ui/index.js +9 -7
  207. package/esm/ui/launchViewMenu.js +3 -3
  208. package/esm/ui/legendSpec.d.ts +2 -0
  209. package/esm/ui/legendSpec.js +3 -0
  210. package/esm/ui/palette.d.ts +0 -1
  211. package/esm/ui/palette.js +3 -27
  212. package/esm/ui/replaceViewAction.d.ts +1 -1
  213. package/esm/ui/replaceViewAction.js +1 -1
  214. package/esm/ui/theme.d.ts +1 -1
  215. package/esm/ui/theme.js +6 -40
  216. package/esm/ui/viewHeaderHeight.d.ts +1 -0
  217. package/esm/ui/viewHeaderHeight.js +1 -0
  218. package/esm/util/Base1DUtils.d.ts +1 -1
  219. package/esm/util/Base1DUtils.js +2 -2
  220. package/esm/util/SvgCanvas.d.ts +15 -13
  221. package/esm/util/SvgCanvas.js +72 -53
  222. package/esm/util/aborting.d.ts +39 -0
  223. package/esm/util/aborting.js +84 -0
  224. package/esm/util/adapterMetadata.d.ts +1 -1
  225. package/esm/util/adapterMetadata.js +6 -6
  226. package/esm/util/addAndShowTrack.d.ts +1 -4
  227. package/esm/util/addRelativeUris.d.ts +10 -2
  228. package/esm/util/addRelativeUris.js +22 -7
  229. package/esm/util/addTrackFromWidget.d.ts +2 -5
  230. package/esm/util/animationAllowed.d.ts +9 -0
  231. package/esm/util/animationAllowed.js +13 -0
  232. package/esm/util/applyRowResizeWheel.d.ts +10 -5
  233. package/esm/util/applyRowResizeWheel.js +10 -21
  234. package/esm/util/bandLayout.d.ts +4 -4
  235. package/esm/util/bandLayout.js +4 -4
  236. package/esm/util/bezierConnector.js +5 -4
  237. package/esm/util/bgzfWorkerPool.d.ts +20 -74
  238. package/esm/util/bgzfWorkerPool.js +20 -74
  239. package/esm/util/cachedSetup.d.ts +1 -1
  240. package/esm/util/cachedSetup.js +2 -2
  241. package/esm/util/categoricalField.d.ts +37 -0
  242. package/esm/util/categoricalField.js +52 -0
  243. package/esm/util/color/cssColorsLevel4.d.ts +1 -0
  244. package/esm/util/color/cssColorsLevel4.js +1 -0
  245. package/esm/util/color/index.d.ts +5 -3
  246. package/esm/util/color/index.js +7 -4
  247. package/esm/util/colorBits.d.ts +1 -2
  248. package/esm/util/colorBits.js +17 -39
  249. package/esm/util/colorRamp.d.ts +27 -1
  250. package/esm/util/colorRamp.js +56 -2
  251. package/esm/util/colorSchemes.d.ts +9 -0
  252. package/esm/util/colorSchemes.js +7 -0
  253. package/esm/util/{createStopTokenRotation.d.ts → createAbortRotation.d.ts} +11 -14
  254. package/esm/util/{createStopTokenRotation.js → createAbortRotation.js} +14 -26
  255. package/esm/util/cssColorParse.d.ts +15 -0
  256. package/esm/util/cssColorParse.js +53 -0
  257. package/esm/util/diagonalizeRegions.d.ts +2 -3
  258. package/esm/util/diagonalizeRegions.js +7 -12
  259. package/esm/util/expandLooseSearchIndex.d.ts +7 -0
  260. package/esm/util/expandLooseSearchIndex.js +25 -0
  261. package/esm/util/featureTransforms.d.ts +30 -3
  262. package/esm/util/featureTransforms.js +233 -36
  263. package/esm/util/fetchAndMaybeUnzip.js +5 -6
  264. package/esm/util/fetchContext.d.ts +5 -6
  265. package/esm/util/fetchContext.js +1 -1
  266. package/esm/util/fetchHub.d.ts +3 -1
  267. package/esm/util/fetchHub.js +2 -2
  268. package/esm/util/fetchSeq.d.ts +2 -3
  269. package/esm/util/fetchSeq.js +2 -2
  270. package/esm/util/fieldReader.d.ts +17 -0
  271. package/esm/util/fieldReader.js +62 -0
  272. package/esm/util/groupKeys.d.ts +75 -0
  273. package/esm/util/groupKeys.js +152 -0
  274. package/esm/util/highlights.d.ts +6 -4
  275. package/esm/util/highlights.js +12 -25
  276. package/esm/util/hooks.d.ts +1 -2
  277. package/esm/util/hooks.js +1 -2
  278. package/esm/util/index.d.ts +3 -3
  279. package/esm/util/index.js +4 -3
  280. package/esm/util/indexCandidates.js +1 -1
  281. package/esm/util/installFetch.d.ts +13 -10
  282. package/esm/util/installFetch.js +11 -10
  283. package/esm/util/installPrerequisiteFetch.d.ts +5 -3
  284. package/esm/util/installPrerequisiteFetch.js +3 -4
  285. package/esm/util/io/index.js +12 -12
  286. package/esm/util/isDataCurrent.d.ts +7 -5
  287. package/esm/util/isDataCurrent.js +9 -6
  288. package/esm/util/jexl.js +24 -21
  289. package/esm/util/jexlFilterRows.d.ts +89 -0
  290. package/esm/util/jexlFilterRows.js +252 -0
  291. package/esm/util/jexlFilters.d.ts +7 -5
  292. package/esm/util/jexlStrings.d.ts +3 -4
  293. package/esm/util/jexlStrings.js +2 -3
  294. package/esm/util/legendCandidates.d.ts +31 -27
  295. package/esm/util/legendCandidates.js +79 -53
  296. package/esm/util/localStorage.js +4 -4
  297. package/esm/util/markEncoding.d.ts +32 -16
  298. package/esm/util/markEncoding.js +177 -150
  299. package/esm/util/markEncodingTypes.d.ts +137 -66
  300. package/esm/util/mstUtils.d.ts +19 -22
  301. package/esm/util/mstUtils.js +19 -22
  302. package/esm/util/numericUtils.d.ts +7 -0
  303. package/esm/util/numericUtils.js +16 -0
  304. package/esm/util/numericValue.d.ts +14 -0
  305. package/esm/util/numericValue.js +34 -0
  306. package/esm/util/openFeatureWidget.js +1 -2
  307. package/esm/util/openViews.d.ts +1 -0
  308. package/esm/util/openViews.js +3 -3
  309. package/esm/util/parseLineByLine.d.ts +3 -4
  310. package/esm/util/parseLineByLine.js +7 -13
  311. package/esm/util/progress.d.ts +21 -21
  312. package/esm/util/progress.js +27 -26
  313. package/esm/util/renameRegions.d.ts +1 -2
  314. package/esm/util/renderToStaticMarkup.js +16 -16
  315. package/esm/util/rxjs.d.ts +7 -8
  316. package/esm/util/rxjs.js +12 -15
  317. package/esm/util/simpleFeature.d.ts +0 -1
  318. package/esm/util/svgColorProps.d.ts +11 -0
  319. package/esm/util/svgColorProps.js +28 -1
  320. package/esm/util/tabix.d.ts +3 -4
  321. package/esm/util/tabix.js +6 -7
  322. package/esm/util/thresholdScale.d.ts +54 -0
  323. package/esm/util/thresholdScale.js +112 -0
  324. package/esm/util/timeGate.d.ts +4 -5
  325. package/esm/util/timeGate.js +4 -5
  326. package/esm/util/trackConfigDelta.d.ts +22 -18
  327. package/esm/util/trackConfigDelta.js +40 -38
  328. package/esm/util/tracks.d.ts +27 -4
  329. package/esm/util/tracks.js +116 -43
  330. package/esm/util/translateTranscript.d.ts +44 -0
  331. package/esm/util/translateTranscript.js +102 -0
  332. package/esm/util/types/index.d.ts +19 -7
  333. package/esm/util/types/services.d.ts +1 -1
  334. package/esm/util/unknownSnapshotKeys.d.ts +15 -0
  335. package/esm/util/unknownSnapshotKeys.js +13 -0
  336. package/esm/util/useFeatureSequence.js +4 -4
  337. package/esm/util/useFetch.d.ts +3 -4
  338. package/esm/util/useFetch.js +5 -6
  339. package/esm/util/usePanelVirtualScroll.d.ts +7 -39
  340. package/esm/util/usePanelVirtualScroll.js +9 -40
  341. package/esm/util/useRowVirtualScroll.d.ts +6 -29
  342. package/esm/util/useRowVirtualScroll.js +8 -49
  343. package/esm/util/useVirtualScrollWheel.d.ts +20 -4
  344. package/esm/util/useVirtualScrollWheel.js +40 -84
  345. package/esm/util/viewHighlights.d.ts +3 -0
  346. package/esm/util/viewHighlights.js +5 -0
  347. package/esm/util/viewStatus.d.ts +24 -15
  348. package/esm/util/viewStatus.js +17 -0
  349. package/esm/util/withLaunchInput.d.ts +1 -1
  350. package/esm/util/withLaunchInput.js +0 -4
  351. package/package.json +26 -12
  352. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.d.ts +0 -80
  353. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/DLGAP3.js +0 -583
  354. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +0 -141
  355. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.js +0 -1116
  356. package/esm/ReExports/BaseFeatureDetails.d.ts +0 -1
  357. package/esm/ReExports/BaseFeatureDetails.js +0 -10
  358. package/esm/ReExports/barrelOnlyNames.d.ts +0 -5
  359. package/esm/ReExports/barrelOnlyNames.js +0 -63
  360. package/esm/ReExports/index.d.ts +0 -1
  361. package/esm/ReExports/index.js +0 -1
  362. package/esm/ReExports/publicTracks.d.ts +0 -1
  363. package/esm/ReExports/publicTracks.js +0 -14
  364. package/esm/ReExports/publicUi.d.ts +0 -4
  365. package/esm/ReExports/publicUi.js +0 -33
  366. package/esm/ReExports/publicUtil.d.ts +0 -1
  367. package/esm/ReExports/publicUtil.js +0 -32
  368. package/esm/ReExports/sharedModules.d.ts +0 -96
  369. package/esm/ReExports/sharedModules.js +0 -66
  370. package/esm/ReExports/workerNamespaceNames.d.ts +0 -11
  371. package/esm/ReExports/workerNamespaceNames.js +0 -275
  372. package/esm/pluggableElementTypes/models/HighlightsMixin.d.ts +0 -51
  373. package/esm/pluggableElementTypes/models/HighlightsMixin.js +0 -78
  374. package/esm/ui/highlightChipReveal.d.ts +0 -32
  375. package/esm/ui/highlightChipReveal.js +0 -39
  376. package/esm/util/adapterConfigKey.d.ts +0 -12
  377. package/esm/util/adapterConfigKey.js +0 -14
  378. package/esm/util/stopToken.d.ts +0 -212
  379. package/esm/util/stopToken.js +0 -438
@@ -1,13 +1,14 @@
1
1
  /**
2
2
  * @module
3
- * The config **readers**: `readConfObject` off a live MST config node,
4
- * `readConfigValue` off a plain snapshot object in a worker or a renderer, and
5
- * `readConfSlot` for the callers that hold either and don't know which. All
6
- * three exist to evaluate a slot's `jexl:...` callback on read; they differ only
7
- * in where the jexl instance comes from (the node's env vs. an explicit
8
- * argument) and in how much of that they are willing to decide at runtime.
3
+ * The config **readers**: `readConfObject` off a live MST config node, and
4
+ * `readConfigValue` off a plain snapshot object in a worker or a renderer. Both
5
+ * exist to evaluate a slot's `jexl:...` callback on read; they differ only in
6
+ * where the jexl instance comes from, the node's env or an explicit argument.
7
+ * A `featureField` slot's `jexl:` expression is the display's to evaluate per
8
+ * feature, so `readConfObject` hands it over as written.
9
9
  */
10
10
  import { getEnv, getSnapshot, getType, isMapType, isStateTreeNode, } from '@jbrowse/mobx-state-tree';
11
+ import { getConfigurationSchemaMetadata } from './schemaRegistry.js';
11
12
  import { evaluateJexl, isCallbackValue } from './slotValueUtils.js';
12
13
  // Evaluate a slot's `jexl:...` callback string against the realm's single jexl
13
14
  // instance (carrying plugin-registered functions), read from the config node's
@@ -40,6 +41,10 @@ function rawSlotValue(confObject, slotName) {
40
41
  ? confObject.get(slotName)
41
42
  : confObject[slotName];
42
43
  }
44
+ function isFeatureField(confObject, slotName) {
45
+ return (isStateTreeNode(confObject) &&
46
+ !!getConfigurationSchemaMetadata(getType(confObject))?.featureFields.has(slotName));
47
+ }
43
48
  // Read and resolve a single slot: raw value, jexl callback evaluation, then a
44
49
  // referentially-stable snapshot for sub-config nodes.
45
50
  function readSlot(confObject, slotName, args) {
@@ -49,7 +54,7 @@ function readSlot(confObject, slotName, args) {
49
54
  if (value === undefined) {
50
55
  return undefined;
51
56
  }
52
- const val = isCallbackValue(value)
57
+ const val = isCallbackValue(value) && !isFeatureField(confObject, slotName)
53
58
  ? evalConfigCallback(value, args, confObject)
54
59
  : value;
55
60
  // Fast path for primitives (most common case)
@@ -97,10 +102,9 @@ export function readConfObject(confObject, slotPath, args = {}) {
97
102
  }
98
103
  return readSlot(conf, slotPath[slotPath.length - 1], args);
99
104
  }
100
- // The plain-object half of the slot walk, shared by readConfigValue and
101
- // readConfSlot. The MST half is readSlot/rawSlotValue above. A plain object has
102
- // no map entries and no sub-config nodes to snapshot, so it is just a path
103
- // reduce.
105
+ // The plain-object half of the slot walk, for readConfigValue. The MST half is
106
+ // readSlot/rawSlotValue above. A plain object has no map entries and no
107
+ // sub-config nodes to snapshot, so it is just a path reduce.
104
108
  function resolveConfigValue(config, key) {
105
109
  if (Array.isArray(key)) {
106
110
  let val = config;
@@ -121,41 +125,3 @@ export function readConfigValue(config, key, feature, jexl) {
121
125
  const raw = resolveConfigValue(config, key);
122
126
  return (isCallbackValue(raw) ? evaluateJexl(raw, { feature }, jexl) : raw);
123
127
  }
124
- /**
125
- * #api core/configuration
126
- * Read a single config slot from a config that may be **either** a live MST
127
- * node or a plain snapshot object, evaluating the value if it is a `jexl:`
128
- * expression. For the dialogs and panels that are handed a track config without
129
- * knowing which of the two they got. An About panel gets a hydrated track
130
- * config from the session and a bare object from an embedded caller.
131
- *
132
- * Reach for `readConfObject` or `readConfigValue` when the shape is known:
133
- * this one decides at runtime, and the plain branch inherits the snapshot
134
- * caveat (a slot at its default is absent from a snapshot, so it reads
135
- * `undefined`).
136
- *
137
- * @param config - live config model or plain config object
138
- * @param slotPath - slot name, or path of sub-config names ending in a slot
139
- * @param args - extra arguments for a callback slot, e.g. `{ feature }`
140
- * @param jexl - realm jexl instance, required only to evaluate a callback slot
141
- * on a plain object (a live node resolves its own from env)
142
- */
143
- export function readConfSlot(config, slotPath, args = {}, jexl) {
144
- if (isStateTreeNode(config)) {
145
- // pass slotPath through rather than normalizing a string into a one-element
146
- // array: readConfObject keeps the single-slot read allocation-free
147
- return readConfObject(config, slotPath, args);
148
- }
149
- const value = resolveConfigValue(config, slotPath);
150
- // A plain-object config has no MST env, so the realm's jexl instance can't be
151
- // resolved automatically — callers reading a callback slot must pass it. Only
152
- // reached when the slot actually holds a `jexl:` value (trackId/adapter/etc.
153
- // never do), so non-callback readers need not supply it.
154
- if (isCallbackValue(value)) {
155
- if (!jexl) {
156
- throw new Error(`cannot evaluate jexl config slot ${JSON.stringify(slotPath)} on a plain-object config: no jexl instance provided`);
157
- }
158
- return evaluateJexl(value, args, jexl);
159
- }
160
- return value;
161
- }
@@ -0,0 +1,37 @@
1
+ import type { ConfigurationSchemaDefinition } from './configurationSchema.ts';
2
+ import type { IAnyType } from '@jbrowse/mobx-state-tree';
3
+ /**
4
+ * A combination one config object cannot mean, declared once: when every slot
5
+ * named in `when` holds one of the listed values, each dotted path in `slots`
6
+ * has to name a value — a non-empty string, or a sub-schema a string lifts
7
+ * into. `message` says why, and `id` is the stable name a report carries.
8
+ * `requirementProblems` reads it for a display's notice, and the generated
9
+ * JSON Schema carries it as `if`/`then` with the message, which the CLI
10
+ * validator and an editor report.
11
+ *
12
+ * `ConfigurationSchema()` types `when`, its values and `slots` off the
13
+ * definition and throws at construction for what the types cannot reach: a
14
+ * misspelt `when` key or value would never fire, and a misspelt path would
15
+ * require a key `closed` then refuses.
16
+ */
17
+ export interface ConfigurationSchemaRequirement<WHEN extends Partial<Record<string, string[]>> = Partial<Record<string, string[]>>, PATH extends string = string> {
18
+ id: string;
19
+ when: WHEN;
20
+ slots: PATH[];
21
+ message: string;
22
+ }
23
+ /** A requirement a snapshot does not meet: the slot path left empty, and why. */
24
+ export interface RequirementProblem {
25
+ id: string;
26
+ slot: string;
27
+ message: string;
28
+ }
29
+ export declare function checkRequirements(modelName: string, definition: ConfigurationSchemaDefinition, requires: ConfigurationSchemaRequirement[]): void;
30
+ /**
31
+ * #api core/configuration
32
+ * The `requires` entries of a configuration schema that `snapshot` does not
33
+ * meet, as a config file or `getSnapshot` spells it: a slot left off reads as
34
+ * its default, so a `when` value that is the default fires for an absent slot,
35
+ * which is what the generated JSON Schema's `if` does.
36
+ */
37
+ export declare function requirementProblems(type: IAnyType, snapshot: Record<string, unknown>): RequirementProblem[];
@@ -0,0 +1,88 @@
1
+ import { getConfigurationSchemaMetadata } from './schemaRegistry.js';
2
+ import { isBareConfigurationSchemaType, isSlotDefinitionEntry, } from './schemaTypes.js';
3
+ function memberOf(definition, name) {
4
+ return Object.hasOwn(definition, name) ? definition[name] : undefined;
5
+ }
6
+ function subSchemaOf(entry) {
7
+ return isBareConfigurationSchemaType(entry)
8
+ ? getConfigurationSchemaMetadata(entry)
9
+ : undefined;
10
+ }
11
+ function requiredPathProblem(modelName, definition, path) {
12
+ const [head = '', ...rest] = path;
13
+ const entry = memberOf(definition, head);
14
+ const sub = subSchemaOf(entry);
15
+ return entry === undefined
16
+ ? `${modelName} declares no "${head}"`
17
+ : rest.length > 0
18
+ ? sub
19
+ ? requiredPathProblem(sub.name, sub.definition, rest)
20
+ : `"${head}" is not a single sub-schema, so no path runs through it`
21
+ : isSlotDefinitionEntry(entry)
22
+ ? entry.defaultValue === undefined ||
23
+ typeof entry.defaultValue === 'string'
24
+ ? undefined
25
+ : `"${head}" holds no string, and a requirement is met by naming one`
26
+ : sub?.options.shorthand !== undefined
27
+ ? undefined
28
+ : `"${head}" is neither a slot nor a sub-schema a string lifts into`;
29
+ }
30
+ export function checkRequirements(modelName, definition, requires) {
31
+ for (const { when, slots } of requires) {
32
+ for (const [slot, values = []] of Object.entries(when)) {
33
+ const entry = memberOf(definition, slot);
34
+ if (!isSlotDefinitionEntry(entry)) {
35
+ throw new Error(`${modelName} requires something when "${slot}" holds a value, and declares no such slot`);
36
+ }
37
+ const refused = values.filter(value => entry.model?.is(value) === false);
38
+ if (refused.length > 0) {
39
+ throw new Error(`${modelName} requires something when "${slot}" holds ${refused.join(', ')}, which the slot does not take`);
40
+ }
41
+ }
42
+ for (const path of slots) {
43
+ const problem = requiredPathProblem(modelName, definition, path.split('.'));
44
+ if (problem) {
45
+ throw new Error(`${modelName} requires "${path}", and ${problem}`);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ function namesAValue(definition, snapshot, path) {
51
+ const [head = '', ...rest] = path;
52
+ const value = typeof snapshot === 'object' && snapshot !== null
53
+ ? snapshot[head]
54
+ : undefined;
55
+ const sub = subSchemaOf(memberOf(definition, head));
56
+ const shorthand = sub?.options.shorthand;
57
+ return rest.length > 0
58
+ ? sub !== undefined && namesAValue(sub.definition, value, rest)
59
+ : typeof value === 'string'
60
+ ? value !== ''
61
+ : sub !== undefined &&
62
+ shorthand !== undefined &&
63
+ namesAValue(sub.definition, value, [shorthand]);
64
+ }
65
+ /**
66
+ * #api core/configuration
67
+ * The `requires` entries of a configuration schema that `snapshot` does not
68
+ * meet, as a config file or `getSnapshot` spells it: a slot left off reads as
69
+ * its default, so a `when` value that is the default fires for an absent slot,
70
+ * which is what the generated JSON Schema's `if` does.
71
+ */
72
+ export function requirementProblems(type, snapshot) {
73
+ const schema = getConfigurationSchemaMetadata(type);
74
+ if (!schema) {
75
+ return [];
76
+ }
77
+ const { definition } = schema;
78
+ return (schema.options.requires ?? [])
79
+ .filter(({ when }) => Object.entries(when).every(([slot, values]) => {
80
+ const entry = memberOf(definition, slot);
81
+ const held = snapshot[slot] ??
82
+ (isSlotDefinitionEntry(entry) ? entry.defaultValue : undefined);
83
+ return typeof held === 'string' && values?.includes(held);
84
+ }))
85
+ .flatMap(({ id, slots, message }) => slots
86
+ .filter(path => !namesAValue(definition, snapshot, path.split('.')))
87
+ .map(slot => ({ id, slot, message })));
88
+ }
@@ -1,7 +1,9 @@
1
1
  import type { ConfigurationSchemaDefinition, MergedConfigurationSchemaOptions } from './configurationSchema.ts';
2
- import type { AnyConfigurationModel } from './types.ts';
2
+ import type { AnyConfigurationModel, AnyConfigurationSchemaType } from './types.ts';
3
3
  import type { IAnyType } from '@jbrowse/mobx-state-tree';
4
4
  export interface ConfigurationSchemaMetadata {
5
+ /** the name `ConfigurationSchema` was given, e.g. `FeatureColor` */
6
+ name: string;
5
7
  /** the raw slot/sub-schema/constant table, also carrying per-slot editor metadata */
6
8
  definition: ConfigurationSchemaDefinition;
7
9
  /**
@@ -9,10 +11,28 @@ export interface ConfigurationSchemaMetadata {
9
11
  * i.e. with any `baseConfiguration`'s hooks already composed in
10
12
  */
11
13
  options: MergedConfigurationSchemaOptions<any, any>;
14
+ /** the frozen-family slots, the only members a snapshot's `null` is stored in */
15
+ storesNull: ReadonlySet<string>;
16
+ /** the `featureField` slots, which the reader hands over as written */
17
+ featureFields: ReadonlySet<string>;
18
+ /** the slots that refuse a `jexl:` string: every one but a callback and a featureField */
19
+ takesNoCallback: ReadonlyMap<string, string>;
12
20
  }
13
21
  export declare function registerConfigurationSchema(type: IAnyType, metadata: ConfigurationSchemaMetadata): void;
14
22
  export declare function getConfigurationSchemaMetadata(type: IAnyType): ConfigurationSchemaMetadata | undefined;
15
23
  export declare function isRegisteredConfigurationSchema(type: IAnyType): boolean;
24
+ export interface ConfigurationSchemaUnionMetadata {
25
+ /** the name `ConfigurationSchemaUnion` was given, e.g. `MarkTransform` */
26
+ name: string;
27
+ /** each member schema, keyed by the `type` it answers to */
28
+ members: Record<string, AnyConfigurationSchemaType>;
29
+ }
30
+ export declare function registerConfigurationSchemaUnion(type: IAnyType, metadata: ConfigurationSchemaUnionMetadata): void;
31
+ /**
32
+ * The name and members of a union `ConfigurationSchemaUnion` built, or
33
+ * undefined for any other type — a pluggable element union included.
34
+ */
35
+ export declare function getConfigurationSchemaUnion(type: IAnyType): ConfigurationSchemaUnionMetadata | undefined;
16
36
  /**
17
37
  * The slot/sub-schema/constant table for a config (includes slots merged in from
18
38
  * `baseConfiguration` at schema construction). Undefined when the argument isn't
@@ -19,6 +19,17 @@ export function getConfigurationSchemaMetadata(type) {
19
19
  export function isRegisteredConfigurationSchema(type) {
20
20
  return schemaRegistry.has(type);
21
21
  }
22
+ const unionRegistry = new WeakMap();
23
+ export function registerConfigurationSchemaUnion(type, metadata) {
24
+ unionRegistry.set(type, metadata);
25
+ }
26
+ /**
27
+ * The name and members of a union `ConfigurationSchemaUnion` built, or
28
+ * undefined for any other type — a pluggable element union included.
29
+ */
30
+ export function getConfigurationSchemaUnion(type) {
31
+ return unionRegistry.get(type);
32
+ }
22
33
  // The three lookups above take a schema *type*; the two below take a live config
23
34
  // *node* and make the `getType` hop themselves, which is what every reader
24
35
  // actually wants — a node is what they hold. Leaving the hop to the call site is
@@ -1,3 +1,4 @@
1
+ import type { MergedConfigurationSchemaOptions } from './configurationSchema.ts';
1
2
  import type { ConfigSlotDefinition } from './configurationSlot.ts';
2
3
  import type { AnyConfigurationModel, AnyConfigurationSchemaType } from './types.ts';
3
4
  /**
@@ -20,4 +21,6 @@ export declare function isConfigurationSchemaType(thing: unknown): thing is AnyC
20
21
  */
21
22
  export declare function isConstantEntry(def: unknown): def is string | number;
22
23
  export declare function isSlotDefinitionEntry(def: unknown): def is ConfigSlotDefinition;
24
+ /** The prop an explicit or implicit identifier option installs, named `id` when the option is `true`. */
25
+ export declare function identifierName({ explicitIdentifier, implicitIdentifier, }: MergedConfigurationSchemaOptions<any, any>): string | undefined;
23
26
  export declare function isConfigurationModel(thing: unknown): thing is AnyConfigurationModel;
@@ -21,6 +21,11 @@ export function getTypeNamesFromExplicitlyTypedUnion(maybeUnionType) {
21
21
  if (isUnionType(resolved)) {
22
22
  const typeNames = [];
23
23
  for (const subType of getUnionSubTypes(resolved)) {
24
+ // the branch a `maybe`-like union adds so the slot can be absent, not
25
+ // a schema — `isConfigurationSchemaType` already skips it the same way
26
+ if (subType.name === 'undefined') {
27
+ continue;
28
+ }
24
29
  const resolvedSub = resolveLateType(subType);
25
30
  // a nested union contributes its own names; otherwise the subtype is a
26
31
  // single explicitly-typed schema whose name is its default's `type`
@@ -89,6 +94,11 @@ export function isConstantEntry(def) {
89
94
  export function isSlotDefinitionEntry(def) {
90
95
  return (typeof def === 'object' && def !== null && !isType(def) && 'type' in def);
91
96
  }
97
+ /** The prop an explicit or implicit identifier option installs, named `id` when the option is `true`. */
98
+ export function identifierName({ explicitIdentifier, implicitIdentifier, }) {
99
+ const spec = explicitIdentifier || implicitIdentifier;
100
+ return spec ? (typeof spec === 'string' ? spec : 'id') : undefined;
101
+ }
92
102
  export function isConfigurationModel(thing) {
93
103
  return isStateTreeNode(thing) && isConfigurationSchemaType(getType(thing));
94
104
  }
@@ -1,11 +1,32 @@
1
1
  import type PluginManager from '../PluginManager.ts';
2
2
  import type { ConfigSlotDefinition, ConfigSlotType } from './configurationSlot.ts';
3
3
  import type { AnyConfigurationModel } from './types.ts';
4
+ import type { IAnyType } from '@jbrowse/mobx-state-tree';
4
5
  /**
5
6
  * Whether `slotName` on a config node is a slot (vs a nested sub-schema or a
6
7
  * string/number constant).
7
8
  */
8
9
  export declare function isConfigurationSlot(node: AnyConfigurationModel, slotName: string): boolean;
10
+ /**
11
+ * Whether `slotName` on a config node is a single nested sub-schema, the kind
12
+ * `setSubschema` replaces whole (not an array or map of them).
13
+ */
14
+ export declare function isConfigurationSubschema(node: AnyConfigurationModel, slotName: string): boolean;
15
+ /**
16
+ * What to hand `setSubschema` for a write of `slotName`: `value` itself where
17
+ * the sub-schema is a channel, and the node's own snapshot with `value`'s
18
+ * members over it — recursing into the namespaces inside it — where it is not.
19
+ * `null` resets at any depth of a namespace, the way it resets a slot (ADR-146).
20
+ *
21
+ * **A `shorthand` is what tells the two apart.** A sub-schema that takes a bare
22
+ * string takes one written value, so `{ field: 'biotype' }` after
23
+ * `{ field: 'biotype', domain: [...] }` is a colour or facet with no domain,
24
+ * and a merge would leave the old one standing with no way to clear it. A
25
+ * sub-schema with no shorthand is a namespace of independent settings, where
26
+ * `{ scales: { y: { domainMin: 5 } } }` means "pin the bottom" and used to
27
+ * reset `type` and `autoscale` with it.
28
+ */
29
+ export declare function mergedSubschemaValue(node: AnyConfigurationModel, slotName: string, value: unknown): {};
9
30
  /**
10
31
  * Run `node`'s own schema `preProcessSnapshot` over a partial bag of slot
11
32
  * values headed for that config.
@@ -19,6 +40,13 @@ export declare function isConfigurationSlot(node: AnyConfigurationModel, slotNam
19
40
  * is the same shape they already tolerate.
20
41
  */
21
42
  export declare function preProcessSlotValues(node: AnyConfigurationModel, values: Record<string, unknown>): Record<string, unknown>;
43
+ /**
44
+ * Why a config of type `schema` cannot hold `value` at `key`, or undefined
45
+ * when it can: the schema's own lift first, then the slot's type, or a
46
+ * sub-schema's lift and checks. Also undefined for a key the schema does not
47
+ * declare, which is a question for its caller.
48
+ */
49
+ export declare function slotValueRefusal(schema: IAnyType, key: string, value: unknown): string | undefined;
22
50
  /**
23
51
  * The duck-typed object the config editor's leaf components consume. They never
24
52
  * touch MST internals — only this shape (see ColorEditor.test.tsx, which passes
@@ -32,7 +60,10 @@ export interface SlotFacade {
32
60
  type: ConfigSlotType;
33
61
  contextVariable: string[];
34
62
  defaultValue: unknown;
35
- /** enum choices, present only for `stringEnum`/`maybeStringEnum` slots */
63
+ /**
64
+ * enum choices, present only for the enum slot types; a `stringEnumArray`'s
65
+ * are the choices of each entry
66
+ */
36
67
  choices?: string[];
37
68
  pluginManager: PluginManager;
38
69
  readonly value: unknown;
@@ -47,9 +78,9 @@ export interface SlotFacade {
47
78
  }
48
79
  /**
49
80
  * The vocabulary an enum slot offers, or undefined for any other slot. Reads the
50
- * author's own `types.enumeration` off `model` — `stringEnum` and
51
- * `maybeStringEnum` are the only two types the editor takes choices from, so a
52
- * slot typed anything else renders as free text however valid its `model` is.
81
+ * author's own `types.enumeration` off `model` — the enum types are the only
82
+ * ones the editor takes choices from, so a slot typed anything else renders as
83
+ * free text however valid its `model` is.
53
84
  *
54
85
  * Shared by the config editor's facade below and by
55
86
  * `ConfigSlotDefaults.test.ts`, which snapshots every schema's vocabularies:
@@ -1,8 +1,10 @@
1
- import { getSnapshot } from '@jbrowse/mobx-state-tree';
1
+ import { getSnapshot, getType, isArrayType, isMapType, isStateTreeNode, } from '@jbrowse/mobx-state-tree';
2
2
  import { getEnumerationValues } from '../util/mst-reflection.js';
3
3
  import { getEnv } from '../util/mstUtils.js';
4
- import { getConfigurationSchemaDefinition, getConfigurationSchemaOptions, } from './schemaRegistry.js';
5
- import { isSlotDefinitionEntry } from './schemaTypes.js';
4
+ import ConfigSlot, { slotWriteRefusal } from './configurationSlot.js';
5
+ import { getConfigurationSchemaDefinition, getConfigurationSchemaMetadata, getConfigurationSchemaOptions, } from './schemaRegistry.js';
6
+ import { isConfigurationSchemaType, isSlotDefinitionEntry, } from './schemaTypes.js';
7
+ import { preProcessSnapshotWith } from './snapshotPreprocess.js';
6
8
  /**
7
9
  * The slot's metadata entry, or undefined when `slotName` names a nested
8
10
  * sub-schema or a string/number constant rather than a slot.
@@ -18,6 +20,59 @@ function slotDefinition(node, slotName) {
18
20
  export function isConfigurationSlot(node, slotName) {
19
21
  return !!slotDefinition(node, slotName);
20
22
  }
23
+ /**
24
+ * Whether `slotName` on a config node is a single nested sub-schema, the kind
25
+ * `setSubschema` replaces whole (not an array or map of them).
26
+ */
27
+ export function isConfigurationSubschema(node, slotName) {
28
+ const def = getConfigurationSchemaDefinition(node)?.[slotName];
29
+ return isConfigurationSchemaType(def) && !isArrayType(def) && !isMapType(def);
30
+ }
31
+ function isPlainObject(v) {
32
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
33
+ }
34
+ function isNamespace(member) {
35
+ const options = isStateTreeNode(member)
36
+ ? getConfigurationSchemaOptions(member)
37
+ : undefined;
38
+ return !!options && options.shorthand === undefined;
39
+ }
40
+ // JSON Merge Patch (RFC 7396) over a namespace's snapshot: a `null` member
41
+ // leaves the key out, which a stripDefault snapshot reads as the default
42
+ function mergePatch(namespace, patch) {
43
+ const out = { ...getSnapshot(namespace) };
44
+ for (const [k, v] of Object.entries(patch)) {
45
+ const member = namespace[k];
46
+ if (v === null) {
47
+ delete out[k];
48
+ }
49
+ else {
50
+ out[k] =
51
+ isPlainObject(v) && isNamespace(member) ? mergePatch(member, v) : v;
52
+ }
53
+ }
54
+ return out;
55
+ }
56
+ /**
57
+ * What to hand `setSubschema` for a write of `slotName`: `value` itself where
58
+ * the sub-schema is a channel, and the node's own snapshot with `value`'s
59
+ * members over it — recursing into the namespaces inside it — where it is not.
60
+ * `null` resets at any depth of a namespace, the way it resets a slot (ADR-146).
61
+ *
62
+ * **A `shorthand` is what tells the two apart.** A sub-schema that takes a bare
63
+ * string takes one written value, so `{ field: 'biotype' }` after
64
+ * `{ field: 'biotype', domain: [...] }` is a colour or facet with no domain,
65
+ * and a merge would leave the old one standing with no way to clear it. A
66
+ * sub-schema with no shorthand is a namespace of independent settings, where
67
+ * `{ scales: { y: { domainMin: 5 } } }` means "pin the bottom" and used to
68
+ * reset `type` and `autoscale` with it.
69
+ */
70
+ export function mergedSubschemaValue(node, slotName, value) {
71
+ const existing = node[slotName];
72
+ return isPlainObject(value) && isNamespace(existing)
73
+ ? mergePatch(existing, value)
74
+ : (value ?? {});
75
+ }
21
76
  /**
22
77
  * Run `node`'s own schema `preProcessSnapshot` over a partial bag of slot
23
78
  * values headed for that config.
@@ -31,14 +86,43 @@ export function isConfigurationSlot(node, slotName) {
31
86
  * is the same shape they already tolerate.
32
87
  */
33
88
  export function preProcessSlotValues(node, values) {
34
- const preProcess = getConfigurationSchemaOptions(node)?.preProcessSnapshot;
35
- return preProcess ? preProcess(values) : values;
89
+ const schema = getConfigurationSchemaMetadata(getType(node));
90
+ return schema ? preProcessSnapshotWith(schema, values) : values;
91
+ }
92
+ /**
93
+ * Why a config of type `schema` cannot hold `value` at `key`, or undefined
94
+ * when it can: the schema's own lift first, then the slot's type, or a
95
+ * sub-schema's lift and checks. Also undefined for a key the schema does not
96
+ * declare, which is a question for its caller.
97
+ */
98
+ export function slotValueRefusal(schema, key, value) {
99
+ const meta = getConfigurationSchemaMetadata(schema);
100
+ const entry = meta?.definition[key];
101
+ if (!meta || entry === undefined) {
102
+ return undefined;
103
+ }
104
+ const subSchema = isConfigurationSchemaType(entry)
105
+ ? entry
106
+ : undefined;
107
+ try {
108
+ const lifted = preProcessSnapshotWith(meta, { [key]: value })[key];
109
+ if (subSchema) {
110
+ subSchema.create(lifted);
111
+ }
112
+ else if (isSlotDefinitionEntry(entry) && !ConfigSlot(entry).is(lifted)) {
113
+ return slotWriteRefusal(`${meta.name}.${key}`, entry.type, value);
114
+ }
115
+ return undefined;
116
+ }
117
+ catch (e) {
118
+ return e instanceof Error ? e.message : String(e);
119
+ }
36
120
  }
37
121
  /**
38
122
  * The vocabulary an enum slot offers, or undefined for any other slot. Reads the
39
- * author's own `types.enumeration` off `model` — `stringEnum` and
40
- * `maybeStringEnum` are the only two types the editor takes choices from, so a
41
- * slot typed anything else renders as free text however valid its `model` is.
123
+ * author's own `types.enumeration` off `model` — the enum types are the only
124
+ * ones the editor takes choices from, so a slot typed anything else renders as
125
+ * free text however valid its `model` is.
42
126
  *
43
127
  * Shared by the config editor's facade below and by
44
128
  * `ConfigSlotDefaults.test.ts`, which snapshots every schema's vocabularies:
@@ -47,7 +131,10 @@ export function preProcessSlotValues(node, values) {
47
131
  */
48
132
  export function slotChoices(def) {
49
133
  const { type, model } = def;
50
- return (type === 'stringEnum' || type === 'maybeStringEnum') && model
134
+ return (type === 'stringEnum' ||
135
+ type === 'maybeStringEnum' ||
136
+ type === 'stringEnumArray') &&
137
+ model
51
138
  ? getEnumerationValues(model)
52
139
  : undefined;
53
140
  }
@@ -0,0 +1,27 @@
1
+ import type { ConfigurationSchemaMetadata } from './schemaRegistry.ts';
2
+ import type { IAnyType } from '@jbrowse/mobx-state-tree';
3
+ export declare function listed(keys: readonly string[]): string;
4
+ /**
5
+ * The bare value a schema's `shorthand` lifts: a number where the slot it
6
+ * names holds one (`rules: [7.3]`), a string otherwise (`color: 'red'`).
7
+ */
8
+ export declare function shorthandForm({ definition, options, }: ConfigurationSchemaMetadata): 'string' | 'number' | undefined;
9
+ /**
10
+ * What a schema does to every snapshot on its way in, whichever door it
11
+ * arrives by (`create`, `applySnapshot`, `setSubschema`, a settings bag): a
12
+ * bare string or number lifts into the declared `shorthand` slot, beside any
13
+ * `shorthandWith` slots, and `null` into the empty object that clears it; a
14
+ * `null` member reads as unset, except in a frozen-family slot, which stores
15
+ * it; a `closed` schema refuses a key it does not declare, then the schema's
16
+ * own `preProcessSnapshot` runs, and a `jexl:` callback in a slot declaring no
17
+ * `contextVariable` is refused. A bare value the shorthand does not lift
18
+ * passes through for MST to refuse.
19
+ */
20
+ export declare function preProcessSnapshotWith(schema: ConfigurationSchemaMetadata, snapshot: unknown): Record<string, unknown>;
21
+ /**
22
+ * #api core/configuration
23
+ * A snapshot as `type` admits it: the same lift and checks `type.create`
24
+ * applies, so a dialog or a validator refuses exactly what a config file
25
+ * cannot hold. Throws what the schema's `preProcessSnapshot` throws.
26
+ */
27
+ export declare function preProcessConfigSnapshot(type: IAnyType, snapshot: unknown): Record<string, unknown>;
@@ -0,0 +1,102 @@
1
+ import { isJexl } from '../util/jexlStrings.js';
2
+ import { slotWriteRefusal } from './configurationSlot.js';
3
+ import { getConfigurationSchemaMetadata } from './schemaRegistry.js';
4
+ import { identifierName, isConstantEntry, isSlotDefinitionEntry, } from './schemaTypes.js';
5
+ // the keys a config file may annotate any object with, as the JSON schema's
6
+ // `patternProperties` admits them
7
+ const COMMENT_KEY = /^_+comment/;
8
+ export function listed(keys) {
9
+ return keys.length > 1
10
+ ? `${keys.slice(0, -1).join(', ')} and ${keys.at(-1)}`
11
+ : (keys[0] ?? 'nothing');
12
+ }
13
+ function refuseUndeclaredKeys({ name, definition, options }, snapshot) {
14
+ const id = identifierName(options);
15
+ const declared = [
16
+ ...Object.keys(definition).filter(key => !isConstantEntry(definition[key])),
17
+ ...(options.explicitlyTyped ? ['type'] : []),
18
+ ...(id ? [id] : []),
19
+ ];
20
+ const unknown = typeof snapshot === 'string'
21
+ ? [JSON.stringify(snapshot)]
22
+ : Object.keys(snapshot ?? {}).filter(key => !declared.includes(key) && !COMMENT_KEY.test(key));
23
+ if (unknown.length > 0) {
24
+ throw new Error(`${name} takes ${listed(declared)}, not ${unknown.join(', ')}`);
25
+ }
26
+ }
27
+ // Checked here as well as by each slot's MST type because this runs on every
28
+ // create, where MST's own check is off in a build that has not enabled it
29
+ function refuseCallbacks({ name, takesNoCallback }, snapshot) {
30
+ if (typeof snapshot === 'object' && snapshot !== null) {
31
+ for (const key in snapshot) {
32
+ const type = takesNoCallback.get(key);
33
+ const value = snapshot[key];
34
+ if (type !== undefined && isJexl(value)) {
35
+ throw new Error(slotWriteRefusal(`${name}.${key}`, type, value));
36
+ }
37
+ }
38
+ }
39
+ }
40
+ const NUMBER_SLOT_TYPES = new Set(['number', 'integer', 'maybeNumber']);
41
+ /**
42
+ * The bare value a schema's `shorthand` lifts: a number where the slot it
43
+ * names holds one (`rules: [7.3]`), a string otherwise (`color: 'red'`).
44
+ */
45
+ export function shorthandForm({ definition, options, }) {
46
+ const { shorthand } = options;
47
+ const entry = shorthand === undefined ? undefined : definition[shorthand];
48
+ return shorthand === undefined
49
+ ? undefined
50
+ : isSlotDefinitionEntry(entry) && NUMBER_SLOT_TYPES.has(entry.type)
51
+ ? 'number'
52
+ : 'string';
53
+ }
54
+ // ADR-146's reset, on the snapshot path: the member keeps its key, so a
55
+ // settings bag still resets it, and `create` reads `undefined` as the default
56
+ function nullMembersAsUnset(snapshot, storesNull) {
57
+ let out = snapshot;
58
+ for (const key in snapshot) {
59
+ if (snapshot[key] === null && !storesNull.has(key)) {
60
+ out = out === snapshot ? { ...snapshot } : out;
61
+ out[key] = undefined;
62
+ }
63
+ }
64
+ return out;
65
+ }
66
+ /**
67
+ * What a schema does to every snapshot on its way in, whichever door it
68
+ * arrives by (`create`, `applySnapshot`, `setSubschema`, a settings bag): a
69
+ * bare string or number lifts into the declared `shorthand` slot, beside any
70
+ * `shorthandWith` slots, and `null` into the empty object that clears it; a
71
+ * `null` member reads as unset, except in a frozen-family slot, which stores
72
+ * it; a `closed` schema refuses a key it does not declare, then the schema's
73
+ * own `preProcessSnapshot` runs, and a `jexl:` callback in a slot declaring no
74
+ * `contextVariable` is refused. A bare value the shorthand does not lift
75
+ * passes through for MST to refuse.
76
+ */
77
+ export function preProcessSnapshotWith(schema, snapshot) {
78
+ const { shorthand, shorthandWith, closed, preProcessSnapshot } = schema.options;
79
+ const lifted = snapshot === null
80
+ ? {}
81
+ : shorthand !== undefined && typeof snapshot === shorthandForm(schema)
82
+ ? { ...shorthandWith, [shorthand]: snapshot }
83
+ : nullMembersAsUnset(snapshot, schema.storesNull);
84
+ if (closed) {
85
+ refuseUndeclaredKeys(schema, lifted);
86
+ }
87
+ const processed = preProcessSnapshot ? preProcessSnapshot(lifted) : lifted;
88
+ refuseCallbacks(schema, processed);
89
+ return processed;
90
+ }
91
+ /**
92
+ * #api core/configuration
93
+ * A snapshot as `type` admits it: the same lift and checks `type.create`
94
+ * applies, so a dialog or a validator refuses exactly what a config file
95
+ * cannot hold. Throws what the schema's `preProcessSnapshot` throws.
96
+ */
97
+ export function preProcessConfigSnapshot(type, snapshot) {
98
+ const schema = getConfigurationSchemaMetadata(type);
99
+ return schema
100
+ ? preProcessSnapshotWith(schema, snapshot)
101
+ : snapshot;
102
+ }