@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.
- package/README.md +112 -43
- package/esm/BaseFeatureWidget/BaseFeatureDetail/FeatureDetails.d.ts +2 -3
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.d.ts +4 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/ParentFeatureLine.js +17 -0
- package/esm/BaseFeatureWidget/BaseFeatureDetail/index.js +4 -3
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.d.ts +2 -2
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +2 -2
- package/esm/BaseFeatureWidget/index.d.ts +1 -1
- package/esm/BaseFeatureWidget/stateModelFactory.d.ts +8 -1
- package/esm/BaseFeatureWidget/stateModelFactory.js +6 -0
- package/esm/BaseFeatureWidget/types.d.ts +10 -2
- package/esm/PluginLoader.d.ts +1 -0
- package/esm/PluginLoader.js +52 -8
- package/esm/PluginManager.d.ts +99 -17
- package/esm/PluginManager.js +194 -26
- package/esm/ReExports/BaseFeatureDetails.js +1 -1
- package/esm/ReExports/MuiDataGridReExports.d.ts +1 -0
- package/esm/ReExports/MuiDataGridReExports.js +2 -2
- package/esm/ReExports/barrelOnlyNames.d.ts +5 -0
- package/esm/ReExports/barrelOnlyNames.js +63 -0
- package/esm/ReExports/modules.js +31 -109
- package/esm/ReExports/publicTracks.d.ts +1 -0
- package/esm/ReExports/publicTracks.js +14 -0
- package/esm/ReExports/publicUi.d.ts +4 -0
- package/esm/ReExports/publicUi.js +33 -0
- package/esm/ReExports/publicUtil.d.ts +1 -1
- package/esm/ReExports/publicUtil.js +8 -4
- package/esm/ReExports/sharedModules.d.ts +96 -0
- package/esm/ReExports/sharedModules.js +66 -0
- package/esm/ReExports/uiStub.d.ts +2 -0
- package/esm/ReExports/uiStub.js +11 -0
- package/esm/ReExports/workerModules.d.ts +2 -0
- package/esm/ReExports/workerModules.js +15 -0
- package/esm/ReExports/workerNamespaceNames.d.ts +11 -0
- package/esm/ReExports/workerNamespaceNames.js +281 -0
- package/esm/configuration/configurationSchema.d.ts +5 -38
- package/esm/configuration/configurationSchema.js +64 -40
- package/esm/configuration/index.d.ts +2 -2
- package/esm/configuration/index.js +1 -1
- package/esm/configuration/promotableDefaults.d.ts +54 -19
- package/esm/configuration/promotableDefaults.js +117 -48
- package/esm/configuration/promotablePin.d.ts +50 -40
- package/esm/configuration/promotableResolve.d.ts +1 -1
- package/esm/configuration/promotableResolve.js +1 -1
- package/esm/configuration/tabixIndexFields.d.ts +2 -2
- package/esm/configuration/tabixIndexFields.js +2 -2
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +12 -0
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +35 -4
- package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +41 -0
- package/esm/data_adapters/BaseAdapter/featureDensity.js +32 -0
- package/esm/data_adapters/BaseAdapter/index.d.ts +2 -1
- package/esm/data_adapters/BaseAdapter/index.js +1 -0
- package/esm/data_adapters/BaseAdapter/stats.d.ts +33 -1
- package/esm/data_adapters/BaseAdapter/stats.js +52 -13
- package/esm/data_adapters/BaseAdapter/types.d.ts +3 -8
- package/esm/pluggableElementTypes/AdapterType.d.ts +2 -1
- package/esm/pluggableElementTypes/AdapterType.js +1 -1
- package/esm/pluggableElementTypes/DisplayType.d.ts +4 -12
- package/esm/pluggableElementTypes/DisplayType.js +3 -10
- package/esm/pluggableElementTypes/LazyStateModelElement.d.ts +27 -0
- package/esm/pluggableElementTypes/LazyStateModelElement.js +71 -0
- package/esm/pluggableElementTypes/ViewType.d.ts +20 -4
- package/esm/pluggableElementTypes/ViewType.js +32 -4
- package/esm/pluggableElementTypes/extendElementType.d.ts +1 -2
- package/esm/pluggableElementTypes/extendElementType.js +9 -5
- package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +44 -3
- package/esm/pluggableElementTypes/models/BaseDisplayModel.js +75 -2
- package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +21 -0
- package/esm/pluggableElementTypes/models/BaseTrackModel.js +34 -2
- package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +49 -0
- package/esm/pluggableElementTypes/models/BaseViewModel.js +28 -0
- package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +14 -10
- package/esm/pluggableElementTypes/models/assertDisplayContract.js +25 -32
- package/esm/pluggableElementTypes/models/baseTrackConfig.js +7 -1
- package/esm/rpc/RpcRegistry.d.ts +10 -0
- package/esm/rpc/byteBudget.d.ts +9 -0
- package/esm/rpc/coreRpcMethods.d.ts +1 -0
- package/esm/rpc/coreRpcMethods.js +1 -0
- package/esm/rpc/methods/CoreGetFeatureDensity.d.ts +11 -0
- package/esm/rpc/methods/CoreGetFeatureDensity.js +22 -0
- package/esm/svg/svgReady.d.ts +1 -0
- package/esm/ui/BaseExportSvgDialog.d.ts +1 -1
- package/esm/ui/CascadingMenu.js +30 -8
- package/esm/ui/ErrorMessageStackTraceDialog.js +5 -6
- package/esm/ui/ExportSvgDialog.d.ts +1 -1
- package/esm/ui/LoadingOverlay.d.ts +14 -0
- package/esm/ui/LoadingOverlay.js +1 -1
- package/esm/ui/MenuTypes.d.ts +14 -5
- package/esm/ui/MenuTypes.js +3 -0
- package/esm/ui/PaletteContext.d.ts +11 -4
- package/esm/ui/PaletteContext.js +34 -5
- package/esm/ui/PinAdornment.js +31 -43
- package/esm/ui/ScrollChrome.d.ts +16 -0
- package/esm/ui/ScrollChrome.js +12 -0
- package/esm/ui/ScrollZoomToggle.d.ts +4 -3
- package/esm/ui/ScrollZoomToggle.js +4 -3
- package/esm/ui/SizeSliderRow.js +1 -1
- package/esm/ui/index.d.ts +3 -3
- package/esm/ui/index.js +4 -4
- package/esm/ui/launchViewMenu.js +7 -1
- package/esm/ui/legendMenuItem.d.ts +10 -16
- package/esm/ui/legendMenuItem.js +9 -20
- package/esm/ui/makeSizeMenu.js +1 -1
- package/esm/ui/menuItemAdornment.d.ts +2 -3
- package/esm/ui/menuItemAdornment.js +2 -3
- package/esm/ui/menuItems.d.ts +2 -3
- package/esm/ui/menuItems.js +1 -2
- package/esm/ui/palette.d.ts +11 -11
- package/esm/ui/palette.js +11 -11
- package/esm/ui/promotablePinCoverage.d.ts +16 -2
- package/esm/ui/promotablePinCoverage.js +40 -3
- package/esm/ui/theme.js +5 -0
- package/esm/ui/toggleMenuItems.d.ts +14 -9
- package/esm/ui/toggleMenuItems.js +32 -15
- package/esm/util/Base1DUtils.d.ts +4 -2
- package/esm/util/Base1DUtils.js +12 -4
- package/esm/util/SvgCanvas.js +4 -3
- package/esm/util/adapterConfigKey.d.ts +12 -0
- package/esm/util/adapterConfigKey.js +14 -0
- package/esm/util/adapterMetadata.js +2 -1
- package/esm/util/addAndShowTrack.d.ts +1 -1
- package/esm/util/addAndShowTrack.js +5 -1
- package/esm/util/addTrackFromWidget.js +2 -2
- package/esm/util/analytics.js +4 -5
- package/esm/util/cacheBudgets.d.ts +22 -19
- package/esm/util/cacheBudgets.js +22 -19
- package/esm/util/clampToContig.d.ts +17 -0
- package/esm/util/clampToContig.js +19 -0
- package/esm/util/colorBits.d.ts +2 -1
- package/esm/util/colorBits.js +2 -5
- package/esm/util/createStopTokenRotation.d.ts +9 -7
- package/esm/util/createStopTokenRotation.js +7 -27
- package/esm/util/featureTypes.d.ts +24 -0
- package/esm/util/featureTypes.js +35 -0
- package/esm/util/fetchContext.d.ts +2 -2
- package/esm/util/fetchContext.js +2 -2
- package/esm/util/fetchPhases.d.ts +10 -10
- package/esm/util/hooks.d.ts +8 -0
- package/esm/util/hooks.js +27 -0
- package/esm/util/index.d.ts +6 -5
- package/esm/util/index.js +5 -4
- package/esm/util/installFetch.d.ts +71 -34
- package/esm/util/installFetch.js +57 -29
- package/esm/util/installInitAutorun.d.ts +14 -13
- package/esm/util/installInitAutorun.js +17 -17
- package/esm/util/installPrerequisiteFetch.d.ts +86 -0
- package/esm/util/installPrerequisiteFetch.js +73 -0
- package/esm/util/lazyAfterAttach.d.ts +13 -0
- package/esm/util/lazyAfterAttach.js +31 -0
- package/esm/util/legendCandidates.d.ts +50 -0
- package/esm/util/legendCandidates.js +87 -0
- package/esm/util/mstUtils.d.ts +12 -1
- package/esm/util/mstUtils.js +20 -2
- package/esm/util/openFeatureWidget.d.ts +5 -0
- package/esm/util/openFeatureWidget.js +1 -0
- package/esm/util/openViews.d.ts +16 -0
- package/esm/util/openViews.js +22 -0
- package/esm/util/parentWalk.d.ts +1 -1
- package/esm/util/parentWalk.js +1 -1
- package/esm/util/pluginStore.d.ts +1 -0
- package/esm/util/pluginStore.js +8 -1
- package/esm/util/range.d.ts +13 -9
- package/esm/util/range.js +17 -8
- package/esm/util/renderToStaticMarkup.js +10 -0
- package/esm/util/rxjs.d.ts +16 -0
- package/esm/util/rxjs.js +49 -0
- package/esm/util/scheduleDetachedDestroy.d.ts +18 -0
- package/esm/util/scheduleDetachedDestroy.js +24 -0
- package/esm/util/scrollLatch.d.ts +1 -0
- package/esm/util/scrollLatch.js +8 -0
- package/esm/util/stopToken.d.ts +6 -5
- package/esm/util/tabix.d.ts +10 -4
- package/esm/util/tabix.js +11 -5
- package/esm/util/trackConfigDelta.d.ts +6 -6
- package/esm/util/trackConfigDelta.js +3 -3
- package/esm/util/tracks.d.ts +48 -0
- package/esm/util/tracks.js +192 -66
- package/esm/util/types/index.d.ts +58 -10
- package/esm/util/types/index.js +3 -0
- package/esm/util/unknownSnapshotKeys.d.ts +36 -0
- package/esm/util/unknownSnapshotKeys.js +69 -0
- package/esm/util/usePanelVirtualScroll.d.ts +6 -2
- package/esm/util/usePanelVirtualScroll.js +6 -2
- package/esm/util/useRowVirtualScroll.d.ts +1 -1
- package/esm/util/useRowVirtualScroll.js +1 -1
- package/esm/util/useVirtualScrollWheel.js +11 -1
- package/esm/util/viewStatus.d.ts +23 -0
- package/esm/util/viewStatus.js +17 -0
- package/esm/util/wheelZoom.d.ts +3 -1
- package/esm/util/wheelZoom.js +39 -14
- package/esm/util/whenViewSettled.d.ts +17 -4
- package/esm/util/whenViewSettled.js +19 -6
- package/esm/util/withLaunchInput.d.ts +168 -0
- package/esm/util/withLaunchInput.js +273 -0
- package/package.json +19 -11
- package/esm/ui/promotableMenuItems.d.ts +0 -19
- package/esm/ui/promotableMenuItems.js +0 -89
- package/esm/util/applyInitSettings.d.ts +0 -79
- package/esm/util/applyInitSettings.js +0 -91
package/esm/PluginManager.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import PhasedScheduler from './PhasedScheduler.ts';
|
|
2
2
|
import './util/tracks.ts';
|
|
3
3
|
import type Plugin from './Plugin.ts';
|
|
4
|
+
import type { PluginConstructor } from './Plugin.ts';
|
|
4
5
|
import type AdapterType from './pluggableElementTypes/AdapterType.ts';
|
|
5
6
|
import type AddTrackWorkflowType from './pluggableElementTypes/AddTrackWorkflowType.ts';
|
|
6
7
|
import type ConnectionType from './pluggableElementTypes/ConnectionType.ts';
|
|
@@ -20,7 +21,7 @@ import './ui/buildExtraTrackMenuItems.ts';
|
|
|
20
21
|
import './ui/multiTrackMenuItems.ts';
|
|
21
22
|
import './util/addTrackComponent.ts';
|
|
22
23
|
import type { AbstractRootModel, AbstractSessionModel, SimpleFeatureSerialized } from './util/index.ts';
|
|
23
|
-
import type { IAnyModelType, IStateTreeNode, IAnyType } from '@jbrowse/mobx-state-tree';
|
|
24
|
+
import type { IAnyModelType, IStateTreeNode, IAnyType, SnapshotIn } from '@jbrowse/mobx-state-tree';
|
|
24
25
|
import type { ComponentType, ReactNode } from 'react';
|
|
25
26
|
/**
|
|
26
27
|
* Every pluggable element group, in the order `elementCreationSchedule` builds
|
|
@@ -137,7 +138,18 @@ export interface ReplaceWidgetProps {
|
|
|
137
138
|
*
|
|
138
139
|
* That is what makes `extendViewType(pm, 'LinearGenomeView', …)` hand back a
|
|
139
140
|
* typed state model, and a misspelled or renamed name a compile error rather
|
|
140
|
-
* than an extension that quietly never applies.
|
|
141
|
+
* than an extension that quietly never applies. `getViewType` reads it too, so
|
|
142
|
+
* a caller composing another view's model into its own gets the real type
|
|
143
|
+
* instead of `IAnyModelType`.
|
|
144
|
+
*
|
|
145
|
+
* AN AUGMENTATION IS HAND-WRITTEN, so each registration annotates the model it
|
|
146
|
+
* passes to `ViewType` against its own entry here (`const stateModel:
|
|
147
|
+
* ViewTypeRegistry['CircularView'] = …`). That one line is what makes the
|
|
148
|
+
* registry earn what `getViewType` promises: without it a drifted entry is
|
|
149
|
+
* worse than the `IAnyModelType` it replaced, since a caller would get a
|
|
150
|
+
* confidently wrong type rather than an unchecked one. It cannot live on
|
|
151
|
+
* `ViewType`'s constructor — TypeScript forbids type parameters there, and a
|
|
152
|
+
* class parameter widens `name` to `string`, so the conditional never fires. Declaring them here rather than
|
|
141
153
|
* beside the helpers is load-bearing: an interface can only be augmented
|
|
142
154
|
* through the module that declares it, and a barrel re-exporting the type would
|
|
143
155
|
* give every augmentation its own unrelated copy.
|
|
@@ -148,6 +160,21 @@ export interface DisplayTypeRegistry {
|
|
|
148
160
|
}
|
|
149
161
|
export type ViewTypeName = keyof ViewTypeRegistry;
|
|
150
162
|
export type DisplayTypeName = keyof DisplayTypeRegistry;
|
|
163
|
+
/**
|
|
164
|
+
* What `addView(name, snapshot)` takes for a view type name. A registered name
|
|
165
|
+
* gets the view's authored shape — the snapshot type `withLaunchInput` widened
|
|
166
|
+
* to accept the launch keys beside the declared properties — so a misspelled
|
|
167
|
+
* key is a compile error at the literal site. `type` is optional because
|
|
168
|
+
* `addView` writes it. An unregistered name stays `Record<string, unknown>`,
|
|
169
|
+
* which is what an out-of-tree view's `addView` has always been.
|
|
170
|
+
*
|
|
171
|
+
* Read off `ViewTypeRegistry` rather than registered a second time, so the
|
|
172
|
+
* snapshot type cannot drift from the model: a view that augments the registry
|
|
173
|
+
* has typed `addView`, `replaceView` and `addOrReplaceView` for free.
|
|
174
|
+
*/
|
|
175
|
+
export type ViewSnapshotInput<N extends string> = N extends ViewTypeName ? Omit<SnapshotIn<ViewTypeRegistry[N]>, 'type'> & {
|
|
176
|
+
type?: N;
|
|
177
|
+
} : Record<string, unknown>;
|
|
151
178
|
export interface ExtensionPointRegistry {
|
|
152
179
|
'Core-extendSession': {
|
|
153
180
|
args: IAnyModelType;
|
|
@@ -264,10 +291,20 @@ export interface PluginLoadRecord {
|
|
|
264
291
|
metadata?: PluginMetadata;
|
|
265
292
|
plugin: Plugin;
|
|
266
293
|
}
|
|
294
|
+
/**
|
|
295
|
+
* Instantiate an application's bundled plugin list as `isCore` load records —
|
|
296
|
+
* what tells the plugin store these came with the bundle rather than being
|
|
297
|
+
* installed by the user, so `InstalledPluginsList` filters them out and the
|
|
298
|
+
* About widget lists them. Every product and every test harness builds its
|
|
299
|
+
* manager from one of these lists, and a harness that passed bare instances
|
|
300
|
+
* silently disagreed with the app it was testing.
|
|
301
|
+
*/
|
|
302
|
+
export declare function corePluginRecords(plugins: PluginConstructor[]): PluginLoadRecord[];
|
|
267
303
|
export interface RuntimePluginLoadRecord extends PluginLoadRecord {
|
|
268
304
|
definition: PluginDefinition;
|
|
269
305
|
}
|
|
270
306
|
export default class PluginManager {
|
|
307
|
+
#private;
|
|
271
308
|
plugins: Plugin[];
|
|
272
309
|
jexl: import("@jbrowse/jexl").Jexl;
|
|
273
310
|
pluginMetadata: Record<string, PluginMetadata>;
|
|
@@ -289,25 +326,27 @@ export default class PluginManager {
|
|
|
289
326
|
extensionPoints: Map<string, ExtensionPointCallback[]>;
|
|
290
327
|
warnedClobber: Set<string>;
|
|
291
328
|
/**
|
|
292
|
-
*
|
|
293
|
-
* `
|
|
329
|
+
* The lazily-hydrated MST config node for one frozen track config, built by
|
|
330
|
+
* `build` on first ask and returned by identity after that.
|
|
331
|
+
* `configuration/configurationSchema.ts` is the only caller.
|
|
332
|
+
*
|
|
294
333
|
* `jbrowse.tracks` is `types.frozen` for large-tracklist performance, so a
|
|
295
|
-
* track config is a plain JS object until first referenced; hydrating it
|
|
296
|
-
*
|
|
297
|
-
*
|
|
298
|
-
*
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
302
|
-
*
|
|
303
|
-
* See ADR-031.
|
|
334
|
+
* track config is a plain JS object until first referenced; hydrating it into
|
|
335
|
+
* an MST node is deferred to that read. MST's custom-reference `getValue` has
|
|
336
|
+
* no memoization of its own — it reruns on every property access — so without
|
|
337
|
+
* this, every read of `track.configuration` would fabricate a fresh,
|
|
338
|
+
* non-identical node. Keyed by schemaType (each track type's config schema is
|
|
339
|
+
* rebuilt fresh per PluginManager instance, see addTrackType) then by the
|
|
340
|
+
* frozen object, so a hit can only ever come from this same instance and this
|
|
341
|
+
* same track type. See ADR-031.
|
|
304
342
|
*
|
|
305
|
-
*
|
|
343
|
+
* The node is never mutated: admin edits replace the frozen entry (new
|
|
306
344
|
* identity drops the WeakMap entry), and a non-admin's edits go to a private
|
|
307
345
|
* session working copy, not here (ADR-032). Both levels are `WeakMap`s so
|
|
308
|
-
* entries collect normally — no manual invalidation needed
|
|
346
|
+
* entries collect normally — no manual invalidation needed, which is why this
|
|
347
|
+
* is a memo and not a cache with a lifecycle to expose.
|
|
309
348
|
*/
|
|
310
|
-
|
|
349
|
+
hydratedTrackConfig(schemaType: IAnyType, frozen: object, build: () => unknown): unknown;
|
|
311
350
|
constructor(initialPlugins?: (Plugin | PluginLoadRecord | RuntimePluginLoadRecord)[]);
|
|
312
351
|
pluginConfigurationNamespacedSchemas(): Record<string, unknown>;
|
|
313
352
|
pluginConfigurationUnnamespacedSchemas(): Record<string, unknown>;
|
|
@@ -330,10 +369,22 @@ export default class PluginManager {
|
|
|
330
369
|
getRpcElements(): RpcMethodType[];
|
|
331
370
|
getDisplayElements(): DisplayType[];
|
|
332
371
|
getAdapterElements(): AdapterType[];
|
|
333
|
-
/**
|
|
372
|
+
/**
|
|
373
|
+
* get a MST type for the union of all specified pluggable MST types.
|
|
374
|
+
* Membership is late-bound, so a lazily registered state model joins when
|
|
375
|
+
* its loader resolves; a snapshot naming one cannot be cast until then.
|
|
376
|
+
*/
|
|
334
377
|
pluggableMstType(groupName: PluggableElementTypeGroup, fieldName: string, fallback?: IAnyType): IAnyType;
|
|
335
378
|
/** get a MST type for the union of all specified pluggable config schemas */
|
|
336
379
|
pluggableConfigSchemaType(typeGroup: PluggableElementTypeGroup, fieldName?: string): IAnyType;
|
|
380
|
+
/**
|
|
381
|
+
* An adapter union dispatches on `type`, so a config still spelling an
|
|
382
|
+
* adapter's old name has to be rewritten to the name it registers under
|
|
383
|
+
* before the union sees it. Here rather than in each schema holding an
|
|
384
|
+
* adapter slot, so a track, an assembly's sequence and a connection all take
|
|
385
|
+
* it.
|
|
386
|
+
*/
|
|
387
|
+
private canonicalizeAdapterSnapshot;
|
|
337
388
|
jbrequireCache: Map<any, any>;
|
|
338
389
|
get lib(): Record<string, unknown>;
|
|
339
390
|
load: <FTYPE extends AnyFunction>(lib: FTYPE) => ReturnType<FTYPE>;
|
|
@@ -347,6 +398,12 @@ export default class PluginManager {
|
|
|
347
398
|
default: AnyFunction;
|
|
348
399
|
}) => any;
|
|
349
400
|
getAdapterType(typeName: string): AdapterType;
|
|
401
|
+
/**
|
|
402
|
+
* The name an adapter `type` registers under: itself, or the adapter that
|
|
403
|
+
* declares it in `aliases`. A name nothing answers to comes back as written,
|
|
404
|
+
* so the registered-names error still names what the config said.
|
|
405
|
+
*/
|
|
406
|
+
canonicalAdapterTypeName(typeName: string): string;
|
|
350
407
|
/**
|
|
351
408
|
* Whether an adapter type is registered, for a caller walking a config where
|
|
352
409
|
* `type` names a track, a display and an adapter alike — `getAdapterType`
|
|
@@ -357,7 +414,32 @@ export default class PluginManager {
|
|
|
357
414
|
getTextSearchAdapterType(typeName: string): TextSearchAdapterType;
|
|
358
415
|
getTrackType(typeName: string): TrackType;
|
|
359
416
|
getDisplayType(typeName: string): DisplayType;
|
|
417
|
+
getViewType<N extends ViewTypeName>(typeName: N): Omit<ViewType, 'stateModel'> & {
|
|
418
|
+
stateModel: ViewTypeRegistry[N];
|
|
419
|
+
};
|
|
360
420
|
getViewType(typeName: string): ViewType;
|
|
421
|
+
/**
|
|
422
|
+
* The registered view and display types a snapshot names, from every `type`
|
|
423
|
+
* string anywhere in it — `heldForMissingPlugins` included. Over-collection
|
|
424
|
+
* is harmless: a name that resolves to neither is dropped here.
|
|
425
|
+
*/
|
|
426
|
+
private sessionElementTypes;
|
|
427
|
+
/**
|
|
428
|
+
* Every async code path that hands a snapshot to a synchronous session
|
|
429
|
+
* instantiation (`setSession`, `cast`) must await this first.
|
|
430
|
+
*/
|
|
431
|
+
preloadSessionTypes(sessionSnapshot: unknown): Promise<void>;
|
|
432
|
+
unloadedSessionTypes(sessionSnapshot: unknown): string[];
|
|
433
|
+
/**
|
|
434
|
+
* Without this, a snapshot naming an unloaded lazy type fails inside MST as
|
|
435
|
+
* a union mismatch that reads like a corrupt snapshot.
|
|
436
|
+
*/
|
|
437
|
+
assertSessionTypesLoaded(sessionSnapshot: unknown): void;
|
|
438
|
+
/**
|
|
439
|
+
* Aliases resolve here because a legacy session names the alias, and the
|
|
440
|
+
* model that remaps it cannot be consulted before it is loaded.
|
|
441
|
+
*/
|
|
442
|
+
resolveDisplayTypeRecord(name: string): DisplayType | undefined;
|
|
361
443
|
getAddTrackWorkflow(typeName: string): AddTrackWorkflowType;
|
|
362
444
|
getWidgetType(typeName: string): WidgetType;
|
|
363
445
|
getConnectionType(typeName: string): ConnectionType;
|
package/esm/PluginManager.js
CHANGED
|
@@ -3,6 +3,7 @@ import CorePlugin from './CorePlugin.js';
|
|
|
3
3
|
import PhasedScheduler from './PhasedScheduler.js';
|
|
4
4
|
import { getReExportRegistry } from './ReExports/registry.js';
|
|
5
5
|
import { ConfigurationSchema, isBareConfigurationSchemaType, } from './configuration/index.js';
|
|
6
|
+
import LazyStateModelElement from './pluggableElementTypes/LazyStateModelElement.js';
|
|
6
7
|
import createJexlInstance from './util/jexl.js';
|
|
7
8
|
import { expandLooseTrackConfig } from './util/tracks.js';
|
|
8
9
|
/**
|
|
@@ -24,6 +25,9 @@ export const pluggableElementTypeGroups = [
|
|
|
24
25
|
'internet account',
|
|
25
26
|
'add track workflow',
|
|
26
27
|
];
|
|
28
|
+
function isUnloadedLazyElement(element) {
|
|
29
|
+
return element instanceof LazyStateModelElement && !element.isStateModelLoaded;
|
|
30
|
+
}
|
|
27
31
|
/** internal class that holds the info for a certain element type */
|
|
28
32
|
class TypeRecord {
|
|
29
33
|
registeredTypes = {};
|
|
@@ -90,6 +94,17 @@ function nextAccumulator(name, accumulator, result) {
|
|
|
90
94
|
function logCallbackError(name, error) {
|
|
91
95
|
console.error(`error in a ${name} extension point callback`, error);
|
|
92
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Instantiate an application's bundled plugin list as `isCore` load records —
|
|
99
|
+
* what tells the plugin store these came with the bundle rather than being
|
|
100
|
+
* installed by the user, so `InstalledPluginsList` filters them out and the
|
|
101
|
+
* About widget lists them. Every product and every test harness builds its
|
|
102
|
+
* manager from one of these lists, and a harness that passed bare instances
|
|
103
|
+
* silently disagreed with the app it was testing.
|
|
104
|
+
*/
|
|
105
|
+
export function corePluginRecords(plugins) {
|
|
106
|
+
return plugins.map(P => ({ plugin: new P(), metadata: { isCore: true } }));
|
|
107
|
+
}
|
|
93
108
|
export default class PluginManager {
|
|
94
109
|
plugins = [];
|
|
95
110
|
jexl = createJexlInstance();
|
|
@@ -113,26 +128,41 @@ export default class PluginManager {
|
|
|
113
128
|
// singular component points are re-evaluated on every render, so the
|
|
114
129
|
// clobber warning is emitted once per point per app
|
|
115
130
|
warnedClobber = new Set();
|
|
131
|
+
#trackConfigHydrationCache = new WeakMap();
|
|
116
132
|
/**
|
|
117
|
-
*
|
|
118
|
-
* `
|
|
133
|
+
* The lazily-hydrated MST config node for one frozen track config, built by
|
|
134
|
+
* `build` on first ask and returned by identity after that.
|
|
135
|
+
* `configuration/configurationSchema.ts` is the only caller.
|
|
136
|
+
*
|
|
119
137
|
* `jbrowse.tracks` is `types.frozen` for large-tracklist performance, so a
|
|
120
|
-
* track config is a plain JS object until first referenced; hydrating it
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
* See ADR-031.
|
|
138
|
+
* track config is a plain JS object until first referenced; hydrating it into
|
|
139
|
+
* an MST node is deferred to that read. MST's custom-reference `getValue` has
|
|
140
|
+
* no memoization of its own — it reruns on every property access — so without
|
|
141
|
+
* this, every read of `track.configuration` would fabricate a fresh,
|
|
142
|
+
* non-identical node. Keyed by schemaType (each track type's config schema is
|
|
143
|
+
* rebuilt fresh per PluginManager instance, see addTrackType) then by the
|
|
144
|
+
* frozen object, so a hit can only ever come from this same instance and this
|
|
145
|
+
* same track type. See ADR-031.
|
|
129
146
|
*
|
|
130
|
-
*
|
|
147
|
+
* The node is never mutated: admin edits replace the frozen entry (new
|
|
131
148
|
* identity drops the WeakMap entry), and a non-admin's edits go to a private
|
|
132
149
|
* session working copy, not here (ADR-032). Both levels are `WeakMap`s so
|
|
133
|
-
* entries collect normally — no manual invalidation needed
|
|
150
|
+
* entries collect normally — no manual invalidation needed, which is why this
|
|
151
|
+
* is a memo and not a cache with a lifecycle to expose.
|
|
134
152
|
*/
|
|
135
|
-
|
|
153
|
+
hydratedTrackConfig(schemaType, frozen, build) {
|
|
154
|
+
let byFrozen = this.#trackConfigHydrationCache.get(schemaType);
|
|
155
|
+
if (!byFrozen) {
|
|
156
|
+
byFrozen = new WeakMap();
|
|
157
|
+
this.#trackConfigHydrationCache.set(schemaType, byFrozen);
|
|
158
|
+
}
|
|
159
|
+
let node = byFrozen.get(frozen);
|
|
160
|
+
if (!node) {
|
|
161
|
+
node = build();
|
|
162
|
+
byFrozen.set(frozen, node);
|
|
163
|
+
}
|
|
164
|
+
return node;
|
|
165
|
+
}
|
|
136
166
|
constructor(initialPlugins = []) {
|
|
137
167
|
// add the core plugin
|
|
138
168
|
this.addPlugin({
|
|
@@ -292,9 +322,28 @@ export default class PluginManager {
|
|
|
292
322
|
console.warn(`${groupName} ${newElement.name} already registered, cannot register it again`);
|
|
293
323
|
}
|
|
294
324
|
else {
|
|
295
|
-
|
|
325
|
+
const extend = () => this.evaluateExtensionPoint(
|
|
296
326
|
/** #extensionPoint Core-extendPluggableElement | sync | Mutate any pluggable element after it is created */
|
|
297
|
-
'Core-extendPluggableElement', newElement, { group: groupName })
|
|
327
|
+
'Core-extendPluggableElement', newElement, { group: groupName });
|
|
328
|
+
// A lazily registered state model is not there for a callback to
|
|
329
|
+
// extend yet, so the point fires when the loader resolves instead.
|
|
330
|
+
// agent-docs/reference/EAGER_BUNDLE.md
|
|
331
|
+
if (isUnloadedLazyElement(newElement)) {
|
|
332
|
+
newElement.onStateModelLoaded = () => {
|
|
333
|
+
const extended = extend();
|
|
334
|
+
if (extended !== newElement) {
|
|
335
|
+
typeRecord.add(newElement.name, extended);
|
|
336
|
+
if (extended instanceof LazyStateModelElement &&
|
|
337
|
+
extended.isStateModelLoaded) {
|
|
338
|
+
newElement.stateModel = extended.stateModel;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
typeRecord.add(newElement.name, newElement);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
typeRecord.add(newElement.name, extend());
|
|
346
|
+
}
|
|
298
347
|
}
|
|
299
348
|
});
|
|
300
349
|
return this;
|
|
@@ -326,16 +375,38 @@ export default class PluginManager {
|
|
|
326
375
|
getAdapterElements() {
|
|
327
376
|
return this.getElementTypesInGroup('adapter');
|
|
328
377
|
}
|
|
329
|
-
/**
|
|
378
|
+
/**
|
|
379
|
+
* get a MST type for the union of all specified pluggable MST types.
|
|
380
|
+
* Membership is late-bound, so a lazily registered state model joins when
|
|
381
|
+
* its loader resolves; a snapshot naming one cannot be cast until then.
|
|
382
|
+
*/
|
|
330
383
|
pluggableMstType(groupName, fieldName, fallback = types.maybe(types.null)) {
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
384
|
+
const record = this.getElementTypeRecord(groupName);
|
|
385
|
+
const fieldOf = (t) => isUnloadedLazyElement(t)
|
|
386
|
+
? undefined
|
|
387
|
+
: t[fieldName];
|
|
388
|
+
const anyMember = record.all().some(t => {
|
|
389
|
+
const field = fieldOf(t);
|
|
390
|
+
return ((isType(field) && isModelType(field)) ||
|
|
391
|
+
typeof t[`${fieldName}Loader`] === 'function');
|
|
392
|
+
});
|
|
393
|
+
if (!anyMember) {
|
|
336
394
|
return fallback;
|
|
337
395
|
}
|
|
338
|
-
|
|
396
|
+
const modelsOf = () => record
|
|
397
|
+
.all()
|
|
398
|
+
.map(t => fieldOf(t))
|
|
399
|
+
.filter(t => isType(t) && isModelType(t));
|
|
400
|
+
let members = modelsOf();
|
|
401
|
+
return types.union({
|
|
402
|
+
name: `pluggable(${groupName} ${fieldName})`,
|
|
403
|
+
members: () => {
|
|
404
|
+
if (members.length !== modelsOf().length) {
|
|
405
|
+
members = modelsOf();
|
|
406
|
+
}
|
|
407
|
+
return members;
|
|
408
|
+
},
|
|
409
|
+
});
|
|
339
410
|
}
|
|
340
411
|
/** get a MST type for the union of all specified pluggable config schemas */
|
|
341
412
|
pluggableConfigSchemaType(typeGroup, fieldName = 'configSchema') {
|
|
@@ -360,7 +431,28 @@ export default class PluginManager {
|
|
|
360
431
|
? types.snapshotProcessor(union, {
|
|
361
432
|
preProcessor: (snap) => expandLooseTrackConfig(snap, this),
|
|
362
433
|
})
|
|
363
|
-
:
|
|
434
|
+
: typeGroup === 'adapter'
|
|
435
|
+
? types.snapshotProcessor(union, {
|
|
436
|
+
preProcessor: (snap) => this.canonicalizeAdapterSnapshot(snap),
|
|
437
|
+
})
|
|
438
|
+
: union;
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* An adapter union dispatches on `type`, so a config still spelling an
|
|
442
|
+
* adapter's old name has to be rewritten to the name it registers under
|
|
443
|
+
* before the union sees it. Here rather than in each schema holding an
|
|
444
|
+
* adapter slot, so a track, an assembly's sequence and a connection all take
|
|
445
|
+
* it.
|
|
446
|
+
*/
|
|
447
|
+
canonicalizeAdapterSnapshot(snap) {
|
|
448
|
+
if (typeof snap === 'object' &&
|
|
449
|
+
snap !== null &&
|
|
450
|
+
'type' in snap &&
|
|
451
|
+
typeof snap.type === 'string') {
|
|
452
|
+
const canonical = this.canonicalAdapterTypeName(snap.type);
|
|
453
|
+
return canonical === snap.type ? snap : { ...snap, type: canonical };
|
|
454
|
+
}
|
|
455
|
+
return snap;
|
|
364
456
|
}
|
|
365
457
|
jbrequireCache = new Map();
|
|
366
458
|
// populated by PluginLoader once a runtime plugin is actually being loaded,
|
|
@@ -399,7 +491,18 @@ export default class PluginManager {
|
|
|
399
491
|
throw new TypeError('lib passed to jbrequire must be either a string or a function');
|
|
400
492
|
};
|
|
401
493
|
getAdapterType(typeName) {
|
|
402
|
-
return this.adapterTypes.get(typeName);
|
|
494
|
+
return this.adapterTypes.get(this.canonicalAdapterTypeName(typeName));
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* The name an adapter `type` registers under: itself, or the adapter that
|
|
498
|
+
* declares it in `aliases`. A name nothing answers to comes back as written,
|
|
499
|
+
* so the registered-names error still names what the config said.
|
|
500
|
+
*/
|
|
501
|
+
canonicalAdapterTypeName(typeName) {
|
|
502
|
+
return this.adapterTypes.has(typeName)
|
|
503
|
+
? typeName
|
|
504
|
+
: (this.adapterTypes.all().find(t => t.aliases?.includes(typeName))
|
|
505
|
+
?.name ?? typeName);
|
|
403
506
|
}
|
|
404
507
|
/**
|
|
405
508
|
* Whether an adapter type is registered, for a caller walking a config where
|
|
@@ -408,7 +511,7 @@ export default class PluginManager {
|
|
|
408
511
|
* claims to be an adapter and wrong when you are asking whether it is one.
|
|
409
512
|
*/
|
|
410
513
|
hasAdapterType(typeName) {
|
|
411
|
-
return this.adapterTypes.has(typeName);
|
|
514
|
+
return this.adapterTypes.has(this.canonicalAdapterTypeName(typeName));
|
|
412
515
|
}
|
|
413
516
|
getTextSearchAdapterType(typeName) {
|
|
414
517
|
return this.textSearchAdapterTypes.get(typeName);
|
|
@@ -422,6 +525,71 @@ export default class PluginManager {
|
|
|
422
525
|
getViewType(typeName) {
|
|
423
526
|
return this.viewTypes.get(typeName);
|
|
424
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* The registered view and display types a snapshot names, from every `type`
|
|
530
|
+
* string anywhere in it — `heldForMissingPlugins` included. Over-collection
|
|
531
|
+
* is harmless: a name that resolves to neither is dropped here.
|
|
532
|
+
*/
|
|
533
|
+
sessionElementTypes(sessionSnapshot) {
|
|
534
|
+
const names = new Set();
|
|
535
|
+
const walk = (node) => {
|
|
536
|
+
if (Array.isArray(node)) {
|
|
537
|
+
for (const item of node) {
|
|
538
|
+
walk(item);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
else if (node && typeof node === 'object') {
|
|
542
|
+
for (const [key, value] of Object.entries(node)) {
|
|
543
|
+
if (key === 'type' && typeof value === 'string') {
|
|
544
|
+
names.add(value);
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
walk(value);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
walk(sessionSnapshot);
|
|
553
|
+
return [...names].flatMap(name => {
|
|
554
|
+
const display = this.resolveDisplayTypeRecord(name);
|
|
555
|
+
return [
|
|
556
|
+
...(this.viewTypes.has(name) ? [this.getViewType(name)] : []),
|
|
557
|
+
...(display ? [display] : []),
|
|
558
|
+
];
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Every async code path that hands a snapshot to a synchronous session
|
|
563
|
+
* instantiation (`setSession`, `cast`) must await this first.
|
|
564
|
+
*/
|
|
565
|
+
async preloadSessionTypes(sessionSnapshot) {
|
|
566
|
+
await Promise.all(this.sessionElementTypes(sessionSnapshot).map(t => t.loadStateModel()));
|
|
567
|
+
}
|
|
568
|
+
unloadedSessionTypes(sessionSnapshot) {
|
|
569
|
+
return this.sessionElementTypes(sessionSnapshot)
|
|
570
|
+
.filter(t => !t.isStateModelLoaded)
|
|
571
|
+
.map(t => t.name);
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Without this, a snapshot naming an unloaded lazy type fails inside MST as
|
|
575
|
+
* a union mismatch that reads like a corrupt snapshot.
|
|
576
|
+
*/
|
|
577
|
+
assertSessionTypesLoaded(sessionSnapshot) {
|
|
578
|
+
const unloaded = this.unloadedSessionTypes(sessionSnapshot);
|
|
579
|
+
if (unloaded.length > 0) {
|
|
580
|
+
throw new Error(`session names lazily loaded types that are not loaded yet: ${unloaded.join(', ')}. Await pluginManager.preloadSessionTypes(snapshot) before setting the session`);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* Aliases resolve here because a legacy session names the alias, and the
|
|
585
|
+
* model that remaps it cannot be consulted before it is loaded.
|
|
586
|
+
*/
|
|
587
|
+
resolveDisplayTypeRecord(name) {
|
|
588
|
+
if (this.displayTypes.has(name)) {
|
|
589
|
+
return this.getDisplayType(name);
|
|
590
|
+
}
|
|
591
|
+
return this.getDisplayElements().find(d => d.aliases?.includes(name));
|
|
592
|
+
}
|
|
425
593
|
getAddTrackWorkflow(typeName) {
|
|
426
594
|
return this.addTrackWidgets.get(typeName);
|
|
427
595
|
}
|
|
@@ -7,4 +7,4 @@ export const BaseFeatureDetail = lazyMap({
|
|
|
7
7
|
BaseCard: lazy(() => import('../BaseFeatureWidget/BaseFeatureDetail/BaseCard.js')),
|
|
8
8
|
BaseAttributes: lazy(() => import('../BaseFeatureWidget/BaseFeatureDetail/BaseAttributes.js')),
|
|
9
9
|
BaseCoreDetails: lazy(() => import('../BaseFeatureWidget/BaseFeatureDetail/BaseCoreDetails.js')),
|
|
10
|
-
}
|
|
10
|
+
});
|
|
@@ -3,7 +3,7 @@ import { lazy } from 'react';
|
|
|
3
3
|
// export off it, so they're generated from a name list rather than written out
|
|
4
4
|
// 45 times. The static import specifier means webpack still emits a single
|
|
5
5
|
// x-data-grid chunk shared by all entries.
|
|
6
|
-
const
|
|
6
|
+
export const DATA_GRID_NAMES = [
|
|
7
7
|
'DataGrid',
|
|
8
8
|
'GridActionsCellItem',
|
|
9
9
|
'GridAddIcon',
|
|
@@ -51,7 +51,7 @@ const names = [
|
|
|
51
51
|
'GridViewHeadlineIcon',
|
|
52
52
|
'GridViewStreamIcon',
|
|
53
53
|
];
|
|
54
|
-
export const DataGridEntries = Object.fromEntries(
|
|
54
|
+
export const DataGridEntries = Object.fromEntries(DATA_GRID_NAMES.map(name => [
|
|
55
55
|
name,
|
|
56
56
|
lazy(() => import('@mui/x-data-grid').then(m => ({
|
|
57
57
|
default: m[name],
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Names a source barrel exports that its ABI file deliberately does not serve.
|
|
2
|
+
//
|
|
3
|
+
// The public*.ts split stopped a barrel removal from silently narrowing the ABI
|
|
4
|
+
// -- take a name out of ui/index.ts and publicUi.tsx no longer compiles. This
|
|
5
|
+
// closes the other direction, which the split opened: a name *added* to a barrel
|
|
6
|
+
// is not served until someone adds it here too, and an external plugin cannot
|
|
7
|
+
// see that. Its `import { X } from '@jbrowse/core/ui'` type-checks, because
|
|
8
|
+
// package.json's `./ui` resolves to the barrel, and reads undefined off
|
|
9
|
+
// JBrowseExports at runtime -- the same shape of failure a removal used to
|
|
10
|
+
// cause, just for new code instead of old.
|
|
11
|
+
//
|
|
12
|
+
// So publicSurface.test.ts requires barrel-minus-ABI to be exactly this list.
|
|
13
|
+
// Adding an export to a barrel then fails until the ABI question is answered,
|
|
14
|
+
// and either answer is one line: serve it from the public*.ts file, or name it
|
|
15
|
+
// here. Nothing about being on this list is wrong -- most of these are helpers
|
|
16
|
+
// for app code, session plumbing and in-tree hooks that a plugin has no use for.
|
|
17
|
+
export const BARREL_ONLY_NAMES = {
|
|
18
|
+
'@jbrowse/core/ui': [],
|
|
19
|
+
'@jbrowse/core/util/tracks': [],
|
|
20
|
+
'@jbrowse/core/util': [
|
|
21
|
+
'MAX_GLOB_REGIONS',
|
|
22
|
+
'adapterNeedsAddTrackComponent',
|
|
23
|
+
'assembleLocStrings',
|
|
24
|
+
'canonicalizeViewRefName',
|
|
25
|
+
'clampToContig',
|
|
26
|
+
'clampToListedContig',
|
|
27
|
+
'containerDisplaysAssembly',
|
|
28
|
+
'downloadPhase',
|
|
29
|
+
'finishAddTrack',
|
|
30
|
+
'formatBytes',
|
|
31
|
+
'getDisplayStr',
|
|
32
|
+
'getLocationUri',
|
|
33
|
+
'handleFetchError',
|
|
34
|
+
'indexedDBAvailable',
|
|
35
|
+
'installablePlugins',
|
|
36
|
+
'isSessionWithMultipleViews',
|
|
37
|
+
'isSessionWithPermanentPlugins',
|
|
38
|
+
'isWebWorker',
|
|
39
|
+
'localStorageAvailable',
|
|
40
|
+
'localStorageGetStringArray',
|
|
41
|
+
'matchRefNames',
|
|
42
|
+
'measuredFont',
|
|
43
|
+
'namesTemporaryAssembly',
|
|
44
|
+
'notifyFeatureDetailsMiss',
|
|
45
|
+
'notifyLocalStorageKey',
|
|
46
|
+
'parseBpString',
|
|
47
|
+
'parseRegionNames',
|
|
48
|
+
'resolveNamedRegions',
|
|
49
|
+
'resolveStorePluginRefs',
|
|
50
|
+
'resolveStoreRefs',
|
|
51
|
+
'resolveUri',
|
|
52
|
+
'sessionStorageAvailable',
|
|
53
|
+
'sessionStorageGetItem',
|
|
54
|
+
'sessionStorageRemoveItem',
|
|
55
|
+
'sessionStorageSetItem',
|
|
56
|
+
'statusSource',
|
|
57
|
+
'subscribeToLocalStorageKey',
|
|
58
|
+
'throttleStatusEmits',
|
|
59
|
+
'useCreateOnce',
|
|
60
|
+
'useFinalUnmount',
|
|
61
|
+
'withFeatureDetails',
|
|
62
|
+
],
|
|
63
|
+
};
|