@genome-spy/core 0.77.0 → 0.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/dist/bundle/{browser-KWU9rWZT.js → browser-CETrb2cm.js} +53 -33
  2. package/dist/bundle/esm-BdLYkz-m.js +248 -0
  3. package/dist/bundle/esm-BwiDsqSb.js +1367 -0
  4. package/dist/bundle/esm-CDFd1cjk.js +441 -0
  5. package/dist/bundle/{esm-CRMf_I9V.js → esm-CTUHLDbv.js} +30 -30
  6. package/dist/bundle/esm-Cx-EbkOj.js +1221 -0
  7. package/dist/bundle/esm-DlYGqi79.js +128 -0
  8. package/dist/bundle/{esm-BygJiwh0.js → esm-k9p3oHkt.js} +133 -158
  9. package/dist/bundle/{esm-CT3ygiMq.js → esm-zAZJQO6D.js} +226 -212
  10. package/dist/bundle/index.es.js +14102 -10810
  11. package/dist/bundle/index.js +109 -95
  12. package/dist/bundle/{parquetRead-DG_-F5j5.js → parquetRead-Cad1SOVV.js} +473 -399
  13. package/dist/schema.json +23788 -11049
  14. package/dist/src/config/axisConfig.d.ts +2 -2
  15. package/dist/src/config/axisConfig.d.ts.map +1 -1
  16. package/dist/src/config/axisConfig.js +28 -44
  17. package/dist/src/config/configLayers.d.ts +45 -0
  18. package/dist/src/config/configLayers.d.ts.map +1 -0
  19. package/dist/src/config/configLayers.js +110 -0
  20. package/dist/src/config/defaultConfig.d.ts.map +1 -1
  21. package/dist/src/config/defaultConfig.js +8 -1
  22. package/dist/src/config/defaults/legendDefaults.d.ts +14 -0
  23. package/dist/src/config/defaults/legendDefaults.d.ts.map +1 -0
  24. package/dist/src/config/defaults/legendDefaults.js +46 -0
  25. package/dist/src/config/defaults/titleDefaults.d.ts.map +1 -1
  26. package/dist/src/config/defaults/titleDefaults.js +26 -18
  27. package/dist/src/config/legendConfig.d.ts +11 -0
  28. package/dist/src/config/legendConfig.d.ts.map +1 -0
  29. package/dist/src/config/legendConfig.js +63 -0
  30. package/dist/src/config/styleUtils.d.ts +8 -2
  31. package/dist/src/config/styleUtils.d.ts.map +1 -1
  32. package/dist/src/config/styleUtils.js +25 -1
  33. package/dist/src/config/themes.d.ts.map +1 -1
  34. package/dist/src/config/themes.js +21 -2
  35. package/dist/src/config/titleConfig.d.ts.map +1 -1
  36. package/dist/src/config/titleConfig.js +2 -18
  37. package/dist/src/data/collector.d.ts.map +1 -1
  38. package/dist/src/data/collector.js +40 -18
  39. package/dist/src/data/flowInit.d.ts +6 -0
  40. package/dist/src/data/flowInit.d.ts.map +1 -1
  41. package/dist/src/data/flowInit.js +1 -1
  42. package/dist/src/data/flowNode.d.ts +32 -0
  43. package/dist/src/data/flowNode.d.ts.map +1 -1
  44. package/dist/src/data/flowNode.js +59 -0
  45. package/dist/src/data/sources/lazy/bamSource.d.ts +0 -1
  46. package/dist/src/data/sources/lazy/bamSource.d.ts.map +1 -1
  47. package/dist/src/data/sources/lazy/bamSource.js +39 -30
  48. package/dist/src/data/sources/lazy/bigBedSource.d.ts +0 -10
  49. package/dist/src/data/sources/lazy/bigBedSource.d.ts.map +1 -1
  50. package/dist/src/data/sources/lazy/bigBedSource.js +127 -62
  51. package/dist/src/data/sources/lazy/bigWigSource.d.ts +2 -2
  52. package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
  53. package/dist/src/data/sources/lazy/bigWigSource.js +234 -81
  54. package/dist/src/data/sources/lazy/gff3Source.d.ts +7 -3
  55. package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
  56. package/dist/src/data/sources/lazy/gff3Source.js +7 -8
  57. package/dist/src/data/sources/lazy/indexedFastaSource.d.ts +1 -1
  58. package/dist/src/data/sources/lazy/indexedFastaSource.d.ts.map +1 -1
  59. package/dist/src/data/sources/lazy/indexedFastaSource.js +28 -19
  60. package/dist/src/data/sources/lazy/legendEntriesSource.d.ts +24 -0
  61. package/dist/src/data/sources/lazy/legendEntriesSource.d.ts.map +1 -0
  62. package/dist/src/data/sources/lazy/legendEntriesSource.js +217 -0
  63. package/dist/src/data/sources/lazy/legendGradientSource.d.ts +30 -0
  64. package/dist/src/data/sources/lazy/legendGradientSource.d.ts.map +1 -0
  65. package/dist/src/data/sources/lazy/legendGradientSource.js +388 -0
  66. package/dist/src/data/sources/lazy/mockLazySource.d.ts +4 -1
  67. package/dist/src/data/sources/lazy/mockLazySource.d.ts.map +1 -1
  68. package/dist/src/data/sources/lazy/mockLazySource.js +49 -4
  69. package/dist/src/data/sources/lazy/registerCoreLazySources.js +2 -0
  70. package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
  71. package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +3 -4
  72. package/dist/src/data/sources/lazy/tabixSource.d.ts +9 -4
  73. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  74. package/dist/src/data/sources/lazy/tabixSource.js +201 -70
  75. package/dist/src/data/sources/lazy/tabixTsvSource.d.ts +2 -3
  76. package/dist/src/data/sources/lazy/tabixTsvSource.d.ts.map +1 -1
  77. package/dist/src/data/sources/lazy/tabixTsvSource.js +14 -12
  78. package/dist/src/data/sources/lazy/vcfSource.d.ts +7 -3
  79. package/dist/src/data/sources/lazy/vcfSource.d.ts.map +1 -1
  80. package/dist/src/data/sources/lazy/vcfSource.js +7 -8
  81. package/dist/src/data/sources/urlDescriptor.d.ts +165 -0
  82. package/dist/src/data/sources/urlDescriptor.d.ts.map +1 -0
  83. package/dist/src/data/sources/urlDescriptor.js +473 -0
  84. package/dist/src/data/sources/urlDescriptorController.d.ts +25 -0
  85. package/dist/src/data/sources/urlDescriptorController.d.ts.map +1 -0
  86. package/dist/src/data/sources/urlDescriptorController.js +72 -0
  87. package/dist/src/data/sources/urlDescriptorState.d.ts +47 -0
  88. package/dist/src/data/sources/urlDescriptorState.d.ts.map +1 -0
  89. package/dist/src/data/sources/urlDescriptorState.js +129 -0
  90. package/dist/src/data/sources/urlSource.d.ts.map +1 -1
  91. package/dist/src/data/sources/urlSource.js +101 -61
  92. package/dist/src/data/transforms/packLegendLabels.d.ts +21 -0
  93. package/dist/src/data/transforms/packLegendLabels.d.ts.map +1 -0
  94. package/dist/src/data/transforms/packLegendLabels.js +189 -0
  95. package/dist/src/data/transforms/transformFactory.d.ts.map +1 -1
  96. package/dist/src/data/transforms/transformFactory.js +4 -0
  97. package/dist/src/data/transforms/truncateText.d.ts +27 -0
  98. package/dist/src/data/transforms/truncateText.d.ts.map +1 -0
  99. package/dist/src/data/transforms/truncateText.js +94 -0
  100. package/dist/src/debug/dataflowDebugSnapshot.d.ts +58 -0
  101. package/dist/src/debug/dataflowDebugSnapshot.d.ts.map +1 -0
  102. package/dist/src/debug/dataflowDebugSnapshot.js +159 -0
  103. package/dist/src/debug/markDebugSnapshot.d.ts +54 -0
  104. package/dist/src/debug/markDebugSnapshot.d.ts.map +1 -0
  105. package/dist/src/debug/markDebugSnapshot.js +100 -0
  106. package/dist/src/debug/paramDebugSnapshot.d.ts +53 -0
  107. package/dist/src/debug/paramDebugSnapshot.d.ts.map +1 -0
  108. package/dist/src/debug/paramDebugSnapshot.js +86 -0
  109. package/dist/src/debug/resolutionDebugSnapshot.d.ts +155 -0
  110. package/dist/src/debug/resolutionDebugSnapshot.d.ts.map +1 -0
  111. package/dist/src/debug/resolutionDebugSnapshot.js +291 -0
  112. package/dist/src/debug/valuePreview.d.ts +9 -0
  113. package/dist/src/debug/valuePreview.d.ts.map +1 -0
  114. package/dist/src/debug/valuePreview.js +57 -0
  115. package/dist/src/debug/viewDebugSnapshot.d.ts +131 -0
  116. package/dist/src/debug/viewDebugSnapshot.d.ts.map +1 -0
  117. package/dist/src/debug/viewDebugSnapshot.js +390 -0
  118. package/dist/src/embedFactory.d.ts.map +1 -1
  119. package/dist/src/embedFactory.js +6 -1
  120. package/dist/src/encoder/encoder.d.ts +2 -2
  121. package/dist/src/encoder/encoder.d.ts.map +1 -1
  122. package/dist/src/encoder/encoder.js +5 -4
  123. package/dist/src/fonts/bmFontManager.d.ts +1 -1
  124. package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
  125. package/dist/src/fonts/bmFontManager.js +45 -10
  126. package/dist/src/fonts/textMetrics.d.ts +69 -0
  127. package/dist/src/fonts/textMetrics.d.ts.map +1 -0
  128. package/dist/src/fonts/textMetrics.js +73 -0
  129. package/dist/src/genomeSpy/headlessBootstrap.d.ts.map +1 -1
  130. package/dist/src/genomeSpy/headlessBootstrap.js +8 -0
  131. package/dist/src/genomeSpy/interactionController.d.ts +4 -1
  132. package/dist/src/genomeSpy/interactionController.d.ts.map +1 -1
  133. package/dist/src/genomeSpy/interactionController.js +57 -13
  134. package/dist/src/genomeSpy/renderCoordinator.d.ts.map +1 -1
  135. package/dist/src/genomeSpy/renderCoordinator.js +25 -3
  136. package/dist/src/genomeSpy/viewDataInit.d.ts +14 -0
  137. package/dist/src/genomeSpy/viewDataInit.d.ts.map +1 -1
  138. package/dist/src/genomeSpy/viewDataInit.js +45 -8
  139. package/dist/src/genomeSpyBase.d.ts +6 -0
  140. package/dist/src/genomeSpyBase.d.ts.map +1 -1
  141. package/dist/src/genomeSpyBase.js +25 -4
  142. package/dist/src/gl/glslScaleGenerator.d.ts +17 -0
  143. package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
  144. package/dist/src/gl/glslScaleGenerator.js +39 -2
  145. package/dist/src/gl/includes/common.glsl.js +1 -1
  146. package/dist/src/gl/vertexRangeIndex.d.ts.map +1 -1
  147. package/dist/src/gl/vertexRangeIndex.js +4 -2
  148. package/dist/src/gl/webGLHelper.d.ts +1 -1
  149. package/dist/src/gl/webGLHelper.d.ts.map +1 -1
  150. package/dist/src/gl/webGLHelper.js +13 -8
  151. package/dist/src/marks/__snapshots__/shaderSnapshot.test.js.snap +140 -3
  152. package/dist/src/marks/mark.d.ts +47 -4
  153. package/dist/src/marks/mark.d.ts.map +1 -1
  154. package/dist/src/marks/mark.js +158 -54
  155. package/dist/src/marks/point.d.ts.map +1 -1
  156. package/dist/src/marks/point.js +4 -0
  157. package/dist/src/marks/point.vertex.glsl.js +1 -1
  158. package/dist/src/marks/text.d.ts +1 -1
  159. package/dist/src/marks/text.d.ts.map +1 -1
  160. package/dist/src/marks/text.js +2 -7
  161. package/dist/src/marks/text.vertex.glsl.js +1 -1
  162. package/dist/src/paramRuntime/paramUtils.d.ts +43 -9
  163. package/dist/src/paramRuntime/paramUtils.d.ts.map +1 -1
  164. package/dist/src/paramRuntime/paramUtils.js +61 -1
  165. package/dist/src/paramRuntime/viewParamRuntime.d.ts +32 -0
  166. package/dist/src/paramRuntime/viewParamRuntime.d.ts.map +1 -1
  167. package/dist/src/paramRuntime/viewParamRuntime.js +63 -0
  168. package/dist/src/scales/axisResolution.d.ts +35 -0
  169. package/dist/src/scales/axisResolution.d.ts.map +1 -1
  170. package/dist/src/scales/axisResolution.js +115 -7
  171. package/dist/src/scales/domainExpressions.d.ts +21 -0
  172. package/dist/src/scales/domainExpressions.d.ts.map +1 -0
  173. package/dist/src/scales/domainExpressions.js +43 -0
  174. package/dist/src/scales/domainPlanner.d.ts +12 -1
  175. package/dist/src/scales/domainPlanner.d.ts.map +1 -1
  176. package/dist/src/scales/domainPlanner.js +55 -36
  177. package/dist/src/scales/legendResolution.d.ts +83 -0
  178. package/dist/src/scales/legendResolution.d.ts.map +1 -0
  179. package/dist/src/scales/legendResolution.js +461 -0
  180. package/dist/src/scales/scaleInstanceManager.d.ts +1 -0
  181. package/dist/src/scales/scaleInstanceManager.d.ts.map +1 -1
  182. package/dist/src/scales/scaleInstanceManager.js +5 -0
  183. package/dist/src/scales/scalePropsResolver.d.ts +6 -1
  184. package/dist/src/scales/scalePropsResolver.d.ts.map +1 -1
  185. package/dist/src/scales/scalePropsResolver.js +35 -10
  186. package/dist/src/scales/scaleResolution.d.ts +52 -0
  187. package/dist/src/scales/scaleResolution.d.ts.map +1 -1
  188. package/dist/src/scales/scaleResolution.js +195 -16
  189. package/dist/src/scales/scaleRules.d.ts +10 -0
  190. package/dist/src/scales/scaleRules.d.ts.map +1 -1
  191. package/dist/src/scales/scaleRules.js +38 -1
  192. package/dist/src/scales/viewLevelGuideConfig.d.ts +53 -0
  193. package/dist/src/scales/viewLevelGuideConfig.d.ts.map +1 -0
  194. package/dist/src/scales/viewLevelGuideConfig.js +224 -0
  195. package/dist/src/scales/viewLevelScaleConfig.d.ts +45 -0
  196. package/dist/src/scales/viewLevelScaleConfig.d.ts.map +1 -0
  197. package/dist/src/scales/viewLevelScaleConfig.js +149 -0
  198. package/dist/src/spec/axis.d.ts +109 -3
  199. package/dist/src/spec/channel.d.ts +23 -4
  200. package/dist/src/spec/config.d.ts +59 -4
  201. package/dist/src/spec/data.d.ts +177 -17
  202. package/dist/src/spec/legend.d.ts +246 -0
  203. package/dist/src/spec/mark.d.ts +16 -4
  204. package/dist/src/spec/scale.d.ts +19 -6
  205. package/dist/src/spec/title.d.ts +58 -1
  206. package/dist/src/spec/transform.d.ts +149 -0
  207. package/dist/src/spec/view.d.ts +50 -6
  208. package/dist/src/styles/genome-spy.css +4 -1
  209. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  210. package/dist/src/styles/genome-spy.css.d.ts.map +1 -1
  211. package/dist/src/styles/genome-spy.css.js +4 -1
  212. package/dist/src/types/embedApi.d.ts +262 -6
  213. package/dist/src/types/rendering.d.ts +19 -3
  214. package/dist/src/types/viewContext.d.ts +18 -2
  215. package/dist/src/utils/arrayUtils.d.ts +11 -0
  216. package/dist/src/utils/arrayUtils.d.ts.map +1 -1
  217. package/dist/src/utils/arrayUtils.js +23 -0
  218. package/dist/src/utils/suspension.d.ts +17 -0
  219. package/dist/src/utils/suspension.d.ts.map +1 -0
  220. package/dist/src/utils/suspension.js +41 -0
  221. package/dist/src/utils/ui/tooltip.d.ts +4 -0
  222. package/dist/src/utils/ui/tooltip.d.ts.map +1 -1
  223. package/dist/src/utils/ui/tooltip.js +35 -10
  224. package/dist/src/view/axisGridView.d.ts.map +1 -1
  225. package/dist/src/view/axisGridView.js +1 -4
  226. package/dist/src/view/axisView.d.ts +18 -2
  227. package/dist/src/view/axisView.d.ts.map +1 -1
  228. package/dist/src/view/axisView.js +180 -75
  229. package/dist/src/view/concatView.d.ts +10 -2
  230. package/dist/src/view/concatView.d.ts.map +1 -1
  231. package/dist/src/view/concatView.js +46 -9
  232. package/dist/src/view/containerMutationHelper.d.ts +20 -1
  233. package/dist/src/view/containerMutationHelper.d.ts.map +1 -1
  234. package/dist/src/view/containerMutationHelper.js +203 -32
  235. package/dist/src/view/facetView.d.ts +1 -1
  236. package/dist/src/view/gridView/gridChild.d.ts +54 -4
  237. package/dist/src/view/gridView/gridChild.d.ts.map +1 -1
  238. package/dist/src/view/gridView/gridChild.js +301 -120
  239. package/dist/src/view/gridView/gridChildLegends.d.ts +57 -0
  240. package/dist/src/view/gridView/gridChildLegends.d.ts.map +1 -0
  241. package/dist/src/view/gridView/gridChildLegends.js +503 -0
  242. package/dist/src/view/gridView/gridView.d.ts +25 -0
  243. package/dist/src/view/gridView/gridView.d.ts.map +1 -1
  244. package/dist/src/view/gridView/gridView.js +454 -78
  245. package/dist/src/view/gridView/legendLayout.d.ts +26 -0
  246. package/dist/src/view/gridView/legendLayout.d.ts.map +1 -0
  247. package/dist/src/view/gridView/legendLayout.js +111 -0
  248. package/dist/src/view/gridView/scrollbar.d.ts.map +1 -1
  249. package/dist/src/view/gridView/scrollbar.js +1 -4
  250. package/dist/src/view/gridView/selectionRect.d.ts.map +1 -1
  251. package/dist/src/view/gridView/selectionRect.js +1 -4
  252. package/dist/src/view/gridView/separatorView.d.ts.map +1 -1
  253. package/dist/src/view/gridView/separatorView.js +1 -4
  254. package/dist/src/view/layerView.d.ts +9 -2
  255. package/dist/src/view/layerView.d.ts.map +1 -1
  256. package/dist/src/view/layerView.js +18 -1
  257. package/dist/src/view/layout/flexLayout.d.ts +20 -4
  258. package/dist/src/view/layout/flexLayout.d.ts.map +1 -1
  259. package/dist/src/view/layout/flexLayout.js +331 -31
  260. package/dist/src/view/layout/rectangle.d.ts +14 -0
  261. package/dist/src/view/layout/rectangle.d.ts.map +1 -1
  262. package/dist/src/view/layout/rectangle.js +40 -0
  263. package/dist/src/view/legend/legendEntries.d.ts +20 -0
  264. package/dist/src/view/legend/legendEntries.d.ts.map +1 -0
  265. package/dist/src/view/legend/legendEntries.js +21 -0
  266. package/dist/src/view/legendView.d.ts +134 -0
  267. package/dist/src/view/legendView.d.ts.map +1 -0
  268. package/dist/src/view/legendView.js +1611 -0
  269. package/dist/src/view/renderingContext/bufferedViewRenderingContext.d.ts.map +1 -1
  270. package/dist/src/view/renderingContext/bufferedViewRenderingContext.js +26 -4
  271. package/dist/src/view/renderingContext/clipOptions.d.ts +44 -0
  272. package/dist/src/view/renderingContext/clipOptions.d.ts.map +1 -0
  273. package/dist/src/view/renderingContext/clipOptions.js +140 -0
  274. package/dist/src/view/renderingContext/simpleViewRenderingContext.d.ts.map +1 -1
  275. package/dist/src/view/renderingContext/simpleViewRenderingContext.js +12 -1
  276. package/dist/src/view/resolutionPlanner.d.ts +2 -1
  277. package/dist/src/view/resolutionPlanner.d.ts.map +1 -1
  278. package/dist/src/view/resolutionPlanner.js +89 -25
  279. package/dist/src/view/testUtils.d.ts +4 -2
  280. package/dist/src/view/testUtils.d.ts.map +1 -1
  281. package/dist/src/view/testUtils.js +29 -7
  282. package/dist/src/view/titleView.d.ts +37 -0
  283. package/dist/src/view/titleView.d.ts.map +1 -0
  284. package/dist/src/view/titleView.js +584 -0
  285. package/dist/src/view/unitView.d.ts +3 -3
  286. package/dist/src/view/unitView.d.ts.map +1 -1
  287. package/dist/src/view/unitView.js +3 -2
  288. package/dist/src/view/view.d.ts +25 -24
  289. package/dist/src/view/view.d.ts.map +1 -1
  290. package/dist/src/view/view.js +121 -16
  291. package/dist/src/view/viewFactory.d.ts +2 -5
  292. package/dist/src/view/viewFactory.d.ts.map +1 -1
  293. package/dist/src/view/viewFactory.js +1 -2
  294. package/dist/src/view/viewIdentityRegistry.d.ts +37 -0
  295. package/dist/src/view/viewIdentityRegistry.d.ts.map +1 -0
  296. package/dist/src/view/viewIdentityRegistry.js +71 -0
  297. package/dist/src/view/viewMutationAcidTestUtils.d.ts +112 -0
  298. package/dist/src/view/viewMutationAcidTestUtils.d.ts.map +1 -0
  299. package/dist/src/view/viewMutationAcidTestUtils.js +234 -0
  300. package/dist/src/view/viewMutationApi.d.ts +42 -0
  301. package/dist/src/view/viewMutationApi.d.ts.map +1 -0
  302. package/dist/src/view/viewMutationApi.js +811 -0
  303. package/dist/src/view/viewSelectors.d.ts +10 -0
  304. package/dist/src/view/viewSelectors.d.ts.map +1 -1
  305. package/dist/src/view/viewSelectors.js +23 -1
  306. package/package.json +4 -4
  307. package/dist/bundle/esm-0dYHNV_D.js +0 -121
  308. package/dist/bundle/esm-C49STiCR.js +0 -1248
  309. package/dist/bundle/esm-CscjKVDc.js +0 -1426
  310. package/dist/bundle/esm-CuMSzCHy.js +0 -298
  311. package/dist/bundle/esm-DMXpJXM4.js +0 -369
  312. package/dist/src/view/title.d.ts +0 -13
  313. package/dist/src/view/title.d.ts.map +0 -1
  314. package/dist/src/view/title.js +0 -154
  315. /package/dist/bundle/{AbortablePromiseCache-3gHJdF3E.js → AbortablePromiseCache-BTmAcN-t.js} +0 -0
  316. /package/dist/bundle/{esm-CuVa5T98.js → esm-VvpZ9hsq.js} +0 -0
  317. /package/dist/bundle/{chunk-DmhlhrBa.js → rolldown-runtime-Dy4uBu1J.js} +0 -0
