@jbrowse/core 5.0.0-beta.1 → 5.0.0-beta.3

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 (199) hide show
  1. package/README.md +112 -43
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -3
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +4 -3
  6. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
  7. package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +2 -2
  8. package/esm/BaseFeatureWidget/index.d.ts +1 -1
  9. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +8 -1
  10. package/esm/BaseFeatureWidget/stateModelFactory.js +6 -0
  11. package/esm/BaseFeatureWidget/types.d.ts +10 -2
  12. package/esm/PluginLoader.d.ts +1 -0
  13. package/esm/PluginLoader.js +52 -8
  14. package/esm/PluginManager.d.ts +99 -17
  15. package/esm/PluginManager.js +194 -26
  16. package/esm/ReExports/BaseFeatureDetails.js +1 -1
  17. package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
  18. package/esm/ReExports/MuiDataGridReExports.js +2 -2
  19. package/esm/ReExports/barrelOnlyNames.d.ts +5 -0
  20. package/esm/ReExports/barrelOnlyNames.js +63 -0
  21. package/esm/ReExports/modules.js +31 -109
  22. package/esm/ReExports/publicTracks.d.ts +1 -0
  23. package/esm/ReExports/publicTracks.js +14 -0
  24. package/esm/ReExports/publicUi.d.ts +4 -0
  25. package/esm/ReExports/publicUi.js +33 -0
  26. package/esm/ReExports/publicUtil.d.ts +1 -1
  27. package/esm/ReExports/publicUtil.js +8 -4
  28. package/esm/ReExports/sharedModules.d.ts +96 -0
  29. package/esm/ReExports/sharedModules.js +66 -0
  30. package/esm/ReExports/uiStub.d.ts +2 -0
  31. package/esm/ReExports/uiStub.js +11 -0
  32. package/esm/ReExports/workerModules.d.ts +2 -0
  33. package/esm/ReExports/workerModules.js +15 -0
  34. package/esm/ReExports/workerNamespaceNames.d.ts +11 -0
  35. package/esm/ReExports/workerNamespaceNames.js +281 -0
  36. package/esm/configuration/configurationSchema.d.ts +5 -38
  37. package/esm/configuration/configurationSchema.js +64 -40
  38. package/esm/configuration/index.d.ts +2 -2
  39. package/esm/configuration/index.js +1 -1
  40. package/esm/configuration/promotableDefaults.d.ts +54 -19
  41. package/esm/configuration/promotableDefaults.js +117 -48
  42. package/esm/configuration/promotablePin.d.ts +50 -40
  43. package/esm/configuration/promotableResolve.d.ts +1 -1
  44. package/esm/configuration/promotableResolve.js +1 -1
  45. package/esm/configuration/tabixIndexFields.d.ts +2 -2
  46. package/esm/configuration/tabixIndexFields.js +2 -2
  47. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +12 -0
  48. package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +35 -4
  49. package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +41 -0
  50. package/esm/data_adapters/BaseAdapter/featureDensity.js +32 -0
  51. package/esm/data_adapters/BaseAdapter/index.d.ts +2 -1
  52. package/esm/data_adapters/BaseAdapter/index.js +1 -0
  53. package/esm/data_adapters/BaseAdapter/stats.d.ts +33 -1
  54. package/esm/data_adapters/BaseAdapter/stats.js +52 -13
  55. package/esm/data_adapters/BaseAdapter/types.d.ts +3 -8
  56. package/esm/pluggableElementTypes/AdapterType.d.ts +2 -1
  57. package/esm/pluggableElementTypes/AdapterType.js +1 -1
  58. package/esm/pluggableElementTypes/DisplayType.d.ts +4 -12
  59. package/esm/pluggableElementTypes/DisplayType.js +3 -10
  60. package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +27 -0
  61. package/esm/pluggableElementTypes/LazyStateModelElement.js +71 -0
  62. package/esm/pluggableElementTypes/ViewType.d.ts +20 -4
  63. package/esm/pluggableElementTypes/ViewType.js +32 -4
  64. package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
  65. package/esm/pluggableElementTypes/extendElementType.js +9 -5
  66. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +44 -3
  67. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +75 -2
  68. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +21 -0
  69. package/esm/pluggableElementTypes/models/BaseTrackModel.js +34 -2
  70. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +49 -0
  71. package/esm/pluggableElementTypes/models/BaseViewModel.js +28 -0
  72. package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +14 -10
  73. package/esm/pluggableElementTypes/models/assertDisplayContract.js +25 -32
  74. package/esm/pluggableElementTypes/models/baseTrackConfig.js +7 -1
  75. package/esm/rpc/RpcRegistry.d.ts +10 -0
  76. package/esm/rpc/byteBudget.d.ts +9 -0
  77. package/esm/rpc/coreRpcMethods.d.ts +1 -0
  78. package/esm/rpc/coreRpcMethods.js +1 -0
  79. package/esm/rpc/methods/CoreGetFeatureDensity.d.ts +11 -0
  80. package/esm/rpc/methods/CoreGetFeatureDensity.js +22 -0
  81. package/esm/svg/svgReady.d.ts +1 -0
  82. package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
  83. package/esm/ui/CascadingMenu.js +30 -8
  84. package/esm/ui/ErrorMessageStackTraceDialog.js +5 -6
  85. package/esm/ui/ExportSvgDialog.d.ts +1 -1
  86. package/esm/ui/LoadingOverlay.d.ts +14 -0
  87. package/esm/ui/LoadingOverlay.js +1 -1
  88. package/esm/ui/MenuTypes.d.ts +14 -5
  89. package/esm/ui/MenuTypes.js +3 -0
  90. package/esm/ui/PaletteContext.d.ts +11 -4
  91. package/esm/ui/PaletteContext.js +34 -5
  92. package/esm/ui/PinAdornment.js +31 -43
  93. package/esm/ui/ScrollChrome.d.ts +16 -0
  94. package/esm/ui/ScrollChrome.js +12 -0
  95. package/esm/ui/ScrollZoomToggle.d.ts +4 -3
  96. package/esm/ui/ScrollZoomToggle.js +4 -3
  97. package/esm/ui/SizeSliderRow.js +1 -1
  98. package/esm/ui/index.d.ts +3 -3
  99. package/esm/ui/index.js +4 -4
  100. package/esm/ui/launchViewMenu.js +7 -1
  101. package/esm/ui/legendMenuItem.d.ts +10 -16
  102. package/esm/ui/legendMenuItem.js +9 -20
  103. package/esm/ui/makeSizeMenu.js +1 -1
  104. package/esm/ui/menuItemAdornment.d.ts +2 -3
  105. package/esm/ui/menuItemAdornment.js +2 -3
  106. package/esm/ui/menuItems.d.ts +2 -3
  107. package/esm/ui/menuItems.js +1 -2
  108. package/esm/ui/palette.d.ts +11 -11
  109. package/esm/ui/palette.js +11 -11
  110. package/esm/ui/promotablePinCoverage.d.ts +16 -2
  111. package/esm/ui/promotablePinCoverage.js +40 -3
  112. package/esm/ui/theme.js +5 -0
  113. package/esm/ui/toggleMenuItems.d.ts +14 -9
  114. package/esm/ui/toggleMenuItems.js +32 -15
  115. package/esm/util/Base1DUtils.d.ts +4 -2
  116. package/esm/util/Base1DUtils.js +12 -4
  117. package/esm/util/SvgCanvas.js +4 -3
  118. package/esm/util/adapterConfigKey.d.ts +12 -0
  119. package/esm/util/adapterConfigKey.js +14 -0
  120. package/esm/util/adapterMetadata.js +2 -1
  121. package/esm/util/addAndShowTrack.d.ts +1 -1
  122. package/esm/util/addAndShowTrack.js +5 -1
  123. package/esm/util/addTrackFromWidget.js +2 -2
  124. package/esm/util/analytics.js +4 -5
  125. package/esm/util/cacheBudgets.d.ts +22 -19
  126. package/esm/util/cacheBudgets.js +22 -19
  127. package/esm/util/clampToContig.d.ts +17 -0
  128. package/esm/util/clampToContig.js +19 -0
  129. package/esm/util/colorBits.d.ts +2 -1
  130. package/esm/util/colorBits.js +2 -5
  131. package/esm/util/createStopTokenRotation.d.ts +9 -7
  132. package/esm/util/createStopTokenRotation.js +7 -27
  133. package/esm/util/featureTypes.d.ts +24 -0
  134. package/esm/util/featureTypes.js +35 -0
  135. package/esm/util/fetchContext.d.ts +2 -2
  136. package/esm/util/fetchContext.js +2 -2
  137. package/esm/util/fetchPhases.d.ts +10 -10
  138. package/esm/util/hooks.d.ts +8 -0
  139. package/esm/util/hooks.js +27 -0
  140. package/esm/util/index.d.ts +6 -5
  141. package/esm/util/index.js +5 -4
  142. package/esm/util/installFetch.d.ts +71 -34
  143. package/esm/util/installFetch.js +57 -29
  144. package/esm/util/installInitAutorun.d.ts +14 -13
  145. package/esm/util/installInitAutorun.js +17 -17
  146. package/esm/util/installPrerequisiteFetch.d.ts +86 -0
  147. package/esm/util/installPrerequisiteFetch.js +73 -0
  148. package/esm/util/lazyAfterAttach.d.ts +13 -0
  149. package/esm/util/lazyAfterAttach.js +31 -0
  150. package/esm/util/legendCandidates.d.ts +50 -0
  151. package/esm/util/legendCandidates.js +87 -0
  152. package/esm/util/mstUtils.d.ts +12 -1
  153. package/esm/util/mstUtils.js +20 -2
  154. package/esm/util/openFeatureWidget.d.ts +5 -0
  155. package/esm/util/openFeatureWidget.js +1 -0
  156. package/esm/util/openViews.d.ts +16 -0
  157. package/esm/util/openViews.js +22 -0
  158. package/esm/util/parentWalk.d.ts +1 -1
  159. package/esm/util/parentWalk.js +1 -1
  160. package/esm/util/pluginStore.d.ts +1 -0
  161. package/esm/util/pluginStore.js +8 -1
  162. package/esm/util/range.d.ts +13 -9
  163. package/esm/util/range.js +17 -8
  164. package/esm/util/renderToStaticMarkup.js +10 -0
  165. package/esm/util/rxjs.d.ts +16 -0
  166. package/esm/util/rxjs.js +49 -0
  167. package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
  168. package/esm/util/scheduleDetachedDestroy.js +24 -0
  169. package/esm/util/scrollLatch.d.ts +1 -0
  170. package/esm/util/scrollLatch.js +8 -0
  171. package/esm/util/stopToken.d.ts +6 -5
  172. package/esm/util/tabix.d.ts +10 -4
  173. package/esm/util/tabix.js +11 -5
  174. package/esm/util/trackConfigDelta.d.ts +6 -6
  175. package/esm/util/trackConfigDelta.js +3 -3
  176. package/esm/util/tracks.d.ts +48 -0
  177. package/esm/util/tracks.js +192 -66
  178. package/esm/util/types/index.d.ts +58 -10
  179. package/esm/util/types/index.js +3 -0
  180. package/esm/util/unknownSnapshotKeys.d.ts +36 -0
  181. package/esm/util/unknownSnapshotKeys.js +69 -0
  182. package/esm/util/usePanelVirtualScroll.d.ts +6 -2
  183. package/esm/util/usePanelVirtualScroll.js +6 -2
  184. package/esm/util/useRowVirtualScroll.d.ts +1 -1
  185. package/esm/util/useRowVirtualScroll.js +1 -1
  186. package/esm/util/useVirtualScrollWheel.js +11 -1
  187. package/esm/util/viewStatus.d.ts +23 -0
  188. package/esm/util/viewStatus.js +17 -0
  189. package/esm/util/wheelZoom.d.ts +3 -1
  190. package/esm/util/wheelZoom.js +39 -14
  191. package/esm/util/whenViewSettled.d.ts +17 -4
  192. package/esm/util/whenViewSettled.js +19 -6
  193. package/esm/util/withLaunchInput.d.ts +168 -0
  194. package/esm/util/withLaunchInput.js +273 -0
  195. package/package.json +19 -11
  196. package/esm/ui/promotableMenuItems.d.ts +0 -19
  197. package/esm/ui/promotableMenuItems.js +0 -89
  198. package/esm/util/applyInitSettings.d.ts +0 -79
  199. package/esm/util/applyInitSettings.js +0 -91
