@jbrowse/core 5.0.0-beta.1 → 5.0.0-beta.2
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 +42 -3
- package/esm/BaseFeatureWidget/SequenceFeatureDetails/test_data/NCDN.d.ts +2 -2
- package/esm/PluginLoader.d.ts +1 -0
- package/esm/PluginLoader.js +52 -8
- package/esm/PluginManager.d.ts +70 -17
- package/esm/PluginManager.js +151 -20
- package/esm/ReExports/modules.js +3 -53
- package/esm/ReExports/publicUtil.d.ts +1 -1
- package/esm/ReExports/publicUtil.js +1 -1
- package/esm/ReExports/sharedModules.d.ts +96 -0
- package/esm/ReExports/sharedModules.js +59 -0
- package/esm/ReExports/uiStub.d.ts +1 -0
- package/esm/ReExports/uiStub.js +13 -0
- package/esm/ReExports/workerModules.d.ts +2 -0
- package/esm/ReExports/workerModules.js +10 -0
- package/esm/configuration/configurationSchema.d.ts +5 -38
- package/esm/configuration/configurationSchema.js +53 -40
- package/esm/configuration/promotableDefaults.js +12 -6
- package/esm/configuration/promotableResolve.d.ts +1 -1
- package/esm/configuration/promotableResolve.js +1 -1
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.d.ts +12 -0
- package/esm/data_adapters/BaseAdapter/BaseFeatureDataAdapter.js +39 -0
- package/esm/data_adapters/BaseAdapter/featureDensity.d.ts +29 -0
- package/esm/data_adapters/BaseAdapter/featureDensity.js +17 -0
- package/esm/data_adapters/BaseAdapter/index.d.ts +1 -0
- 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 +1 -0
- package/esm/pluggableElementTypes/DisplayType.d.ts +9 -10
- package/esm/pluggableElementTypes/DisplayType.js +43 -8
- package/esm/pluggableElementTypes/ViewType.d.ts +25 -2
- package/esm/pluggableElementTypes/ViewType.js +75 -2
- package/esm/pluggableElementTypes/extendElementType.js +8 -3
- package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +41 -0
- package/esm/pluggableElementTypes/models/BaseDisplayModel.js +74 -1
- package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +21 -0
- package/esm/pluggableElementTypes/models/BaseTrackModel.js +37 -2
- package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +49 -0
- package/esm/pluggableElementTypes/models/BaseViewModel.js +39 -0
- package/esm/pluggableElementTypes/models/assertDisplayContract.d.ts +10 -7
- package/esm/pluggableElementTypes/models/assertDisplayContract.js +23 -30
- 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/CascadingMenu.js +30 -8
- package/esm/ui/LoadingOverlay.d.ts +14 -0
- package/esm/ui/LoadingOverlay.js +1 -1
- package/esm/ui/MenuTypes.d.ts +11 -2
- 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 +12 -6
- package/esm/ui/index.d.ts +1 -1
- package/esm/ui/index.js +1 -1
- package/esm/ui/launchViewMenu.js +7 -1
- package/esm/ui/legendMenuItem.d.ts +5 -5
- package/esm/ui/legendMenuItem.js +5 -5
- package/esm/ui/makeSizeMenu.js +1 -1
- package/esm/ui/menuItems.d.ts +1 -1
- package/esm/ui/menuItems.js +1 -1
- package/esm/ui/promotableMenuItems.js +8 -6
- package/esm/ui/promotablePinCoverage.js +2 -1
- package/esm/ui/toggleMenuItems.d.ts +1 -3
- 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/cacheBudgets.d.ts +22 -19
- package/esm/util/cacheBudgets.js +22 -19
- package/esm/util/createStopTokenRotation.d.ts +1 -0
- package/esm/util/createStopTokenRotation.js +7 -27
- package/esm/util/fetchContext.d.ts +2 -2
- package/esm/util/fetchContext.js +2 -2
- package/esm/util/fetchPhases.d.ts +9 -9
- package/esm/util/hooks.d.ts +8 -0
- package/esm/util/hooks.js +27 -0
- package/esm/util/index.d.ts +2 -3
- package/esm/util/index.js +2 -3
- package/esm/util/installFetch.d.ts +49 -23
- package/esm/util/installFetch.js +49 -21
- package/esm/util/installInitAutorun.d.ts +8 -8
- package/esm/util/installInitAutorun.js +15 -15
- 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/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/rxjs.d.ts +16 -0
- package/esm/util/rxjs.js +49 -0
- package/esm/util/tabix.d.ts +10 -4
- package/esm/util/tabix.js +11 -5
- package/esm/util/tracks.d.ts +48 -0
- package/esm/util/tracks.js +192 -66
- package/esm/util/types/index.d.ts +48 -5
- 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/viewStatus.d.ts +23 -0
- package/esm/util/viewStatus.js +17 -0
- package/esm/util/whenViewSettled.d.ts +17 -4
- package/esm/util/whenViewSettled.js +19 -6
- package/esm/util/withLaunchInput.d.ts +123 -0
- package/esm/util/withLaunchInput.js +228 -0
- package/package.json +12 -9
- package/esm/util/applyInitSettings.d.ts +0 -79
- package/esm/util/applyInitSettings.js +0 -91
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Wait until a view has either initialized
|
|
2
|
+
* Wait until a view has either initialized — launch blob consumed and all — or
|
|
3
|
+
* failed, and report which.
|
|
3
4
|
*
|
|
4
5
|
* `initialized` folds in a view's assemblies, so an assembly that fails to load
|
|
5
6
|
* leaves it false **forever**. A bare `when(() => view.initialized)` therefore
|
|
@@ -9,6 +10,15 @@
|
|
|
9
10
|
* export hung behind its dialog's spinner, and a launched breakpoint split view
|
|
10
11
|
* that opened but was never navigated or zoomed.
|
|
11
12
|
*
|
|
13
|
+
* `pendingLaunch` is the other half, and it matters because `initialized` can
|
|
14
|
+
* go true MID-launch: LGV's flips the moment displayedRegions land, while the
|
|
15
|
+
* same apply pass still has tracks to attach — so a caller acting there reads a
|
|
16
|
+
* positioned view with its tracks missing (an SVG export saves it that way).
|
|
17
|
+
* A launch failure cannot hang this: the state machine either clears the blob
|
|
18
|
+
* (materialized, reported as a snackbar) or sets the view's `error`
|
|
19
|
+
* (installInitAutorun's failure policy). A view with no launch machinery has no
|
|
20
|
+
* `pendingLaunch` and the term is vacuously satisfied.
|
|
21
|
+
*
|
|
12
22
|
* Every view exposes a resolved `error` beside `initialized`, so waiting on the
|
|
13
23
|
* pair turns the hang into something reportable. What to report is the caller's,
|
|
14
24
|
* because the vocabularies genuinely differ — an export says "cannot export"
|
|
@@ -16,12 +26,15 @@
|
|
|
16
26
|
* says the launch failed — which is why this returns the answer instead of
|
|
17
27
|
* throwing one wording at both.
|
|
18
28
|
*
|
|
19
|
-
* No time bound, deliberately: `initialized || error` is a
|
|
20
|
-
* slow-but-healthy remote assembly is waited out rather than
|
|
29
|
+
* No time bound, deliberately: `(initialized && launch consumed) || error` is a
|
|
30
|
+
* terminal set, so a slow-but-healthy remote assembly is waited out rather than
|
|
31
|
+
* guessed at.
|
|
21
32
|
*
|
|
22
|
-
* @returns true if the view initialized, false if it
|
|
33
|
+
* @returns true if the view initialized (and consumed any launch), false if it
|
|
34
|
+
* settled on an error
|
|
23
35
|
*/
|
|
24
36
|
export declare function whenViewSettled(view: {
|
|
25
37
|
initialized: boolean;
|
|
26
38
|
error: unknown;
|
|
39
|
+
pendingLaunch?: unknown;
|
|
27
40
|
}): Promise<boolean>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { when } from 'mobx';
|
|
2
2
|
/**
|
|
3
|
-
* Wait until a view has either initialized
|
|
3
|
+
* Wait until a view has either initialized — launch blob consumed and all — or
|
|
4
|
+
* failed, and report which.
|
|
4
5
|
*
|
|
5
6
|
* `initialized` folds in a view's assemblies, so an assembly that fails to load
|
|
6
7
|
* leaves it false **forever**. A bare `when(() => view.initialized)` therefore
|
|
@@ -10,6 +11,15 @@ import { when } from 'mobx';
|
|
|
10
11
|
* export hung behind its dialog's spinner, and a launched breakpoint split view
|
|
11
12
|
* that opened but was never navigated or zoomed.
|
|
12
13
|
*
|
|
14
|
+
* `pendingLaunch` is the other half, and it matters because `initialized` can
|
|
15
|
+
* go true MID-launch: LGV's flips the moment displayedRegions land, while the
|
|
16
|
+
* same apply pass still has tracks to attach — so a caller acting there reads a
|
|
17
|
+
* positioned view with its tracks missing (an SVG export saves it that way).
|
|
18
|
+
* A launch failure cannot hang this: the state machine either clears the blob
|
|
19
|
+
* (materialized, reported as a snackbar) or sets the view's `error`
|
|
20
|
+
* (installInitAutorun's failure policy). A view with no launch machinery has no
|
|
21
|
+
* `pendingLaunch` and the term is vacuously satisfied.
|
|
22
|
+
*
|
|
13
23
|
* Every view exposes a resolved `error` beside `initialized`, so waiting on the
|
|
14
24
|
* pair turns the hang into something reportable. What to report is the caller's,
|
|
15
25
|
* because the vocabularies genuinely differ — an export says "cannot export"
|
|
@@ -17,12 +27,15 @@ import { when } from 'mobx';
|
|
|
17
27
|
* says the launch failed — which is why this returns the answer instead of
|
|
18
28
|
* throwing one wording at both.
|
|
19
29
|
*
|
|
20
|
-
* No time bound, deliberately: `initialized || error` is a
|
|
21
|
-
* slow-but-healthy remote assembly is waited out rather than
|
|
30
|
+
* No time bound, deliberately: `(initialized && launch consumed) || error` is a
|
|
31
|
+
* terminal set, so a slow-but-healthy remote assembly is waited out rather than
|
|
32
|
+
* guessed at.
|
|
22
33
|
*
|
|
23
|
-
* @returns true if the view initialized, false if it
|
|
34
|
+
* @returns true if the view initialized (and consumed any launch), false if it
|
|
35
|
+
* settled on an error
|
|
24
36
|
*/
|
|
25
37
|
export async function whenViewSettled(view) {
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
const ready = () => view.initialized && view.pendingLaunch === undefined;
|
|
39
|
+
await when(() => ready() || !!view.error);
|
|
40
|
+
return ready();
|
|
28
41
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export { legacyInitMessage, unknownKeysMessage } from './unknownSnapshotKeys.ts';
|
|
2
|
+
import type { IAnyModelType, IModelType, SnapshotIn } from '@jbrowse/mobx-state-tree';
|
|
3
|
+
/**
|
|
4
|
+
* How a launch key's value is told apart from the state property of the same
|
|
5
|
+
* name. A key whose name collides with nothing is `launch`; the rest name the
|
|
6
|
+
* discriminator that splits one authored array into the recipe entries the
|
|
7
|
+
* launcher resolves and the built snapshots MST restores.
|
|
8
|
+
*
|
|
9
|
+
* `replay` is the one that is not remapped at all: the value lands on its
|
|
10
|
+
* property, and a copy rides in the blob so the launcher can run the ordered
|
|
11
|
+
* imperative step the property write alone does not produce.
|
|
12
|
+
*/
|
|
13
|
+
export type LaunchKeyKind = 'launch' | 'trackEntries' | 'rows' | 'highlightEntries' | 'replay';
|
|
14
|
+
export interface LaunchKeySpec {
|
|
15
|
+
kind: LaunchKeyKind;
|
|
16
|
+
}
|
|
17
|
+
export interface LaunchKeyRegistration<Commands, PassThrough extends string = never> {
|
|
18
|
+
keys: Record<string, LaunchKeySpec>;
|
|
19
|
+
passThrough: readonly PassThrough[];
|
|
20
|
+
/** never assigned; it carries `Commands` to `withLaunchInput`'s return type */
|
|
21
|
+
commands?: Commands;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The launch keys a view captured, plus what it has to report.
|
|
25
|
+
*
|
|
26
|
+
* `Commands` is not made partial: hand-authored JSON is what fills this, so a
|
|
27
|
+
* key the interface marks required is not a guarantee here either way, and the
|
|
28
|
+
* launcher already guards the ones it cannot proceed without.
|
|
29
|
+
*/
|
|
30
|
+
export type LaunchInput<Commands> = Commands & {
|
|
31
|
+
unknown?: Record<string, unknown>;
|
|
32
|
+
malformed?: Record<string, unknown>;
|
|
33
|
+
legacyInit?: boolean;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The blob when it still holds something to apply, else undefined. A view's
|
|
37
|
+
* gates ask this rather than the raw property: a snapshot whose only launch
|
|
38
|
+
* content was a typo has nothing to launch, and a view that thinks otherwise
|
|
39
|
+
* waits on an assembly nobody named and never leaves the spinner.
|
|
40
|
+
*
|
|
41
|
+
* Returns the blob itself, never a copy — the launch autorun clears by
|
|
42
|
+
* identity, and a fresh object per read strands the init it just applied.
|
|
43
|
+
*/
|
|
44
|
+
export declare function pendingLaunch<C>(launch: LaunchInput<C> | undefined): LaunchInput<C> | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* A view's snapshot type, widened to the authored shape: every launch key is
|
|
47
|
+
* accepted beside the declared properties, and a key that is both takes either
|
|
48
|
+
* meaning. Excess-property checking then makes a misspelled key an error at
|
|
49
|
+
* every literal site — a `defaultSession` view, an `addView` call, a
|
|
50
|
+
* `createViewState` spec.
|
|
51
|
+
*/
|
|
52
|
+
export type LaunchSnapshotIn<M extends IAnyModelType, Commands, PassThrough extends string = never> = Omit<SnapshotIn<M>, keyof Commands> & {
|
|
53
|
+
[K in keyof Commands]?: K extends keyof SnapshotIn<M> ? Commands[K] | SnapshotIn<M>[K] : Commands[K];
|
|
54
|
+
} & {
|
|
55
|
+
[K in PassThrough]?: unknown;
|
|
56
|
+
} & {
|
|
57
|
+
/**
|
|
58
|
+
* @deprecated v4's nesting. Write every setting directly on the view object;
|
|
59
|
+
* this is unwrapped on the way in and warns.
|
|
60
|
+
*/
|
|
61
|
+
init?: Commands;
|
|
62
|
+
};
|
|
63
|
+
type ReservedKey = 'id' | 'type' | 'launch';
|
|
64
|
+
/**
|
|
65
|
+
* What a view can be launched with, derived: the keys its launcher interprets
|
|
66
|
+
* (`Commands`) plus every declared property of its state model, optional, in
|
|
67
|
+
* the property's own snapshot type. Nothing is restated, so a property is
|
|
68
|
+
* authorable — and TYPED — from the line that declares it.
|
|
69
|
+
*
|
|
70
|
+
* ```ts
|
|
71
|
+
* export type LinearSyntenyViewInit = ViewInit<
|
|
72
|
+
* LinearSyntenyViewStateModel,
|
|
73
|
+
* LinearSyntenyViewCommands
|
|
74
|
+
* >
|
|
75
|
+
* ```
|
|
76
|
+
*
|
|
77
|
+
* The twin of `LaunchSnapshotIn` above, from the other end: that one widens a
|
|
78
|
+
* snapshot type for a literal MST site, this one is what a caller BUILDING a
|
|
79
|
+
* spec annotates, so its commands stay required and its properties optional.
|
|
80
|
+
*/
|
|
81
|
+
export type ViewInit<M extends IAnyModelType, Commands> = Commands & Partial<Omit<SnapshotIn<M>, keyof Commands | ReservedKey>>;
|
|
82
|
+
export type LaunchInputModel<M extends IAnyModelType, Commands, PassThrough extends string = never> = M extends IModelType<infer P, infer O, any, infer S> ? IModelType<P, O, LaunchSnapshotIn<M, Commands, PassThrough>, S> : never;
|
|
83
|
+
/**
|
|
84
|
+
* Declare one view's launch keys. The argument is
|
|
85
|
+
* `Record<keyof Commands, LaunchKeySpec>`, so a command the view interprets and
|
|
86
|
+
* nobody registered is a compile error rather than a key that partitions as a
|
|
87
|
+
* typo and warns.
|
|
88
|
+
*
|
|
89
|
+
* `passThrough` names keys that are neither a launch key nor a declared
|
|
90
|
+
* property and still belong on the snapshot — a legacy spelling the view's own
|
|
91
|
+
* `preProcessSnapshot` converts.
|
|
92
|
+
*/
|
|
93
|
+
export declare function defineLaunchKeys<Commands>(): <const P extends readonly string[] = readonly never[]>(keys: Record<keyof Commands, LaunchKeySpec>, { passThrough }?: {
|
|
94
|
+
passThrough?: P;
|
|
95
|
+
}) => LaunchKeyRegistration<Commands, P[number]>;
|
|
96
|
+
/**
|
|
97
|
+
* Accept a view's settings written directly on the view object, and move the
|
|
98
|
+
* ones a launcher has to resolve into the internal `launch` property.
|
|
99
|
+
*
|
|
100
|
+
* The partition is a `preProcessSnapshot` and is PURE. A session's view type is
|
|
101
|
+
* a `types.union`, so MST runs every member's preprocessor against every
|
|
102
|
+
* candidate snapshot while deciding which one matches, and runs it about twice
|
|
103
|
+
* more per instantiation; a warning from in here fires against snapshots that
|
|
104
|
+
* are about to be rejected. `afterAttach` — reached only by a snapshot that won
|
|
105
|
+
* — reports what the partition captured.
|
|
106
|
+
*
|
|
107
|
+
* ORDER: MST runs preprocessors in the reverse of the order they were added, so
|
|
108
|
+
* this belongs on the chain BEFORE a view's own legacy-key preprocessor, where
|
|
109
|
+
* it partitions the snapshot MST finally consumes rather than a key that remap
|
|
110
|
+
* is about to convert.
|
|
111
|
+
*
|
|
112
|
+
* The widening cast is the LAST link that may change the creation type: it
|
|
113
|
+
* replaces `CustomC`, so a `.props()` added after it is invisible to
|
|
114
|
+
* `SnapshotIn`. Further `preProcessSnapshot`/`postProcessSnapshot` links are
|
|
115
|
+
* fine — both carry `CustomC` through.
|
|
116
|
+
*
|
|
117
|
+
* Not `types.snapshotProcessor`, which carries the same widened input and stops
|
|
118
|
+
* being a `ModelType`. `PluginManager.pluggableMstType` filters union members on
|
|
119
|
+
* `isModelType`, so a wrapped view is dropped from the session's view union
|
|
120
|
+
* without a word, and `ViewType.stateModel` and every `.properties`
|
|
121
|
+
* introspection site break with it.
|
|
122
|
+
*/
|
|
123
|
+
export declare function withLaunchInput<M extends IAnyModelType, Commands, PassThrough extends string>(model: M, registration: LaunchKeyRegistration<Commands, PassThrough>): LaunchInputModel<M, Commands, PassThrough>;
|
|
@@ -0,0 +1,228 @@
|
|
|
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
|
+
function isObject(value) {
|
|
45
|
+
return !!value && typeof value === 'object';
|
|
46
|
+
}
|
|
47
|
+
// Each per-entry kind says only which entries are an authored recipe. A recipe
|
|
48
|
+
// goes to the blob for the launcher to resolve; everything else is a built
|
|
49
|
+
// snapshot and stays on the property, so a mixed array splits rather than
|
|
50
|
+
// picking one meaning for the whole thing.
|
|
51
|
+
function isRecipeEntry(kind, entry) {
|
|
52
|
+
switch (kind) {
|
|
53
|
+
case 'trackEntries':
|
|
54
|
+
// a built track snapshot cannot carry `trackId` — BaseTrackModel does not
|
|
55
|
+
// declare it. `type` does not discriminate: a spec writes display types
|
|
56
|
+
// inline
|
|
57
|
+
return (typeof entry === 'string' || (isObject(entry) && 'trackId' in entry));
|
|
58
|
+
case 'highlightEntries':
|
|
59
|
+
// a string needs coerceHighlight and the assembly manager, neither of
|
|
60
|
+
// which a pure preprocessor can reach; an object is the persisted shape
|
|
61
|
+
return typeof entry === 'string';
|
|
62
|
+
case 'rows':
|
|
63
|
+
// a built row is a view snapshot, and every view's `type` is a required
|
|
64
|
+
// literal
|
|
65
|
+
return !(isObject(entry) && 'type' in entry);
|
|
66
|
+
default:
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function splitEntries(kind, value) {
|
|
71
|
+
const entries = Array.isArray(value) ? value : [value];
|
|
72
|
+
const recipes = entries.filter(e => isRecipeEntry(kind, e));
|
|
73
|
+
const built = entries.filter(e => !isRecipeEntry(kind, e));
|
|
74
|
+
return {
|
|
75
|
+
launch: recipes.length
|
|
76
|
+
? Array.isArray(value)
|
|
77
|
+
? recipes
|
|
78
|
+
: value
|
|
79
|
+
: undefined,
|
|
80
|
+
state: built.length ? (Array.isArray(value) ? built : value) : undefined,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function classify(snap, { keys, passThrough }, known, out) {
|
|
84
|
+
for (const [key, value] of Object.entries(snap)) {
|
|
85
|
+
const spec = keys[key];
|
|
86
|
+
if (IDENTITY.has(key)) {
|
|
87
|
+
out.state[key] = value;
|
|
88
|
+
}
|
|
89
|
+
else if (spec?.kind === 'launch') {
|
|
90
|
+
out.launch[key] = value;
|
|
91
|
+
}
|
|
92
|
+
else if (spec?.kind === 'replay') {
|
|
93
|
+
out.state[key] = value;
|
|
94
|
+
out.launch[key] = value;
|
|
95
|
+
}
|
|
96
|
+
else if (spec) {
|
|
97
|
+
const { launch, state } = splitEntries(spec.kind, value);
|
|
98
|
+
if (spec.kind === 'rows' && launch !== undefined && state !== undefined) {
|
|
99
|
+
// A row list indexes against `levels` and `tracks[i]`, so lifting half
|
|
100
|
+
// of it renumbers the other half. Nothing here can throw — a pure
|
|
101
|
+
// preprocessor runs against snapshots the union is about to reject — so
|
|
102
|
+
// the whole list goes to the bucket afterAttach reports and the view
|
|
103
|
+
// comes up on its import form rather than on a silently misaligned
|
|
104
|
+
// stack.
|
|
105
|
+
out.malformed[key] = value;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
if (launch !== undefined) {
|
|
109
|
+
out.launch[key] = launch;
|
|
110
|
+
}
|
|
111
|
+
if (state !== undefined) {
|
|
112
|
+
out.state[key] = state;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (known.has(key) || passThrough.includes(key)) {
|
|
117
|
+
out.state[key] = value;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
out.unknown[key] = value;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// BreakpointSplitView's v4 `init` was a bare array of panels rather than an
|
|
125
|
+
// object of settings. A positional list can only be the view's row list, and a
|
|
126
|
+
// view declares at most one, so it is read as that key rather than classified
|
|
127
|
+
// per index — which would name "0" and "1" as unknown keys.
|
|
128
|
+
function legacyInitSnapshot(init, { keys }) {
|
|
129
|
+
const rows = Object.entries(keys).find(([, spec]) => spec.kind === 'rows')?.[0];
|
|
130
|
+
return Array.isArray(init) && rows ? { [rows]: init } : init;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Accept a view's settings written directly on the view object, and move the
|
|
134
|
+
* ones a launcher has to resolve into the internal `launch` property.
|
|
135
|
+
*
|
|
136
|
+
* The partition is a `preProcessSnapshot` and is PURE. A session's view type is
|
|
137
|
+
* a `types.union`, so MST runs every member's preprocessor against every
|
|
138
|
+
* candidate snapshot while deciding which one matches, and runs it about twice
|
|
139
|
+
* more per instantiation; a warning from in here fires against snapshots that
|
|
140
|
+
* are about to be rejected. `afterAttach` — reached only by a snapshot that won
|
|
141
|
+
* — reports what the partition captured.
|
|
142
|
+
*
|
|
143
|
+
* ORDER: MST runs preprocessors in the reverse of the order they were added, so
|
|
144
|
+
* this belongs on the chain BEFORE a view's own legacy-key preprocessor, where
|
|
145
|
+
* it partitions the snapshot MST finally consumes rather than a key that remap
|
|
146
|
+
* is about to convert.
|
|
147
|
+
*
|
|
148
|
+
* The widening cast is the LAST link that may change the creation type: it
|
|
149
|
+
* replaces `CustomC`, so a `.props()` added after it is invisible to
|
|
150
|
+
* `SnapshotIn`. Further `preProcessSnapshot`/`postProcessSnapshot` links are
|
|
151
|
+
* fine — both carry `CustomC` through.
|
|
152
|
+
*
|
|
153
|
+
* Not `types.snapshotProcessor`, which carries the same widened input and stops
|
|
154
|
+
* being a `ModelType`. `PluginManager.pluggableMstType` filters union members on
|
|
155
|
+
* `isModelType`, so a wrapped view is dropped from the session's view union
|
|
156
|
+
* without a word, and `ViewType.stateModel` and every `.properties`
|
|
157
|
+
* introspection site break with it.
|
|
158
|
+
*/
|
|
159
|
+
export function withLaunchInput(model, registration) {
|
|
160
|
+
const known = new Set(Object.keys(model.properties));
|
|
161
|
+
const partitioned = model
|
|
162
|
+
.preProcessSnapshot((snap) => {
|
|
163
|
+
if (!isObject(snap)) {
|
|
164
|
+
return snap;
|
|
165
|
+
}
|
|
166
|
+
const { init, ...rest } = snap;
|
|
167
|
+
const out = {
|
|
168
|
+
state: {},
|
|
169
|
+
launch: {},
|
|
170
|
+
unknown: {},
|
|
171
|
+
malformed: {},
|
|
172
|
+
};
|
|
173
|
+
if (isObject(init)) {
|
|
174
|
+
// v4's nesting, unwrapped rather than refused: a nested key sorts the
|
|
175
|
+
// same three ways a flat one does, so honoring it costs one more pass
|
|
176
|
+
// and a deprecation warning, where dropping it opens an admin's
|
|
177
|
+
// `defaultSession` on its defaults. First, so a snapshot spelling one
|
|
178
|
+
// key both ways resolves to the flat one the docs teach.
|
|
179
|
+
classify(legacyInitSnapshot(init, registration), registration, known, out);
|
|
180
|
+
out.launch.legacyInit = true;
|
|
181
|
+
}
|
|
182
|
+
classify(rest, registration, known, out);
|
|
183
|
+
if (Object.keys(out.unknown).length) {
|
|
184
|
+
out.launch.unknown = out.unknown;
|
|
185
|
+
}
|
|
186
|
+
if (Object.keys(out.malformed).length) {
|
|
187
|
+
out.launch.malformed = out.malformed;
|
|
188
|
+
}
|
|
189
|
+
const persisted = out.state[LAUNCH];
|
|
190
|
+
return Object.keys(out.launch).length
|
|
191
|
+
? {
|
|
192
|
+
...out.state,
|
|
193
|
+
[LAUNCH]: {
|
|
194
|
+
...(isObject(persisted) ? persisted : {}),
|
|
195
|
+
...out.launch,
|
|
196
|
+
},
|
|
197
|
+
}
|
|
198
|
+
: out.state;
|
|
199
|
+
})
|
|
200
|
+
.actions(self => ({
|
|
201
|
+
afterAttach() {
|
|
202
|
+
const { launch } = self;
|
|
203
|
+
if (launch?.legacyInit) {
|
|
204
|
+
reportLegacyInit(self);
|
|
205
|
+
}
|
|
206
|
+
reportUnknownKeys(self, Object.keys(launch?.unknown ?? {}));
|
|
207
|
+
reportMalformedRows(self, Object.keys(launch?.malformed ?? {}));
|
|
208
|
+
},
|
|
209
|
+
}))
|
|
210
|
+
// `legacyInit` names the SPELLING of the snapshot this view was opened from,
|
|
211
|
+
// and a saved one does not use it — so persisting the flag makes every later
|
|
212
|
+
// restore report nesting the snapshot it is reading does not contain,
|
|
213
|
+
// forever, since nothing clears it (`pendingLaunch` excludes the report
|
|
214
|
+
// keys, so the launch autorun never runs). `unknown` and `malformed` stay:
|
|
215
|
+
// those name content that was DISCARDED, which is still true of the saved
|
|
216
|
+
// snapshot, and the blob is the only record of it.
|
|
217
|
+
.postProcessSnapshot((snap) => {
|
|
218
|
+
const launch = snap[LAUNCH];
|
|
219
|
+
if (!isObject(launch) || !launch.legacyInit) {
|
|
220
|
+
return snap;
|
|
221
|
+
}
|
|
222
|
+
const { legacyInit, ...kept } = launch;
|
|
223
|
+
return Object.keys(kept).length
|
|
224
|
+
? { ...snap, [LAUNCH]: kept }
|
|
225
|
+
: Object.fromEntries(Object.entries(snap).filter(([key]) => key !== LAUNCH));
|
|
226
|
+
});
|
|
227
|
+
return partitioned;
|
|
228
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/core",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.2",
|
|
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",
|
|
@@ -140,14 +142,12 @@
|
|
|
140
142
|
"./util/Base1DUtils": "./esm/util/Base1DUtils.js",
|
|
141
143
|
"./util/Base1DViewModel": "./esm/util/Base1DViewModel.js",
|
|
142
144
|
"./util/FileSaver": "./esm/util/FileSaver/index.js",
|
|
143
|
-
"./util/QuickLRU": "./esm/util/QuickLRU/index.js",
|
|
144
145
|
"./util/SvgCanvas": "./esm/util/SvgCanvas.js",
|
|
145
146
|
"./util/TimeTraveller": "./esm/util/TimeTraveller.js",
|
|
146
147
|
"./util/aborting": "./esm/util/aborting.js",
|
|
147
148
|
"./util/adapterMetadata": "./esm/util/adapterMetadata.js",
|
|
148
149
|
"./util/addRelativeUris": "./esm/util/addRelativeUris.js",
|
|
149
150
|
"./util/analytics": "./esm/util/analytics.js",
|
|
150
|
-
"./util/applyInitSettings": "./esm/util/applyInitSettings.js",
|
|
151
151
|
"./util/assemblyConfigUtils": "./esm/util/assemblyConfigUtils.js",
|
|
152
152
|
"./util/bandHeight": "./esm/util/bandHeight.js",
|
|
153
153
|
"./util/bandLayout": "./esm/util/bandLayout.js",
|
|
@@ -194,7 +194,9 @@
|
|
|
194
194
|
"./util/layouts": "./esm/util/layouts/index.js",
|
|
195
195
|
"./util/layouts/GranularRectLayout": "./esm/util/layouts/GranularRectLayout.js",
|
|
196
196
|
"./util/layouts/placeRect": "./esm/util/layouts/placeRect.js",
|
|
197
|
+
"./util/lazyAfterAttach": "./esm/util/lazyAfterAttach.js",
|
|
197
198
|
"./util/leadingEdgeAutorun": "./esm/util/leadingEdgeAutorun.js",
|
|
199
|
+
"./util/legendCandidates": "./esm/util/legendCandidates.js",
|
|
198
200
|
"./util/librpc": "./esm/util/librpc.js",
|
|
199
201
|
"./util/localStorage": "./esm/util/localStorage.js",
|
|
200
202
|
"./util/makeAssembly": "./esm/util/makeAssembly.js",
|
|
@@ -235,7 +237,8 @@
|
|
|
235
237
|
"./util/viewStatus": "./esm/util/viewStatus.js",
|
|
236
238
|
"./util/virtualRange": "./esm/util/virtualRange.js",
|
|
237
239
|
"./util/wheelZoom": "./esm/util/wheelZoom.js",
|
|
238
|
-
"./util/whenViewSettled": "./esm/util/whenViewSettled.js"
|
|
240
|
+
"./util/whenViewSettled": "./esm/util/whenViewSettled.js",
|
|
241
|
+
"./util/withLaunchInput": "./esm/util/withLaunchInput.js"
|
|
239
242
|
},
|
|
240
243
|
"files": [
|
|
241
244
|
"esm"
|
|
@@ -253,9 +256,9 @@
|
|
|
253
256
|
"@jbrowse/mobx-state-tree": "^6.5.1",
|
|
254
257
|
"@jbrowse/quick-lru": "^7.3.5",
|
|
255
258
|
"@leeoniya/ufuzzy": "^1.0.19",
|
|
256
|
-
"@mui/icons-material": "^9.
|
|
257
|
-
"@mui/material": "^9.
|
|
258
|
-
"@mui/system": "^9.
|
|
259
|
+
"@mui/icons-material": "^9.4.0",
|
|
260
|
+
"@mui/material": "^9.4.0",
|
|
261
|
+
"@mui/system": "^9.4.0",
|
|
259
262
|
"@mui/x-data-grid": "^9.12.0",
|
|
260
263
|
"canvas-sequencer-ts": "^3.1.3",
|
|
261
264
|
"compare-versions": "^6.1.1",
|
|
@@ -267,8 +270,8 @@
|
|
|
267
270
|
"pako-esm2": "^2.0.2",
|
|
268
271
|
"rxjs": "^7.8.2",
|
|
269
272
|
"source-map-js": "^1.2.1",
|
|
270
|
-
"@jbrowse/add-track-core": "^5.0.0-beta.
|
|
271
|
-
"@jbrowse/render-core": "^5.0.0-beta.
|
|
273
|
+
"@jbrowse/add-track-core": "^5.0.0-beta.2",
|
|
274
|
+
"@jbrowse/render-core": "^5.0.0-beta.2"
|
|
272
275
|
},
|
|
273
276
|
"peerDependencies": {
|
|
274
277
|
"react": ">=19.0.0",
|
|
@@ -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;
|