@@ -0,0 +1,811 @@
1
+ import ConcatView from "./concatView.js";
2
+ import GridView from "./gridView/gridView.js";
3
+ import LayerView from "./layerView.js";
4
+ import { isMultiscaleSpec } from "./multiscale.js";
5
+ import UnitView from "./unitView.js";
6
+ import { isImportSpec, isLayerSpec, isUnitSpec } from "./viewSpecGuards.js";
7
+ import {
8
+ getImportScopeInfo,
9
+ getViewScopeChain,
10
+ getViewSelector,
11
+ registerViewScope,
12
+ resolveViewSelector,
13
+ } from "./viewSelectors.js";
14
+ import { getViewIdentityRegistry } from "./viewIdentityRegistry.js";
15
+
16
+ /**
17
+ * Error thrown by the public view mutation API.
18
+ */
19
+ export class ViewMutationError extends Error {
20
+ /**
21
+ * @param {string} code
22
+ * @param {string} message
23
+ */
24
+ constructor(code, message) {
25
+ super(message);
26
+ this.name = "ViewMutationError";
27
+
28
+ /**
29
+ * Stable error code for programmatic handling.
30
+ */
31
+ this.code = code;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @typedef {{
37
+ * depth: number,
38
+ * queue: Promise<void>,
39
+ * failed: boolean,
40
+ * error: unknown | undefined,
41
+ * requestedLayoutReflow: boolean,
42
+ * restoreLayoutReflow: () => void
43
+ * }} TransactionState
44
+ */
45
+
46
+ /**
47
+ * Creates the public view hierarchy API for a GenomeSpy instance.
48
+ *
49
+ * @param {{ viewRoot: import("./view.js").default }} genomeSpy
50
+ * @returns {import("../types/embedApi.js").ViewApi}
51
+ */
52
+ export function createViewMutationApi(genomeSpy) {
53
+ /**
54
+ * @typedef {import("../types/embedApi.js").ViewAddress} ViewAddress
55
+ * @typedef {import("../types/embedApi.js").ViewHandle} ViewHandle
56
+ * @typedef {import("../view/viewUtilTypes.d.ts").ViewSelector} ViewSelector
57
+ */
58
+
59
+ /** @type {WeakMap<import("./view.js").default, import("../types/embedApi.js").ViewHandle>} */
60
+ const handlesByView = new WeakMap();
61
+
62
+ /** @type {WeakMap<import("../types/embedApi.js").ViewHandle, import("./view.js").default>} */
63
+ const viewsByHandle = new WeakMap();
64
+
65
+ let queue = Promise.resolve();
66
+
67
+ /** @type {TransactionState | undefined} */
68
+ let activeTransaction;
69
+
70
+ /**
71
+ * @returns {import("./view.js").default}
72
+ */
73
+ function getRootView() {
74
+ return genomeSpy.viewRoot;
75
+ }
76
+
77
+ /**
78
+ * @param {import("./view.js").default} view
79
+ * @returns {boolean}
80
+ */
81
+ function isLiveView(view) {
82
+ const root = getRootView();
83
+ return (
84
+ view === root || Boolean(root?.getDescendants?.().includes(view))
85
+ );
86
+ }
87
+
88
+ /**
89
+ * @param {import("./view.js").default} view
90
+ * @returns {import("../types/embedApi.js").ViewHandleType}
91
+ */
92
+ function getHandleType(view) {
93
+ if (view instanceof ConcatView) {
94
+ return "concat";
95
+ } else if (view instanceof LayerView) {
96
+ return "layer";
97
+ } else if (view instanceof UnitView) {
98
+ return "unit";
99
+ } else if (view instanceof GridView) {
100
+ return "grid";
101
+ } else {
102
+ return "unknown";
103
+ }
104
+ }
105
+
106
+ /**
107
+ * @param {import("./view.js").default} view
108
+ * @returns {ViewSelector | undefined}
109
+ */
110
+ function getSelector(view) {
111
+ if (!view.explicitName) {
112
+ return undefined;
113
+ }
114
+
115
+ try {
116
+ return getViewSelector(view);
117
+ } catch {
118
+ return undefined;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * @param {import("./view.js").default} view
124
+ * @returns {import("../types/embedApi.js").ViewHandle}
125
+ */
126
+ function getHandle(view) {
127
+ let handle = handlesByView.get(view);
128
+ if (handle) {
129
+ return handle;
130
+ }
131
+
132
+ const id = getViewIdentityRegistry(getRootView()).getId(view);
133
+
134
+ handle = {
135
+ id,
136
+
137
+ get name() {
138
+ return view.explicitName;
139
+ },
140
+
141
+ get selector() {
142
+ return getSelector(view);
143
+ },
144
+
145
+ get type() {
146
+ return getHandleType(view);
147
+ },
148
+
149
+ isAlive: () => isLiveView(view),
150
+
151
+ parent: () => {
152
+ if (!isLiveView(view) || !view.layoutParent) {
153
+ return undefined;
154
+ }
155
+
156
+ return getHandle(view.layoutParent);
157
+ },
158
+
159
+ children: () => {
160
+ const children = getLayoutChildren(view);
161
+ if (!isLiveView(view) || !children) {
162
+ return [];
163
+ }
164
+
165
+ return children.map((child) => getHandle(child));
166
+ },
167
+ };
168
+
169
+ handlesByView.set(view, handle);
170
+ viewsByHandle.set(handle, view);
171
+ return handle;
172
+ }
173
+
174
+ /**
175
+ * @param {import("./view.js").default} view
176
+ * @returns {import("./view.js").default[] | undefined}
177
+ */
178
+ function getLayoutChildren(view) {
179
+ const children = /** @type {{ children?: unknown }} */ (view).children;
180
+ return Array.isArray(children)
181
+ ? /** @type {import("./view.js").default[]} */ (children)
182
+ : undefined;
183
+ }
184
+
185
+ /**
186
+ * @param {ViewAddress} address
187
+ * @returns {import("../types/embedApi.js").ViewHandle | undefined}
188
+ */
189
+ function resolve(address) {
190
+ if (address === "root") {
191
+ return getHandle(getRootView());
192
+ } else if (isViewHandle(address)) {
193
+ return viewsByHandle.has(address) && address.isAlive()
194
+ ? address
195
+ : undefined;
196
+ } else if (isViewSelector(address)) {
197
+ const view = resolveViewSelector(getRootView(), address);
198
+ return view ? getHandle(view) : undefined;
199
+ } else {
200
+ throw new ViewMutationError(
201
+ "invalidAddress",
202
+ 'View address must be a handle, selector, or "root".'
203
+ );
204
+ }
205
+ }
206
+
207
+ /**
208
+ * @param {ViewAddress} address
209
+ * @returns {import("../types/embedApi.js").ViewHandle}
210
+ */
211
+ function get(address) {
212
+ const handle = resolve(address);
213
+ if (handle) {
214
+ return handle;
215
+ }
216
+
217
+ if (isViewHandle(address) && viewsByHandle.has(address)) {
218
+ throw new ViewMutationError(
219
+ "staleHandle",
220
+ "Stale view handle no longer refers to a live view."
221
+ );
222
+ }
223
+
224
+ throw new ViewMutationError(
225
+ "unresolvedAddress",
226
+ "View address did not resolve to a live view."
227
+ );
228
+ }
229
+
230
+ /**
231
+ * @param {ViewAddress} address
232
+ * @returns {import("./view.js").default}
233
+ */
234
+ function getView(address) {
235
+ const handle = get(address);
236
+ const view = viewsByHandle.get(handle);
237
+ if (!view) {
238
+ throw new ViewMutationError(
239
+ "invalidAddress",
240
+ "View handle is not owned by this GenomeSpy instance."
241
+ );
242
+ }
243
+
244
+ return view;
245
+ }
246
+
247
+ /**
248
+ * @param {ViewAddress} address
249
+ * @returns {import("../types/embedApi.js").ViewLayoutBounds | undefined}
250
+ */
251
+ function getLayoutBounds(address) {
252
+ const handle = resolve(address);
253
+ if (!handle) {
254
+ return undefined;
255
+ }
256
+
257
+ const view = viewsByHandle.get(handle);
258
+ const coords = view?.coords;
259
+ if (!coords) {
260
+ return undefined;
261
+ }
262
+
263
+ return {
264
+ x: coords.x,
265
+ y: coords.y,
266
+ width: coords.width,
267
+ height: coords.height,
268
+ };
269
+ }
270
+
271
+ /**
272
+ * @param {() => void} listener
273
+ * @returns {() => void}
274
+ */
275
+ function subscribeToLayout(listener) {
276
+ const context = getRootView().context;
277
+ const broadcastListener = () => listener();
278
+ context.addBroadcastListener("layoutComputed", broadcastListener);
279
+
280
+ return () =>
281
+ context.removeBroadcastListener(
282
+ "layoutComputed",
283
+ broadcastListener
284
+ );
285
+ }
286
+
287
+ /**
288
+ * @template T
289
+ * @param {() => T | Promise<T>} operation
290
+ * @returns {Promise<T>}
291
+ */
292
+ function enqueue(operation) {
293
+ if (activeTransaction) {
294
+ return enqueueTransactionOperation(activeTransaction, operation);
295
+ }
296
+
297
+ return enqueueTopLevelOperation(operation);
298
+ }
299
+
300
+ /**
301
+ * @template T
302
+ * @param {() => T | Promise<T>} operation
303
+ * @returns {Promise<T>}
304
+ */
305
+ function enqueueTopLevelOperation(operation) {
306
+ const next = queue.then(operation, operation);
307
+ queue = next.then(clearQueueValue, clearQueueValue);
308
+ return next;
309
+ }
310
+
311
+ /**
312
+ * @template T
313
+ * @param {TransactionState} transaction
314
+ * @param {() => T | Promise<T>} operation
315
+ * @returns {Promise<T>}
316
+ */
317
+ function enqueueTransactionOperation(transaction, operation) {
318
+ const next = transaction.queue.then(operation, operation);
319
+ transaction.queue = next.then(clearQueueValue, (error) => {
320
+ transaction.failed = true;
321
+ transaction.error = error;
322
+ });
323
+ return next;
324
+ }
325
+
326
+ /**
327
+ * @returns {void}
328
+ */
329
+ function clearQueueValue() {}
330
+
331
+ /**
332
+ * @returns {TransactionState}
333
+ */
334
+ function beginTransaction() {
335
+ const transaction = activeTransaction;
336
+ if (transaction) {
337
+ transaction.depth++;
338
+ return transaction;
339
+ }
340
+
341
+ const context = getRootView().context;
342
+ const requestLayoutReflow = context.requestLayoutReflow;
343
+ /** @type {TransactionState} */
344
+ const topLevelTransaction = {
345
+ depth: 1,
346
+ queue: Promise.resolve(),
347
+ failed: false,
348
+ error: undefined,
349
+ requestedLayoutReflow: false,
350
+ restoreLayoutReflow: () => {
351
+ context.requestLayoutReflow = requestLayoutReflow;
352
+ if (topLevelTransaction.requestedLayoutReflow) {
353
+ requestLayoutReflow.call(context);
354
+ }
355
+ },
356
+ };
357
+
358
+ context.requestLayoutReflow = () => {
359
+ topLevelTransaction.requestedLayoutReflow = true;
360
+ };
361
+ activeTransaction = topLevelTransaction;
362
+ return topLevelTransaction;
363
+ }
364
+
365
+ /**
366
+ * @param {TransactionState} transaction
367
+ * @returns {void}
368
+ */
369
+ function endTransaction(transaction) {
370
+ transaction.depth--;
371
+
372
+ if (transaction.depth === 0) {
373
+ transaction.restoreLayoutReflow();
374
+ activeTransaction = undefined;
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Mutations may enqueue more mutations from promise continuations. Keep
380
+ * draining until the transaction queue stops changing.
381
+ *
382
+ * @param {TransactionState} transaction
383
+ * @returns {Promise<void>}
384
+ */
385
+ async function waitForTransactionQueue(transaction) {
386
+ let currentQueue;
387
+ do {
388
+ currentQueue = transaction.queue;
389
+ await currentQueue;
390
+ } while (transaction.queue !== currentQueue);
391
+ }
392
+
393
+ /**
394
+ * @template T
395
+ * @param {(views: import("../types/embedApi.js").ViewApi) => T | Promise<T>} callback
396
+ * @returns {Promise<T>}
397
+ */
398
+ async function runTransaction(callback) {
399
+ const transaction = beginTransaction();
400
+ const previouslyFailed = transaction.failed;
401
+ /** @type {T | undefined} */
402
+ let result;
403
+ /** @type {unknown} */
404
+ let callbackError;
405
+ let callbackFailed = false;
406
+
407
+ try {
408
+ result = await callback(api);
409
+ } catch (error) {
410
+ callbackError = error;
411
+ callbackFailed = true;
412
+ }
413
+
414
+ await waitForTransactionQueue(transaction);
415
+
416
+ try {
417
+ if (callbackFailed) {
418
+ throw callbackError;
419
+ }
420
+
421
+ if (transaction.failed && transaction.failed !== previouslyFailed) {
422
+ throw transaction.error;
423
+ }
424
+
425
+ return /** @type {T} */ (result);
426
+ } finally {
427
+ endTransaction(transaction);
428
+ }
429
+ }
430
+
431
+ /**
432
+ * @param {ViewAddress} parentAddress
433
+ * @param {import("../spec/view.js").ViewSpec | import("../spec/view.js").ImportSpec} spec
434
+ * @param {import("../types/embedApi.js").InsertViewOptions} [options]
435
+ * @returns {Promise<ViewHandle>}
436
+ */
437
+ function insert(parentAddress, spec, options = {}) {
438
+ return enqueue(async () => {
439
+ const parentView = getView(parentAddress);
440
+ const childCount = getMutableContainerChildCount(parentView);
441
+ const index = getInsertIndex(options.index, childCount);
442
+ const scopeName = getInsertScopeName(spec, options);
443
+
444
+ if (scopeName !== undefined && typeof scopeName === "string") {
445
+ ensureScopeNameIsAvailable(parentView, scopeName);
446
+ }
447
+
448
+ const childSpec = structuredClone(spec);
449
+ const childView = await addChildToMutableContainer(
450
+ parentView,
451
+ childSpec,
452
+ index
453
+ );
454
+
455
+ if (options.scope !== undefined) {
456
+ registerViewScope(childView, options.scope);
457
+ }
458
+
459
+ return getHandle(childView);
460
+ });
461
+ }
462
+
463
+ /**
464
+ * @param {import("./view.js").default} parentView
465
+ * @returns {number}
466
+ */
467
+ function getMutableContainerChildCount(parentView) {
468
+ if (
469
+ !(parentView instanceof ConcatView) &&
470
+ !(parentView instanceof LayerView)
471
+ ) {
472
+ throw new ViewMutationError(
473
+ "unsupportedContainer",
474
+ "Only concat and layer views support child insertion."
475
+ );
476
+ }
477
+
478
+ const children = getLayoutChildren(parentView);
479
+ if (!children) {
480
+ throw new ViewMutationError(
481
+ "unsupportedContainer",
482
+ "Mutable container does not expose layout children."
483
+ );
484
+ }
485
+
486
+ return children.length;
487
+ }
488
+
489
+ /**
490
+ * @param {import("./view.js").default} parentView
491
+ * @param {import("../spec/view.js").ViewSpec | import("../spec/view.js").ImportSpec} childSpec
492
+ * @param {number} index
493
+ * @returns {Promise<import("./view.js").default>}
494
+ */
495
+ async function addChildToMutableContainer(parentView, childSpec, index) {
496
+ if (parentView instanceof ConcatView) {
497
+ return parentView.addChildSpec(childSpec, index);
498
+ } else if (parentView instanceof LayerView) {
499
+ if (!isLayerChildSpec(childSpec)) {
500
+ throw new ViewMutationError(
501
+ "unsupportedChildSpec",
502
+ "Layer views accept only unit, layer, multiscale, or import specs as children."
503
+ );
504
+ }
505
+
506
+ return parentView.addChildSpec(childSpec, index);
507
+ }
508
+
509
+ throw new ViewMutationError(
510
+ "unsupportedContainer",
511
+ "Only concat and layer views support child insertion."
512
+ );
513
+ }
514
+
515
+ /**
516
+ * @param {number | undefined} index
517
+ * @param {number} childCount
518
+ * @returns {number}
519
+ */
520
+ function getInsertIndex(index, childCount) {
521
+ const insertIndex = index ?? childCount;
522
+
523
+ if (!Number.isInteger(insertIndex)) {
524
+ throw new ViewMutationError(
525
+ "invalidIndex",
526
+ "Insert index must be an integer."
527
+ );
528
+ }
529
+
530
+ if (insertIndex < 0 || insertIndex > childCount) {
531
+ throw new ViewMutationError(
532
+ "invalidIndex",
533
+ "Insert index must be between 0 and the current child count."
534
+ );
535
+ }
536
+
537
+ return insertIndex;
538
+ }
539
+
540
+ /**
541
+ * @param {import("../spec/view.js").ViewSpec | import("../spec/view.js").ImportSpec} spec
542
+ * @param {import("../types/embedApi.js").InsertViewOptions} options
543
+ * @returns {string | null | undefined}
544
+ */
545
+ function getInsertScopeName(spec, options) {
546
+ const importScopeName =
547
+ isImportSpec(spec) && "name" in spec ? spec.name : undefined;
548
+
549
+ if (
550
+ options.scope !== undefined &&
551
+ importScopeName !== undefined &&
552
+ options.scope !== importScopeName
553
+ ) {
554
+ throw new ViewMutationError(
555
+ "scopeMismatch",
556
+ "Insert scope must match the import instance name."
557
+ );
558
+ }
559
+
560
+ return options.scope ?? importScopeName;
561
+ }
562
+
563
+ /**
564
+ * @param {import("./view.js").default} parentView
565
+ * @param {string} scopeName
566
+ */
567
+ function ensureScopeNameIsAvailable(parentView, scopeName) {
568
+ const parentScope = getViewScopeChain(parentView);
569
+ const targetScope = parentScope.concat(scopeName);
570
+
571
+ getRootView().visit((view) => {
572
+ const info = getImportScopeInfo(view);
573
+ if (
574
+ info &&
575
+ info.name === scopeName &&
576
+ scopesEqual(getViewScopeChain(view), targetScope)
577
+ ) {
578
+ throw new ViewMutationError(
579
+ "duplicateScope",
580
+ 'Scope "' + scopeName + '" already exists.'
581
+ );
582
+ }
583
+ });
584
+ }
585
+
586
+ /**
587
+ * @param {string[]} a
588
+ * @param {string[]} b
589
+ * @returns {boolean}
590
+ */
591
+ function scopesEqual(a, b) {
592
+ if (a.length !== b.length) {
593
+ return false;
594
+ }
595
+
596
+ return a.every((value, index) => value === b[index]);
597
+ }
598
+
599
+ /**
600
+ * @param {import("../spec/view.js").ViewSpec | import("../spec/view.js").ImportSpec} spec
601
+ * @returns {spec is import("../spec/view.js").UnitSpec | import("../spec/view.js").LayerSpec | import("../spec/view.js").MultiscaleSpec | import("../spec/view.js").ImportSpec}
602
+ */
603
+ function isLayerChildSpec(spec) {
604
+ if (isImportSpec(spec)) {
605
+ return true;
606
+ }
607
+
608
+ const viewSpec = /** @type {import("../spec/view.js").ViewSpec} */ (
609
+ spec
610
+ );
611
+ return (
612
+ isUnitSpec(viewSpec) ||
613
+ isLayerSpec(viewSpec) ||
614
+ isMultiscaleSpec(viewSpec)
615
+ );
616
+ }
617
+
618
+ /**
619
+ * @param {ViewAddress} targetAddress
620
+ * @returns {Promise<void>}
621
+ */
622
+ function remove(targetAddress) {
623
+ return enqueue(async () => {
624
+ const targetView = getView(targetAddress);
625
+ if (targetView === getRootView() || !targetView.layoutParent) {
626
+ throw new ViewMutationError(
627
+ "cannotRemoveRoot",
628
+ "Removing the root view is not supported."
629
+ );
630
+ }
631
+
632
+ const parentView = targetView.layoutParent;
633
+ const children = getLayoutChildren(parentView);
634
+ if (!children) {
635
+ throw new ViewMutationError(
636
+ "unsupportedContainer",
637
+ "Parent view does not expose layout children."
638
+ );
639
+ }
640
+
641
+ const index = children.indexOf(targetView);
642
+ if (index < 0) {
643
+ throw new ViewMutationError(
644
+ "invalidHierarchy",
645
+ "Target view is not a child of its layout parent."
646
+ );
647
+ }
648
+
649
+ await removeChildFromMutableContainer(parentView, index);
650
+ });
651
+ }
652
+
653
+ /**
654
+ * @param {import("./view.js").default} parentView
655
+ * @param {number} index
656
+ */
657
+ async function removeChildFromMutableContainer(parentView, index) {
658
+ if (parentView instanceof ConcatView) {
659
+ await parentView.removeChildAt(index);
660
+ } else if (parentView instanceof LayerView) {
661
+ await parentView.removeChildAt(index);
662
+ } else {
663
+ throw new ViewMutationError(
664
+ "unsupportedContainer",
665
+ "Only concat and layer views support child removal."
666
+ );
667
+ }
668
+ }
669
+
670
+ /**
671
+ * @param {ViewAddress} targetAddress
672
+ * @param {import("../types/embedApi.js").MoveViewOptions} options
673
+ * @returns {Promise<ViewHandle>}
674
+ */
675
+ function move(targetAddress, options) {
676
+ return enqueue(async () => {
677
+ const targetView = getView(targetAddress);
678
+ if (targetView === getRootView() || !targetView.layoutParent) {
679
+ throw new ViewMutationError(
680
+ "cannotMoveRoot",
681
+ "Moving the root view is not supported."
682
+ );
683
+ }
684
+
685
+ const parentView = targetView.layoutParent;
686
+ const children = getLayoutChildren(parentView);
687
+ if (!children) {
688
+ throw new ViewMutationError(
689
+ "unsupportedContainer",
690
+ "Parent view does not expose layout children."
691
+ );
692
+ }
693
+
694
+ const fromIndex = children.indexOf(targetView);
695
+ if (fromIndex < 0) {
696
+ throw new ViewMutationError(
697
+ "invalidHierarchy",
698
+ "Target view is not a child of its layout parent."
699
+ );
700
+ }
701
+
702
+ if (!options) {
703
+ throw new ViewMutationError(
704
+ "invalidIndex",
705
+ "Move options with an index are required."
706
+ );
707
+ }
708
+
709
+ const index = getMoveIndex(options.index, children.length - 1);
710
+ await moveChildWithinMutableContainer(parentView, fromIndex, index);
711
+
712
+ return getHandle(targetView);
713
+ });
714
+ }
715
+
716
+ /**
717
+ * @param {number | undefined} index
718
+ * @param {number} remainingChildCount
719
+ * @returns {number}
720
+ */
721
+ function getMoveIndex(index, remainingChildCount) {
722
+ if (!Number.isInteger(index)) {
723
+ throw new ViewMutationError(
724
+ "invalidIndex",
725
+ "Move index must be an integer."
726
+ );
727
+ }
728
+
729
+ if (index < 0 || index > remainingChildCount) {
730
+ throw new ViewMutationError(
731
+ "invalidIndex",
732
+ "Move index must be between 0 and the remaining child count."
733
+ );
734
+ }
735
+
736
+ return index;
737
+ }
738
+
739
+ /**
740
+ * @param {import("./view.js").default} parentView
741
+ * @param {number} fromIndex
742
+ * @param {number} index
743
+ */
744
+ async function moveChildWithinMutableContainer(
745
+ parentView,
746
+ fromIndex,
747
+ index
748
+ ) {
749
+ if (parentView instanceof ConcatView) {
750
+ await parentView.moveChildAt(fromIndex, index);
751
+ } else if (parentView instanceof LayerView) {
752
+ parentView.moveChildAt(fromIndex, index);
753
+ } else {
754
+ throw new ViewMutationError(
755
+ "unsupportedContainer",
756
+ "Only concat and layer views support child reordering."
757
+ );
758
+ }
759
+ }
760
+
761
+ /** @type {import("../types/embedApi.js").ViewApi} */
762
+ const api = {
763
+ root: () => getHandle(getRootView()),
764
+
765
+ resolve,
766
+
767
+ get,
768
+
769
+ getLayoutBounds,
770
+
771
+ subscribeToLayout,
772
+
773
+ insert,
774
+
775
+ remove,
776
+
777
+ move,
778
+
779
+ transaction: (callback) =>
780
+ activeTransaction
781
+ ? runTransaction(callback)
782
+ : enqueueTopLevelOperation(() => runTransaction(callback)),
783
+ };
784
+
785
+ return api;
786
+ }
787
+
788
+ /**
789
+ * @param {unknown} address
790
+ * @returns {address is import("../types/embedApi.js").ViewHandle}
791
+ */
792
+ function isViewHandle(address) {
793
+ return (
794
+ typeof address === "object" &&
795
+ address !== null &&
796
+ typeof (/** @type {any} */ (address).isAlive) === "function"
797
+ );
798
+ }
799
+
800
+ /**
801
+ * @param {unknown} address
802
+ * @returns {address is import("../view/viewUtilTypes.d.ts").ViewSelector}
803
+ */
804
+ function isViewSelector(address) {
805
+ return (
806
+ typeof address === "object" &&
807
+ address !== null &&
808
+ Array.isArray(/** @type {any} */ (address).scope) &&
809
+ typeof (/** @type {any} */ (address).view) === "string"
810
+ );
811
+ }