@@ -0,0 +1,273 @@
1
+ import { reportLegacyInit, reportMalformedRows, reportUnknownKeys, } from './unknownSnapshotKeys.js';
2
+ // re-exported here because the surfaces that classify their own keys — a
3
+ // session spec, which launches without ever building a snapshot — reach the
4
+ // partition's vocabulary through this module
5
+ export { legacyInitMessage, unknownKeysMessage } from './unknownSnapshotKeys.js';
6
+ // What afterAttach reports rather than applies. They live in the blob so the
7
+ // partition has one place to put everything, and `pendingLaunch` is what keeps
8
+ // them from reading as work to do.
9
+ const REPORTED = new Set(['unknown', 'malformed', 'legacyInit']);
10
+ /**
11
+ * The blob when it still holds something to apply, else undefined. A view's
12
+ * gates ask this rather than the raw property: a snapshot whose only launch
13
+ * content was a typo has nothing to launch, and a view that thinks otherwise
14
+ * waits on an assembly nobody named and never leaves the spinner.
15
+ *
16
+ * Returns the blob itself, never a copy — the launch autorun clears by
17
+ * identity, and a fresh object per read strands the init it just applied.
18
+ */
19
+ export function pendingLaunch(launch) {
20
+ return launch && Object.keys(launch).some(k => !REPORTED.has(k))
21
+ ? launch
22
+ : undefined;
23
+ }
24
+ /**
25
+ * Declare one view's launch keys. The argument is
26
+ * `Record<keyof Commands, LaunchKeySpec>`, so a command the view interprets and
27
+ * nobody registered is a compile error rather than a key that partitions as a
28
+ * typo and warns.
29
+ *
30
+ * `passThrough` names keys that are neither a launch key nor a declared
31
+ * property and still belong on the snapshot — a legacy spelling the view's own
32
+ * `preProcessSnapshot` converts.
33
+ */
34
+ export function defineLaunchKeys() {
35
+ return (keys, { passThrough } = {}) => ({
36
+ keys,
37
+ passThrough: passThrough ?? [],
38
+ });
39
+ }
40
+ // `id` picks up MST's optional identifier and `type` picks the view, so neither
41
+ // is ever a setting and neither can be lifted off the snapshot.
42
+ const IDENTITY = new Set(['id', 'type']);
43
+ const LAUNCH = 'launch';
44
+ /**
45
+ * The part of a launch spec that belongs on the snapshot: everything but the
46
+ * launch keys, and the identity and `launch` keys no spec may set. For a caller
47
+ * that applies the launch itself and builds the view from a snapshot — a
48
+ * synteny row, whose parent navigates it and opens its tracks — so what it
49
+ * hands MST is settings only, and the view's own partition sorts those into
50
+ * properties and reported typos.
51
+ */
52
+ export function snapshotSettings(spec, registration) {
53
+ const keys = registration?.keys ?? {};
54
+ return Object.fromEntries(Object.entries(spec).filter(([key]) => !(key in keys) && !IDENTITY.has(key) && key !== LAUNCH));
55
+ }
56
+ function isObject(value) {
57
+ return !!value && typeof value === 'object';
58
+ }
59
+ // Each per-entry kind says only which entries are an authored recipe. A recipe
60
+ // goes to the blob for the launcher to resolve; everything else is a built
61
+ // snapshot and stays on the property, so a mixed array splits rather than
62
+ // picking one meaning for the whole thing.
63
+ function isRecipeEntry(kind, entry) {
64
+ switch (kind) {
65
+ case 'trackEntries':
66
+ // a built track snapshot cannot carry `trackId` — BaseTrackModel does not
67
+ // declare it. `type` does not discriminate: a spec writes display types
68
+ // inline
69
+ return (typeof entry === 'string' || (isObject(entry) && 'trackId' in entry));
70
+ case 'highlightEntries':
71
+ // a string needs coerceHighlight and the assembly manager, neither of
72
+ // which a pure preprocessor can reach; an object is the persisted shape
73
+ return typeof entry === 'string';
74
+ case 'rows':
75
+ // a built row is a view snapshot, and every view's `type` is a required
76
+ // literal
77
+ return !(isObject(entry) && 'type' in entry);
78
+ default:
79
+ return true;
80
+ }
81
+ }
82
+ function splitEntries(kind, value) {
83
+ const entries = Array.isArray(value) ? value : [value];
84
+ const recipes = entries.filter(e => isRecipeEntry(kind, e));
85
+ const built = entries.filter(e => !isRecipeEntry(kind, e));
86
+ return {
87
+ launch: recipes.length
88
+ ? Array.isArray(value)
89
+ ? recipes
90
+ : value
91
+ : undefined,
92
+ state: built.length ? (Array.isArray(value) ? built : value) : undefined,
93
+ };
94
+ }
95
+ // The properties a snapshot's keys are classified against are the REGISTERED
96
+ // view type's, read at preprocess time: `extendViewType` composes onto the
97
+ // model after `withLaunchInput` wrapped it, and a set frozen at wrap time sent
98
+ // every added property to `unknown` — restored at its default, with a warning
99
+ // naming it a typo. The wrapped model's own properties are the answer when no
100
+ // registry is given, or the snapshot names a type it does not hold, which is
101
+ // how a factory-built model in a test behaves.
102
+ function knownPropsResolver(model, registry) {
103
+ let cachedProps;
104
+ let cachedKeys = new Set();
105
+ return (snap) => {
106
+ const name = snap.type;
107
+ const registered = registry && typeof name === 'string' && registry.viewTypes.has(name)
108
+ ? registry.getViewType(name)
109
+ : undefined;
110
+ const props = registered?.isStateModelLoaded
111
+ ? registered.stateModel.properties
112
+ : model.properties;
113
+ if (props !== cachedProps) {
114
+ cachedProps = props;
115
+ cachedKeys = new Set(Object.keys(props));
116
+ }
117
+ return cachedKeys;
118
+ };
119
+ }
120
+ function classify(snap, { keys, passThrough }, known, out) {
121
+ for (const [key, value] of Object.entries(snap)) {
122
+ const spec = keys[key];
123
+ if (IDENTITY.has(key)) {
124
+ out.state[key] = value;
125
+ }
126
+ else if (spec?.kind === 'launch') {
127
+ out.launch[key] = value;
128
+ }
129
+ else if (spec?.kind === 'replay') {
130
+ out.state[key] = value;
131
+ out.launch[key] = value;
132
+ }
133
+ else if (spec) {
134
+ const { launch, state } = splitEntries(spec.kind, value);
135
+ if (spec.kind === 'rows' && launch !== undefined && state !== undefined) {
136
+ // A row list indexes against `levels` and `tracks[i]`, so lifting half
137
+ // of it renumbers the other half. Nothing here can throw — a pure
138
+ // preprocessor runs against snapshots the union is about to reject — so
139
+ // the whole list goes to the bucket afterAttach reports and the view
140
+ // comes up on its import form rather than on a silently misaligned
141
+ // stack.
142
+ out.malformed[key] = value;
143
+ }
144
+ else {
145
+ if (launch !== undefined) {
146
+ out.launch[key] = launch;
147
+ }
148
+ if (state !== undefined) {
149
+ out.state[key] = state;
150
+ }
151
+ }
152
+ }
153
+ else if (known.has(key) || passThrough.includes(key)) {
154
+ out.state[key] = value;
155
+ }
156
+ else {
157
+ out.unknown[key] = value;
158
+ }
159
+ }
160
+ }
161
+ // BreakpointSplitView's v4 `init` was a bare array of panels rather than an
162
+ // object of settings. A positional list can only be the view's row list, and a
163
+ // view declares at most one, so it is read as that key rather than classified
164
+ // per index — which would name "0" and "1" as unknown keys.
165
+ function legacyInitSnapshot(init, { keys }) {
166
+ const rows = Object.entries(keys).find(([, spec]) => spec.kind === 'rows')?.[0];
167
+ return Array.isArray(init) && rows ? { [rows]: init } : init;
168
+ }
169
+ /**
170
+ * Accept a view's settings written directly on the view object, and move the
171
+ * ones a launcher has to resolve into the internal `launch` property.
172
+ *
173
+ * The partition is a `preProcessSnapshot` and is PURE. A session's view type is
174
+ * a `types.union`, so MST runs every member's preprocessor against every
175
+ * candidate snapshot while deciding which one matches, and runs it about twice
176
+ * more per instantiation; a warning from in here fires against snapshots that
177
+ * are about to be rejected. `afterAttach` — reached only by a snapshot that won
178
+ * — reports what the partition captured.
179
+ *
180
+ * `registry` is the PluginManager. With it the partition classifies against
181
+ * the view type as registered, `extendViewType`'s added properties included;
182
+ * without it, against the model as wrapped here. `materialized` draws the line
183
+ * past which the blob is no longer persisted; see `LaunchInputOptions`.
184
+ *
185
+ * ORDER: MST runs preprocessors in the reverse of the order they were added, so
186
+ * this belongs on the chain BEFORE a view's own legacy-key preprocessor, where
187
+ * it partitions the snapshot MST finally consumes rather than a key that remap
188
+ * is about to convert.
189
+ *
190
+ * The widening cast is the LAST link that may change the creation type: it
191
+ * replaces `CustomC`, so a `.props()` added after it is invisible to
192
+ * `SnapshotIn`. Further `preProcessSnapshot`/`postProcessSnapshot` links are
193
+ * fine — both carry `CustomC` through.
194
+ *
195
+ * Not `types.snapshotProcessor`, which carries the same widened input and stops
196
+ * being a `ModelType`. `PluginManager.pluggableMstType` filters union members on
197
+ * `isModelType`, so a wrapped view is dropped from the session's view union
198
+ * without a word, and `ViewType.stateModel` and every `.properties`
199
+ * introspection site break with it.
200
+ */
201
+ export function withLaunchInput(model, registration, { registry, materialized }) {
202
+ const knownProps = knownPropsResolver(model, registry);
203
+ const partitioned = model
204
+ .preProcessSnapshot((snap) => {
205
+ if (!isObject(snap)) {
206
+ return snap;
207
+ }
208
+ const known = knownProps(snap);
209
+ const { init, ...rest } = snap;
210
+ const out = {
211
+ state: {},
212
+ launch: {},
213
+ unknown: {},
214
+ malformed: {},
215
+ };
216
+ if (isObject(init)) {
217
+ // v4's nesting, unwrapped rather than refused: a nested key sorts the
218
+ // same three ways a flat one does, so honoring it costs one more pass
219
+ // and a deprecation warning, where dropping it opens an admin's
220
+ // `defaultSession` on its defaults. First, so a snapshot spelling one
221
+ // key both ways resolves to the flat one the docs teach.
222
+ classify(legacyInitSnapshot(init, registration), registration, known, out);
223
+ out.launch.legacyInit = true;
224
+ }
225
+ classify(rest, registration, known, out);
226
+ if (Object.keys(out.unknown).length) {
227
+ out.launch.unknown = out.unknown;
228
+ }
229
+ if (Object.keys(out.malformed).length) {
230
+ out.launch.malformed = out.malformed;
231
+ }
232
+ const persisted = out.state[LAUNCH];
233
+ return Object.keys(out.launch).length
234
+ ? {
235
+ ...out.state,
236
+ [LAUNCH]: {
237
+ ...(isObject(persisted) ? persisted : {}),
238
+ ...out.launch,
239
+ },
240
+ }
241
+ : out.state;
242
+ })
243
+ .actions(self => ({
244
+ afterAttach() {
245
+ const { launch } = self;
246
+ if (launch?.legacyInit) {
247
+ reportLegacyInit(self);
248
+ }
249
+ reportUnknownKeys(self, Object.keys(launch?.unknown ?? {}));
250
+ reportMalformedRows(self, Object.keys(launch?.malformed ?? {}));
251
+ },
252
+ }))
253
+ // Whole while the view has yet to materialize, since the pending launch is
254
+ // then the only thing a reload can rebuild the view from, and gone once it
255
+ // has — the report keys with it, so a saved session never carries a
256
+ // typo report about content it no longer holds. `legacyInit` goes either
257
+ // way: it names the SPELLING of the snapshot this view was opened from,
258
+ // and the saved one does not use it, so persisting it would report nesting
259
+ // on every restore forever (`pendingLaunch` excludes the report keys, so
260
+ // no launch run ever clears it).
261
+ .postProcessSnapshot((snap) => {
262
+ const launch = snap[LAUNCH];
263
+ if (!isObject(launch)) {
264
+ return snap;
265
+ }
266
+ const { legacyInit, ...kept } = launch;
267
+ return Object.keys(kept).length &&
268
+ !materialized(snap)
269
+ ? { ...snap, [LAUNCH]: kept }
270
+ : Object.fromEntries(Object.entries(snap).filter(([key]) => key !== LAUNCH));
271
+ });
272
+ return partitioned;
273
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/core",
3
- "version": "5.0.0-beta.1",
3
+ "version": "5.0.0-beta.3",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 core libraries used by plugins",
6
6
  "keywords": [
@@ -32,6 +32,8 @@
32
32
  "./PluginLoader": "./esm/PluginLoader.js",
33
33
  "./PluginManager": "./esm/PluginManager.js",
34
34
  "./ReExports/list": "./esm/ReExports/list.js",
35
+ "./ReExports/modules": "./esm/ReExports/modules.js",
36
+ "./ReExports/registry": "./esm/ReExports/registry.js",
35
37
  "./TextSearch/BaseResults": "./esm/TextSearch/BaseResults.js",
36
38
  "./TextSearch/TextSearchManager": "./esm/TextSearch/TextSearchManager.js",
37
39
  "./assemblyManager": "./esm/assemblyManager/index.js",
@@ -44,6 +46,7 @@
44
46
  "./data_adapters/BaseAdapter/getAdapterId": "./esm/data_adapters/BaseAdapter/getAdapterId.js",
45
47
  "./data_adapters/BaseAdapter/stats": "./esm/data_adapters/BaseAdapter/stats.js",
46
48
  "./data_adapters/BaseAdapter/types": "./esm/data_adapters/BaseAdapter/types.js",
49
+ "./data_adapters/adapterSessionRefcount": "./esm/data_adapters/adapterSessionRefcount.js",
47
50
  "./data_adapters/dataAdapterCache": "./esm/data_adapters/dataAdapterCache.js",
48
51
  "./data_adapters/getFeatureAdapter": "./esm/data_adapters/getFeatureAdapter.js",
49
52
  "./data_adapters/getSequenceSubAdapter": "./esm/data_adapters/getSequenceSubAdapter.js",
@@ -140,14 +143,13 @@
140
143
  "./util/Base1DUtils": "./esm/util/Base1DUtils.js",
141
144
  "./util/Base1DViewModel": "./esm/util/Base1DViewModel.js",
142
145
  "./util/FileSaver": "./esm/util/FileSaver/index.js",
143
- "./util/QuickLRU": "./esm/util/QuickLRU/index.js",
144
146
  "./util/SvgCanvas": "./esm/util/SvgCanvas.js",
145
147
  "./util/TimeTraveller": "./esm/util/TimeTraveller.js",
146
148
  "./util/aborting": "./esm/util/aborting.js",
149
+ "./util/adapterConfigKey": "./esm/util/adapterConfigKey.js",
147
150
  "./util/adapterMetadata": "./esm/util/adapterMetadata.js",
148
151
  "./util/addRelativeUris": "./esm/util/addRelativeUris.js",
149
152
  "./util/analytics": "./esm/util/analytics.js",
150
- "./util/applyInitSettings": "./esm/util/applyInitSettings.js",
151
153
  "./util/assemblyConfigUtils": "./esm/util/assemblyConfigUtils.js",
152
154
  "./util/bandHeight": "./esm/util/bandHeight.js",
153
155
  "./util/bandLayout": "./esm/util/bandLayout.js",
@@ -185,6 +187,7 @@
185
187
  "./util/installClearHoverOnSurfaceMove": "./esm/util/installClearHoverOnSurfaceMove.js",
186
188
  "./util/installFetch": "./esm/util/installFetch.js",
187
189
  "./util/installInitAutorun": "./esm/util/installInitAutorun.js",
190
+ "./util/installPrerequisiteFetch": "./esm/util/installPrerequisiteFetch.js",
188
191
  "./util/io": "./esm/util/io/index.js",
189
192
  "./util/io/RemoteFileWithRangeCache": "./esm/util/io/RemoteFileWithRangeCache.js",
190
193
  "./util/isDataCurrent": "./esm/util/isDataCurrent.js",
@@ -194,14 +197,18 @@
194
197
  "./util/layouts": "./esm/util/layouts/index.js",
195
198
  "./util/layouts/GranularRectLayout": "./esm/util/layouts/GranularRectLayout.js",
196
199
  "./util/layouts/placeRect": "./esm/util/layouts/placeRect.js",
200
+ "./util/lazyAfterAttach": "./esm/util/lazyAfterAttach.js",
197
201
  "./util/leadingEdgeAutorun": "./esm/util/leadingEdgeAutorun.js",
202
+ "./util/legendCandidates": "./esm/util/legendCandidates.js",
198
203
  "./util/librpc": "./esm/util/librpc.js",
199
204
  "./util/localStorage": "./esm/util/localStorage.js",
200
205
  "./util/makeAssembly": "./esm/util/makeAssembly.js",
206
+ "./util/mst-reflection": "./esm/util/mst-reflection.js",
201
207
  "./util/mstUtils": "./esm/util/mstUtils.js",
202
208
  "./util/nanoid": "./esm/util/nanoid.js",
203
209
  "./util/numericUtils": "./esm/util/numericUtils.js",
204
210
  "./util/offscreenCanvasPonyfill": "./esm/util/offscreenCanvasPonyfill.js",
211
+ "./util/openViews": "./esm/util/openViews.js",
205
212
  "./util/paintLayer": "./esm/util/paintLayer.js",
206
213
  "./util/parseLineByLine": "./esm/util/parseLineByLine.js",
207
214
  "./util/progress": "./esm/util/progress.js",
@@ -235,7 +242,8 @@
235
242
  "./util/viewStatus": "./esm/util/viewStatus.js",
236
243
  "./util/virtualRange": "./esm/util/virtualRange.js",
237
244
  "./util/wheelZoom": "./esm/util/wheelZoom.js",
238
- "./util/whenViewSettled": "./esm/util/whenViewSettled.js"
245
+ "./util/whenViewSettled": "./esm/util/whenViewSettled.js",
246
+ "./util/withLaunchInput": "./esm/util/withLaunchInput.js"
239
247
  },
240
248
  "files": [
241
249
  "esm"
@@ -253,13 +261,13 @@
253
261
  "@jbrowse/mobx-state-tree": "^6.5.1",
254
262
  "@jbrowse/quick-lru": "^7.3.5",
255
263
  "@leeoniya/ufuzzy": "^1.0.19",
256
- "@mui/icons-material": "^9.3.1",
257
- "@mui/material": "^9.3.1",
258
- "@mui/system": "^9.3.0",
259
- "@mui/x-data-grid": "^9.12.0",
264
+ "@mui/icons-material": "^9.4.0",
265
+ "@mui/material": "^9.4.0",
266
+ "@mui/system": "^9.4.0",
267
+ "@mui/x-data-grid": "^9.13.0",
260
268
  "canvas-sequencer-ts": "^3.1.3",
261
269
  "compare-versions": "^6.1.1",
262
- "dompurify": "^3.4.14",
270
+ "dompurify": "^3.4.15",
263
271
  "generic-filehandle2": "^2.4.0",
264
272
  "idb": "^8.0.3",
265
273
  "mobx": "^7.0.3",
@@ -267,8 +275,8 @@
267
275
  "pako-esm2": "^2.0.2",
268
276
  "rxjs": "^7.8.2",
269
277
  "source-map-js": "^1.2.1",
270
- "@jbrowse/add-track-core": "^5.0.0-beta.1",
271
- "@jbrowse/render-core": "^5.0.0-beta.1"
278
+ "@jbrowse/add-track-core": "^5.0.0-beta.3",
279
+ "@jbrowse/render-core": "^5.0.0-beta.3"
272
280
  },
273
281
  "peerDependencies": {
274
282
  "react": ">=19.0.0",
@@ -1,19 +0,0 @@
1
- import type { Pin } from '../configuration/promotablePin.ts';
2
- import type { CheckboxMenuItem, RadioMenuItem } from './MenuTypes.ts';
3
- import type { RadioOption, SettingRowOptions } from './toggleMenuItems.ts';
4
- /** #menuBuilder promotableToggleItem | `checkboxItem` plus an apply-to-open-tracks pin */
5
- export declare function promotableToggleItem({ label, checked, onToggle, pin, ...opts }: {
6
- label: string;
7
- checked: boolean;
8
- onToggle: () => void;
9
- pin: Pin;
10
- } & SettingRowOptions): CheckboxMenuItem;
11
- /** #menuBuilder promotableRadioItem | `radioItem` plus an apply-to-open-tracks pin */
12
- export declare function promotableRadioItem({ label, checked, onClick, pin, ...opts }: {
13
- label: string;
14
- checked: boolean;
15
- onClick: () => void;
16
- pin?: Pin;
17
- } & SettingRowOptions): RadioMenuItem;
18
- /** #menuBuilder promotableRadioItems | `radioItems` plus a pin per option, from a factory over the value */
19
- export declare function promotableRadioItems<T extends string>(options: readonly RadioOption<T>[], current: T | undefined, setMode: (m: T) => void, pin: (value: T) => Pin): RadioMenuItem[];
@@ -1,89 +0,0 @@
1
- import { checkboxItem, radioItem, radioItems } from './toggleMenuItems.js';
2
- // Every builder here describes the trailing pin (`pin`) rather than
3
- // rendering it. That is what keeps this module — and therefore every state
4
- // model and menu file that calls it — free of React and of MUI's
5
- // ToggleButton/Tooltip. `menuItemAdornment.tsx` turns the description into
6
- // `PinAdornment` at the point the menu is drawn. See
7
- // reference/EAGER_BUNDLE.md; `menuItems.purity.test.ts` holds it.
8
- //
9
- // Each is the plain builder in `toggleMenuItems.ts` plus a pin, and each is
10
- // written that way — `checkboxItem` / `radioItems` build the row — so the
11
- // promotable and plain forms of a row can differ only by the pin.
12
- // A promotable setting as one native checkbox menu row: the value toggles the
13
- // track (inheriting native hover/sizing/keyboard), and a trailing pin
14
- // (endAdornment) applies this value to every open track of the display type,
15
- // offering the display-type default as its snackbar's one action. Always shown
16
- // so the capability is discoverable.
17
- //
18
- // **The row itself is `checkboxItem`'s**, so the two builders can only ever
19
- // differ by the pin. They used to be two literals, and had already drifted: this
20
- // one accepted `helpText` and `keepMenuOpen` while silently dropping `disabled`
21
- // and `disabledHelpText`, so a promotable row could not be greyed out the way
22
- // its plain sibling could. Sharing the body is also what makes a future
23
- // change to what a checkbox row *is* reach both — the failure `checkboxItem`'s
24
- // own comment records is a menu regressing by omission.
25
- //
26
- // `keepMenuOpen` is left unset by default, so `CascadingMenu` keeps the row open
27
- // by its checkbox type: these rows only write a setting, users flip several in
28
- // one visit, and the menu is an observer so the ticks and pins move live. A row
29
- // whose click opens a dialog instead (colorBy's "Tag...") passes false.
30
- /** #menuBuilder promotableToggleItem | `checkboxItem` plus an apply-to-open-tracks pin */
31
- export function promotableToggleItem({ label, checked, onToggle, pin, ...opts }) {
32
- return {
33
- ...checkboxItem(label, checked, onToggle, opts),
34
- pin: { control: pin, label },
35
- };
36
- }
37
- // ONE radio row of a promotable-value group — the escape hatch, for a group the
38
- // plural builder below can't express. **Reach for `promotableRadioItems` first**:
39
- // every option in a group has to get a pin, and hand-naming the rows is what
40
- // leaves one without.
41
- //
42
- // The rows that genuinely need this: `pin` is optional here, for a row with no
43
- // single value to promote yet (the colorBy "Tag..." row before a tag is picked)
44
- // or a display whose slot isn't promotable at all (the shared colorBy menu on
45
- // gwas/variants); and the alignments size presets, whose group is gated row by
46
- // row (`needsContent`) and mixes in a non-promotable "Custom..." peer.
47
- //
48
- // **The row itself is `radioItem`'s**, for the reason `promotableToggleItem`'s
49
- // is `checkboxItem`'s: it was a second literal, and it had drifted the same way
50
- // its checkbox sibling had — naming `helpText`/`keepMenuOpen` by hand and so
51
- // silently dropping `disabled` and `disabledHelpText`, which the
52
- // alignments size presets have to bolt back on afterwards (`needsContent`).
53
- /** #menuBuilder promotableRadioItem | `radioItem` plus an apply-to-open-tracks pin */
54
- export function promotableRadioItem({ label, checked, onClick, pin, ...opts }) {
55
- return {
56
- ...radioItem(label, checked, onClick, opts),
57
- ...(pin && {
58
- pin: { control: pin, label },
59
- }),
60
- };
61
- }
62
- // A whole promotable radio group: `radioItems` plus one pin per option. The
63
- // plural form of the builder above, and the one to reach for on a group whose
64
- // options differ only in their value — which is all four of them today
65
- // (`heightMode`, `displayMode`, `subfeatureLabels`, `sashimiArcsMode`).
66
- //
67
- // **Every option in a group gets a pin, the `promotedBase` value included** —
68
- // once a non-base value is promoted, pinning the base back is the only per-value
69
- // way to undo it from its own row, and a radio group with one row silently
70
- // missing its trailing control reads as a bug. Building the group here is what
71
- // makes that structural instead of a rule to remember: `sashimiArcsMode`'s base
72
- // looked unpinnable precisely because each row had been named by hand. Prefer
73
- // this over `.map(promotableRadioItem)` whenever the pin is a function of the
74
- // option's value.
75
- //
76
- // `pin` is a factory rather than an array so it can't be a row short. Pass
77
- // `value => makePin(self, slot, value)`, or a model member of that shape where
78
- // the menu module is handed a duck-typed model (alignments).
79
- //
80
- // The rows are `radioItems`' own, so the promotable and plain groups can't drift
81
- // on anything but the pin. `radioItems` maps `options` in order, which is what
82
- // lets each row be paired back to the option that built it.
83
- /** #menuBuilder promotableRadioItems | `radioItems` plus a pin per option, from a factory over the value */
84
- export function promotableRadioItems(options, current, setMode, pin) {
85
- return radioItems(options, current, setMode).map((item, i) => {
86
- const { value, label } = options[i];
87
- return { ...item, pin: { control: pin(value), label } };
88
- });
89
- }
@@ -1,79 +0,0 @@
1
- import type { IAnyModelType, IStateTreeNode, SnapshotIn } from '@jbrowse/mobx-state-tree';
2
- /**
3
- * A view's init type, derived: the keys its launcher interprets (`Commands`)
4
- * plus every declared property of its state model, optional, in the property's
5
- * own snapshot type. Nothing is restated, so a property is authorable — and
6
- * TYPED — from the line that declares it.
7
- *
8
- * ```ts
9
- * export type LinearSyntenyViewInit = ViewInit<
10
- * LinearSyntenyViewStateModel,
11
- * LinearSyntenyViewCommands
12
- * >
13
- * ```
14
- *
15
- * THE ONE RULE THIS DEPENDS ON: the model's own `init` property must be typed
16
- * as the `Commands`, not as this. `init` is a property, so an `init` typed as
17
- * the whole thing makes the whole thing depend on itself — TS7023 on the
18
- * factory, then implicit-any across every file that touches the view (ADR-055,
19
- * same failure the view/display instance pair has). Commands never mention the
20
- * model, so typing `init` as those breaks the loop, and it costs nothing: the
21
- * view's own code reads the commands out of `self.init`, and the settings half
22
- * is read only by `applyInitSettings`, which asks the model rather than a type.
23
- */
24
- export type ViewInit<M extends IAnyModelType, Commands> = Commands & Partial<Omit<SnapshotIn<M>, keyof Commands | (typeof RESERVED_KEYS)[number]>>;
25
- export declare const RESERVED_KEYS: readonly ['id', 'type', 'init'];
26
- export interface InitSettingsReport {
27
- /** keys applied, in the order they were found */
28
- applied: string[];
29
- /** keys naming no declared property — a typo, or a prop that never existed */
30
- unknown: string[];
31
- /** declared keys whose value the property's own type rejected */
32
- invalid: string[];
33
- }
34
- /**
35
- * Apply the plain-settings half of an `init` blob: every key naming a declared
36
- * MST property of `self` is written straight to it, and the caller handles only
37
- * the keys it names in `commands`.
38
- *
39
- * THE POINT IS THAT THERE IS NO PER-SETTING CODE. A view used to need a
40
- * hand-written `if (init.x !== undefined) self.setX(init.x)` arm per property,
41
- * so a new toggle worked from its menu the moment it was declared and was
42
- * dropped in silence from every authored surface — a session spec, a share
43
- * link, a config `defaultSession` — until someone remembered the second edit.
44
- * Nobody did: `drawLocationMarkers` shipped unauthorable, and DotplotView's
45
- * `alpha`/`drawCigar`/`lineWidth`/`lockAspectRatio` never had an arm at all.
46
- * Reading the property list off the model at runtime means declaring the
47
- * property IS declaring it authorable, including properties a composed mixin
48
- * brings in (colorBy, showColorLegend), and there is nothing left to keep in
49
- * sync.
50
- *
51
- * `commands` is what a launcher genuinely has to interpret: keys with no
52
- * property behind them (`loc`, `autoDiagonalize`), keys whose name collides
53
- * with a property meaning something else (a spec's `views` is a list of
54
- * assemblies to open; the model's `views` is the built rows), and keys with an
55
- * ordering constraint (`levelHeights` must land after the auto-scale pass).
56
- * Listing one is a decision to write code for it; everything else needs none.
57
- *
58
- * WRITTEN AS A PATCH, not through `setX`. Applying init is state restoration,
59
- * and the authority on that is MST: `applyPatch` validates each value against
60
- * the property's own type and touches nothing else, where `applySnapshot`
61
- * would rebuild the view's children. That it skips the setters is correct
62
- * rather than a shortcut — a session reload restores the same state from a
63
- * snapshot and calls no setters either, so a property needing a setter's side
64
- * effect to be correct is already broken on reload, and the effect belongs in a
65
- * reaction on the property.
66
- *
67
- * A value the property's type rejects is dropped and reported rather than
68
- * thrown: init blobs come from URLs, and one bad number should not cost the
69
- * reader the whole view.
70
- */
71
- export declare function applyInitSettings(self: IStateTreeNode, init: object | undefined, { commands }?: {
72
- commands?: readonly string[];
73
- }): InitSettingsReport;
74
- /**
75
- * Say what `applyInitSettings` refused, naming the surface. Split from the
76
- * apply so a caller under test can assert the report without a console, and so
77
- * the two messages read the same wherever they come from.
78
- */
79
- export declare function warnInitSettings(surface: string, report: InitSettingsReport): void;
@@ -1,91 +0,0 @@
1
- import { applyPatch, getPropertyMembers } from '@jbrowse/mobx-state-tree';
2
- // Keys that are a view's identity or its plumbing rather than a setting. A
3
- // launch spec never gets to write these: `type` picks the view, `id` is passed
4
- // top-level so MST's optional identifier honors it, and `init` inside `init` is
5
- // the nesting mistake loadSessionSpec already reports.
6
- export const RESERVED_KEYS = ['id', 'type', 'init'];
7
- const RESERVED = new Set(RESERVED_KEYS);
8
- /**
9
- * Apply the plain-settings half of an `init` blob: every key naming a declared
10
- * MST property of `self` is written straight to it, and the caller handles only
11
- * the keys it names in `commands`.
12
- *
13
- * THE POINT IS THAT THERE IS NO PER-SETTING CODE. A view used to need a
14
- * hand-written `if (init.x !== undefined) self.setX(init.x)` arm per property,
15
- * so a new toggle worked from its menu the moment it was declared and was
16
- * dropped in silence from every authored surface — a session spec, a share
17
- * link, a config `defaultSession` — until someone remembered the second edit.
18
- * Nobody did: `drawLocationMarkers` shipped unauthorable, and DotplotView's
19
- * `alpha`/`drawCigar`/`lineWidth`/`lockAspectRatio` never had an arm at all.
20
- * Reading the property list off the model at runtime means declaring the
21
- * property IS declaring it authorable, including properties a composed mixin
22
- * brings in (colorBy, showColorLegend), and there is nothing left to keep in
23
- * sync.
24
- *
25
- * `commands` is what a launcher genuinely has to interpret: keys with no
26
- * property behind them (`loc`, `autoDiagonalize`), keys whose name collides
27
- * with a property meaning something else (a spec's `views` is a list of
28
- * assemblies to open; the model's `views` is the built rows), and keys with an
29
- * ordering constraint (`levelHeights` must land after the auto-scale pass).
30
- * Listing one is a decision to write code for it; everything else needs none.
31
- *
32
- * WRITTEN AS A PATCH, not through `setX`. Applying init is state restoration,
33
- * and the authority on that is MST: `applyPatch` validates each value against
34
- * the property's own type and touches nothing else, where `applySnapshot`
35
- * would rebuild the view's children. That it skips the setters is correct
36
- * rather than a shortcut — a session reload restores the same state from a
37
- * snapshot and calls no setters either, so a property needing a setter's side
38
- * effect to be correct is already broken on reload, and the effect belongs in a
39
- * reaction on the property.
40
- *
41
- * A value the property's type rejects is dropped and reported rather than
42
- * thrown: init blobs come from URLs, and one bad number should not cost the
43
- * reader the whole view.
44
- */
45
- export function applyInitSettings(self,
46
- // `object` rather than a keyed record: an init blob's static type is the
47
- // view's own `ViewInit`, which has named members and no index signature — by
48
- // design, so a typo is a compile error there — and that is not assignable to
49
- // `Record<string, unknown>`. This reads it by enumeration anyway.
50
- init, { commands = [] } = {}) {
51
- const report = { applied: [], unknown: [], invalid: [] };
52
- if (!init) {
53
- return report;
54
- }
55
- const skip = new Set(commands);
56
- const { properties } = getPropertyMembers(self);
57
- const patch = [];
58
- for (const [key, value] of Object.entries(init)) {
59
- if (skip.has(key) || RESERVED.has(key) || value === undefined) {
60
- continue;
61
- }
62
- const propType = properties[key];
63
- if (!propType) {
64
- report.unknown.push(key);
65
- }
66
- else if (!propType.is(value)) {
67
- report.invalid.push(key);
68
- }
69
- else {
70
- patch.push({ op: 'replace', path: `/${key}`, value });
71
- report.applied.push(key);
72
- }
73
- }
74
- if (patch.length) {
75
- applyPatch(self, patch);
76
- }
77
- return report;
78
- }
79
- /**
80
- * Say what `applyInitSettings` refused, naming the surface. Split from the
81
- * apply so a caller under test can assert the report without a console, and so
82
- * the two messages read the same wherever they come from.
83
- */
84
- export function warnInitSettings(surface, report) {
85
- if (report.unknown.length) {
86
- console.warn(`${surface} ignored unknown key(s): ${report.unknown.join(', ')}`);
87
- }
88
- if (report.invalid.length) {
89
- console.warn(`${surface} ignored key(s) with an invalid value: ${report.invalid.join(', ')}`);
90
- }
91
- }