@jbrowse/core 5.0.0-beta.10 → 5.0.0-beta.13

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 (145) hide show
  1. package/README.md +210 -80
  2. package/esm/BaseFeatureWidget/BaseFeatureDetail/ArrayValue.js +0 -2
  3. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.d.ts +3 -0
  4. package/esm/BaseFeatureWidget/BaseFeatureDetail/Attributes.js +14 -1
  5. package/esm/BaseFeatureWidget/BaseFeatureDetail/BasicValue.js +22 -6
  6. package/esm/BaseFeatureWidget/BaseFeatureDetail/jexlFilterActions.js +3 -4
  7. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeatureDetails.d.ts +2 -0
  8. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeatureDetails.js +5 -5
  9. package/esm/BaseFeatureWidget/SequenceFeatureDetails/SequenceFeaturePanel.js +1 -1
  10. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/FeatureSequenceDialog.d.ts +3 -1
  11. package/esm/BaseFeatureWidget/SequenceFeatureDetails/dialogs/FeatureSequenceDialog.js +2 -2
  12. package/esm/BaseFeatureWidget/SequenceFeatureDetails/featureTypeUtil.d.ts +2 -1
  13. package/esm/BaseFeatureWidget/SequenceFeatureDetails/featureTypeUtil.js +7 -14
  14. package/esm/BaseFeatureWidget/SequenceFeatureDetails/seqtypes/CDNASequence.js +3 -3
  15. package/esm/BaseFeatureWidget/SequenceFeatureDetails/useSequenceData.js +8 -5
  16. package/esm/BaseFeatureWidget/stateModelFactory.d.ts +7 -0
  17. package/esm/BaseFeatureWidget/stateModelFactory.js +11 -0
  18. package/esm/BaseFeatureWidget/types.d.ts +2 -0
  19. package/esm/CorePlugin.js +32 -1
  20. package/esm/PluginManager.d.ts +6 -3
  21. package/esm/PluginManager.js +6 -3
  22. package/esm/ReExports/coreModules.generated.js +291 -283
  23. package/esm/ReExports/coreWorkerModules.generated.js +288 -281
  24. package/esm/ReExports/list.js +10 -2
  25. package/esm/TextSearch/TextSearchManager.d.ts +3 -3
  26. package/esm/TextSearch/TextSearchManager.js +6 -13
  27. package/esm/configuration/configurationSchema.d.ts +33 -95
  28. package/esm/configuration/configurationSchema.js +50 -218
  29. package/esm/configuration/configurationSlot.d.ts +18 -64
  30. package/esm/configuration/configurationSlot.js +31 -97
  31. package/esm/configuration/formatDetailsConfigSchema.js +2 -0
  32. package/esm/configuration/getConf.d.ts +7 -36
  33. package/esm/configuration/getConf.js +7 -37
  34. package/esm/configuration/index.d.ts +5 -2
  35. package/esm/configuration/index.js +3 -1
  36. package/esm/configuration/partitionAdvanced.d.ts +12 -0
  37. package/esm/configuration/partitionAdvanced.js +42 -0
  38. package/esm/configuration/plot.d.ts +67 -0
  39. package/esm/configuration/plot.js +175 -0
  40. package/esm/configuration/readConfObject.d.ts +15 -17
  41. package/esm/configuration/readConfObject.js +19 -50
  42. package/esm/configuration/schemaTypes.js +5 -1
  43. package/esm/configuration/snapshotPreprocess.js +1 -3
  44. package/esm/configuration/types.d.ts +60 -159
  45. package/esm/pluggableElementTypes/DisplayType.d.ts +14 -0
  46. package/esm/pluggableElementTypes/DisplayType.js +13 -0
  47. package/esm/pluggableElementTypes/RpcMethodType.d.ts +7 -0
  48. package/esm/pluggableElementTypes/RpcMethodType.js +9 -0
  49. package/esm/pluggableElementTypes/WidgetType.d.ts +6 -0
  50. package/esm/pluggableElementTypes/WidgetType.js +6 -0
  51. package/esm/pluggableElementTypes/addMenuItems.d.ts +2 -1
  52. package/esm/pluggableElementTypes/addMenuItems.js +2 -1
  53. package/esm/pluggableElementTypes/index.js +1 -8
  54. package/esm/pluggableElementTypes/models/BaseDisplayModel.d.ts +58 -1
  55. package/esm/pluggableElementTypes/models/BaseDisplayModel.js +84 -2
  56. package/esm/pluggableElementTypes/models/BaseTrackModel.d.ts +2 -4
  57. package/esm/pluggableElementTypes/models/BaseTrackModel.js +2 -4
  58. package/esm/pluggableElementTypes/models/BaseViewModel.d.ts +2 -2
  59. package/esm/pluggableElementTypes/models/BaseViewModel.js +1 -1
  60. package/esm/pluggableElementTypes/models/baseTrackConfig.js +3 -0
  61. package/esm/rpc/RpcRegistry.d.ts +2 -1
  62. package/esm/rpc/byteBudget.d.ts +7 -0
  63. package/esm/rpc/byteBudget.js +10 -0
  64. package/esm/rpc/coreRpcMethods.d.ts +1 -1
  65. package/esm/rpc/coreRpcMethods.js +1 -1
  66. package/esm/rpc/explainTransferError.js +3 -3
  67. package/esm/rpc/methods/CoreLoadTrackCode.d.ts +17 -0
  68. package/esm/rpc/methods/CoreLoadTrackCode.js +24 -0
  69. package/esm/ui/AppLogo.js +43 -3
  70. package/esm/ui/JexlFilterDialog.d.ts +1 -1
  71. package/esm/ui/JexlFilterDialog.js +2 -3
  72. package/esm/ui/buildExtraTrackMenuItems.d.ts +2 -2
  73. package/esm/ui/colors.d.ts +41 -30
  74. package/esm/ui/colors.js +81 -44
  75. package/esm/ui/multiTrackMenuItems.d.ts +2 -2
  76. package/esm/util/TimeTraveller.d.ts +3 -0
  77. package/esm/util/TimeTraveller.js +34 -2
  78. package/esm/util/alignedBytes.d.ts +19 -0
  79. package/esm/util/alignedBytes.js +37 -0
  80. package/esm/util/analytics.d.ts +5 -6
  81. package/esm/util/analytics.js +5 -3
  82. package/esm/util/baseDisplayConfig.d.ts +8 -0
  83. package/esm/util/baseDisplayConfig.js +27 -0
  84. package/esm/util/bezierConnector.js +5 -1
  85. package/esm/util/cachedSetup.d.ts +16 -6
  86. package/esm/util/cachedSetup.js +108 -38
  87. package/esm/util/categoricalField.d.ts +23 -3
  88. package/esm/util/categoricalField.js +36 -3
  89. package/esm/util/cellMatches.d.ts +23 -0
  90. package/esm/util/cellMatches.js +264 -0
  91. package/esm/util/cellsStep.d.ts +27 -0
  92. package/esm/util/cellsStep.js +439 -0
  93. package/esm/util/color-bits/parse.js +22 -11
  94. package/esm/util/colorRamp.js +6 -0
  95. package/esm/util/colorScale.d.ts +9 -2
  96. package/esm/util/colorScale.js +33 -2
  97. package/esm/util/colorSchemes.d.ts +4 -2
  98. package/esm/util/colorSchemes.js +4 -1
  99. package/esm/util/copyToClipboard.js +8 -1
  100. package/esm/util/createAbortRotation.js +3 -3
  101. package/esm/util/featureTransforms.d.ts +7 -6
  102. package/esm/util/featureTransforms.js +131 -479
  103. package/esm/util/fetchPhases.d.ts +1 -1
  104. package/esm/util/formatBytes.js +1 -1
  105. package/esm/util/formatGuessers.d.ts +25 -14
  106. package/esm/util/formatGuessers.js +42 -27
  107. package/esm/util/formatRelativeTime.js +1 -1
  108. package/esm/util/getLocationUri.d.ts +2 -1
  109. package/esm/util/getLocationUri.js +8 -2
  110. package/esm/util/groupKeys.d.ts +4 -5
  111. package/esm/util/groupKeys.js +7 -6
  112. package/esm/util/intervals.js +9 -4
  113. package/esm/util/io/index.js +3 -1
  114. package/esm/util/isoformRank.d.ts +39 -0
  115. package/esm/util/isoformRank.js +118 -0
  116. package/esm/util/jexlFilters.d.ts +31 -49
  117. package/esm/util/jexlFilters.js +29 -39
  118. package/esm/util/locString.js +5 -2
  119. package/esm/util/markEncoding.js +48 -8
  120. package/esm/util/markEncodingTypes.d.ts +11 -2
  121. package/esm/util/quantileExtent.d.ts +22 -0
  122. package/esm/util/quantileExtent.js +24 -1
  123. package/esm/util/springAnimate.js +1 -1
  124. package/esm/util/stepTables.d.ts +14 -0
  125. package/esm/util/stepTables.js +38 -4
  126. package/esm/util/systemColorScheme.d.ts +4 -0
  127. package/esm/util/systemColorScheme.js +21 -0
  128. package/esm/util/tabix.d.ts +7 -3
  129. package/esm/util/tabix.js +3 -3
  130. package/esm/util/temporaryAssembly.d.ts +2 -2
  131. package/esm/util/temporaryAssembly.js +2 -3
  132. package/esm/util/trackConfigDelta.d.ts +1 -1
  133. package/esm/util/tracks.d.ts +28 -45
  134. package/esm/util/tracks.js +71 -82
  135. package/esm/util/types/index.d.ts +15 -7
  136. package/esm/util/types/index.js +21 -2
  137. package/esm/util/unknownSnapshotKeys.d.ts +3 -1
  138. package/esm/util/unknownSnapshotKeys.js +5 -11
  139. package/esm/util/usePanZoom.js +10 -3
  140. package/esm/util/useRafCommit.js +1 -0
  141. package/esm/util/useRowVirtualScroll.d.ts +1 -0
  142. package/esm/util/withFeatureDetails.js +4 -0
  143. package/package.json +13 -9
  144. package/esm/rpc/methods/CoreLoadAdapterCode.d.ts +0 -13
  145. package/esm/rpc/methods/CoreLoadAdapterCode.js +0 -16
@@ -1,10 +1,11 @@
1
1
  import type { SimpleFeatureSerialized, SimpleFeatureSerializedNoId } from '../../util/index.ts';
2
+ import type { CanonicalTranscripts } from '../../util/isoformRank.ts';
2
3
  import type { SequenceDisplayMode, ShowCoordinatesMode } from './model.ts';
3
4
  export declare function featureHasCDS(feature: SimpleFeatureSerializedNoId): boolean;
4
5
  export declare function featureHasExon(feature: SimpleFeatureSerializedNoId): boolean;
5
6
  export declare function featureHasExonOrCDS(feature: SimpleFeatureSerializedNoId): boolean;
6
7
  export declare function getTranscripts(feature: SimpleFeatureSerialized): SimpleFeatureSerialized[];
7
- export declare function pickDefaultTranscriptIndex(transcripts: SimpleFeatureSerialized[]): number;
8
+ export declare function pickDefaultTranscriptIndex(transcripts: SimpleFeatureSerialized[], canonical?: CanonicalTranscripts): number;
8
9
  export declare function getDefaultMode(feature: SimpleFeatureSerializedNoId): SequenceDisplayMode;
9
10
  export declare function modeHasUpDownstream(mode: SequenceDisplayMode): boolean;
10
11
  export declare function modeSupportsRevcomp(mode: SequenceDisplayMode): boolean;
@@ -1,3 +1,4 @@
1
+ import { DEFAULT_CANONICAL_TRANSCRIPTS, isoformScorer, rankIsoforms, serializedIsoformReader, } from '../../util/isoformRank.js';
1
2
  // these predicates only ever read type/subfeatures, so they accept a bare
2
3
  // subfeature (no guaranteed uniqueId) as readily as a full feature
3
4
  export function featureHasCDS(feature) {
@@ -30,20 +31,12 @@ export function getTranscripts(feature) {
30
31
  uniqueId: `${feature.uniqueId}_${idx}`,
31
32
  })) ?? []);
32
33
  }
33
- // index of the transcript the gene glyph itself would collapse to in
34
- // 'longestCoding' mode (RenderFeatureDataRPC/glyphs/subfeatures.ts): prefer a
35
- // coding transcript, then the longest span — so the sequence panel's default
36
- // matches what the track already drew. A feature that is itself a transcript
37
- // (clicked directly, not via its container gene) has no nested transcripts to
38
- // autopick from.
39
- export function pickDefaultTranscriptIndex(transcripts) {
40
- if (transcripts.length === 0) {
41
- return 0;
42
- }
43
- const coding = transcripts.filter(t => featureHasCDS(t));
44
- const candidates = coding.length > 0 ? coding : transcripts;
45
- const longest = candidates.reduce((a, b) => b.end - b.start > a.end - a.start ? b : a);
46
- return transcripts.indexOf(longest);
34
+ // The isoform the canvas gene glyph draws first, so the panel opens on the
35
+ // transcript the track showed. A feature that is itself a transcript has no
36
+ // nested transcripts to pick from.
37
+ export function pickDefaultTranscriptIndex(transcripts, canonical = DEFAULT_CANONICAL_TRANSCRIPTS) {
38
+ const [best] = rankIsoforms(transcripts, isoformScorer(serializedIsoformReader, canonical));
39
+ return best ? transcripts.indexOf(best) : 0;
47
40
  }
48
41
  export function getDefaultMode(feature) {
49
42
  return featureHasCDS(feature)
@@ -51,9 +51,9 @@ const CDNASequence = observer(function CDNASequence({ cds, exons, sequence, upst
51
51
  }
52
52
  // The stretches of the feature its own exons do not reach. Real annotations
53
53
  // produce them: CAT/liftoff emits a transcript spanning the source alignment
54
- // with exons only where the CDS is supported, so KCNT2 in
55
- // `hprc_cfhr_HG00099.1.genes.gff3.gz` runs 10,207 bp past its first exon and
56
- // 28 of that corpus's 438 transcripts do the same.
54
+ // with exons only where the CDS is supported, so KCNT2 in HG00099.1's HPRC CAT
55
+ // annotation runs 10,207 bp past its first exon, and 28 of the 438 transcripts
56
+ // around CFH do the same.
57
57
  //
58
58
  // Uncolored, like the inter-exon gaps they are — the annotation does not call
59
59
  // them exonic, so stretching the first and last exon over them (which is what
@@ -18,13 +18,16 @@ function processFeatureData(children, feature) {
18
18
  // translations if included)
19
19
  const featureType = feature.type?.toLowerCase();
20
20
  const isMatureProteinRegion = featureType === 'mature_protein_region_of_cds';
21
+ const ofType = (type) => children.filter(sub => sub.type?.toLowerCase() === type);
22
+ // A frameshift polyprotein's CDS carries its reading frames as CDS rows beside
23
+ // its cleavage products; a single-frame one has only the products.
24
+ const codingRows = ofType('cds');
21
25
  const cds = isMatureProteinRegion
22
26
  ? [{ start: 0, end: feature.end - feature.start, type: 'CDS' }]
23
- : filterSuccessiveElementsWithSameStartAndEndCoord(children.filter(sub => {
24
- const type = sub.type?.toLowerCase();
25
- return type === 'cds' || type === 'mature_protein_region_of_cds';
26
- }));
27
- const exons = filterSuccessiveElementsWithSameStartAndEndCoord(children.filter(sub => sub.type?.toLowerCase() === 'exon'));
27
+ : filterSuccessiveElementsWithSameStartAndEndCoord(codingRows.length > 0
28
+ ? codingRows
29
+ : ofType('mature_protein_region_of_cds'));
30
+ const exons = filterSuccessiveElementsWithSameStartAndEndCoord(ofType('exon'));
28
31
  // annotated UTRs are deliberately not read: a UTR is just the exonic sequence
29
32
  // outside the CDS, so the renderer derives the split from cds+exons. Trusting
30
33
  // the annotation meant a transcript that named only one of its UTRs lost the
@@ -1,6 +1,7 @@
1
1
  import type PluginManager from '../PluginManager.ts';
2
2
  import type { AnyConfigurationModel } from '../configuration/index.ts';
3
3
  import type { ParentFeatureSummary, SimpleFeatureSerialized } from '../util/index.ts';
4
+ import type { CanonicalTranscripts } from '../util/isoformRank.ts';
4
5
  import type { SequenceHoverPosition } from './SequenceFeatureDetails/model.ts';
5
6
  import type { FormatDetailsTiers } from './formatDetails.ts';
6
7
  import type { Descriptors, MaybeSerializedFeat } from './types.tsx';
@@ -88,6 +89,12 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
88
89
  feature?: SimpleFeatureSerialized;
89
90
  error?: Error;
90
91
  };
92
+ /**
93
+ * #getter
94
+ * the isoform tags the open track's display ranks by, so the sequence
95
+ * panel opens on the transcript the track draws first
96
+ */
97
+ readonly canonicalTranscripts: CanonicalTranscripts;
91
98
  /**
92
99
  * #getter
93
100
  * levels of subfeature card the panel renders; unset means no limit
@@ -1,6 +1,7 @@
1
1
  import { getEnv, isStateTreeNode, types } from '@jbrowse/mobx-state-tree';
2
2
  import { hydrateTrackConfig } from '../configuration/index.js';
3
3
  import { getSession } from '../util/index.js';
4
+ import { DEFAULT_CANONICAL_TRANSCRIPTS, isCanonicalTranscriptsHost, } from '../util/isoformRank.js';
4
5
  import { ElementId } from '../util/types/mst.js';
5
6
  import { SequenceFeatureDetailsF } from './SequenceFeatureDetails/model.js';
6
7
  import { applyFormatDetails, formatDetailsNumber } from './formatDetails.js';
@@ -116,6 +117,16 @@ export function stateModelFactory(pluginManager) {
116
117
  return { error };
117
118
  }
118
119
  },
120
+ /**
121
+ * #getter
122
+ * the isoform tags the open track's display ranks by, so the sequence
123
+ * panel opens on the transcript the track draws first
124
+ */
125
+ get canonicalTranscripts() {
126
+ const track = self.track;
127
+ return (track?.displays.find(isCanonicalTranscriptsHost)
128
+ ?.canonicalTranscripts ?? DEFAULT_CANONICAL_TRANSCRIPTS);
129
+ },
119
130
  /**
120
131
  * #getter
121
132
  * levels of subfeature card the panel renders; unset means no limit
@@ -1,4 +1,5 @@
1
1
  import type { MenuItem } from '../ui/MenuTypes.ts';
2
+ import type { CanonicalTranscripts } from '../util/isoformRank.ts';
2
3
  import type { SimpleFeatureSerialized } from '../util/simpleFeature.ts';
3
4
  import type { SequenceFeatureDetailsModel, SequenceHoverTarget } from './SequenceFeatureDetails/model.ts';
4
5
  import type { IStateTreeNode } from '@jbrowse/mobx-state-tree';
@@ -9,6 +10,7 @@ export interface FeatureDetailsModel extends IStateTreeNode, SequenceHoverTarget
9
10
  view: {
10
11
  assemblyNames: string[];
11
12
  } | undefined;
13
+ canonicalTranscripts?: CanonicalTranscripts;
12
14
  }
13
15
  export interface Descriptors {
14
16
  [key: string]: React.ReactNode | Descriptors;
package/esm/CorePlugin.js CHANGED
@@ -1,10 +1,40 @@
1
+ import { trackTypeForAdapter } from '@jbrowse/add-track-core';
1
2
  import { configSchema, stateModelFactory } from './BaseFeatureWidget/index.js';
2
3
  import Plugin from './Plugin.js';
3
4
  import CytobandAdapterF from './data_adapters/CytobandAdapter/index.js';
4
5
  import WidgetType from './pluggableElementTypes/WidgetType.js';
5
6
  import * as coreRpcMethods from './rpc/coreRpcMethods.js';
6
- import { installFormatGuessers } from './util/formatGuessers.js';
7
+ import { guessTrackConfFromTable } from './util/formatGuessers.js';
8
+ import { getFileName } from './util/getFileName.js';
7
9
  import { lazyWithPreload } from './util/lazyWithPreload.js';
10
+ import { addAdapterGuesser, addTrackTypeGuesser } from './util/tracks.js';
11
+ /**
12
+ * Guess every format `@jbrowse/add-track-core`'s table describes — the same
13
+ * table `@jbrowse/cli`'s `add-track` reads, so a file resolves to the same
14
+ * adapter config in the app and on the command line.
15
+ *
16
+ * Whether a build can open a format is decided by `hasAdapterType`, not by the
17
+ * table: guessing `BamAdapter` in a build with no alignments plugin writes a
18
+ * track config that fails at render. A plugin therefore registers its adapters
19
+ * and nothing else — there is no format list to keep in step. ADR-077.
20
+ *
21
+ * `CorePlugin` installs this first, so any `addAdapterGuesser` a plugin
22
+ * registers is later in the chain and wins over the table. That is how a format
23
+ * the table cannot express is added, and how a third-party plugin claims one.
24
+ */
25
+ // #region installFormatGuessers
26
+ function installFormatGuessers(pluginManager) {
27
+ addAdapterGuesser(pluginManager, (file, index, adapterHint) => {
28
+ const adapter = guessTrackConfFromTable(file, index, adapterHint)?.adapter;
29
+ return adapter && pluginManager.hasAdapterType(adapter.type)
30
+ ? adapter
31
+ : undefined;
32
+ });
33
+ addTrackTypeGuesser(pluginManager, (adapterName, file) => pluginManager.hasAdapterType(adapterName)
34
+ ? trackTypeForAdapter(adapterName, file && getFileName(file))
35
+ : undefined);
36
+ }
37
+ // #endregion
8
38
  // the core plugin, which registers types that ALL JBrowse applications are
9
39
  // expected to need.
10
40
  export default class CorePlugin extends Plugin {
@@ -19,6 +49,7 @@ export default class CorePlugin extends Plugin {
19
49
  pluginManager.addWidgetType(() => {
20
50
  return new WidgetType({
21
51
  name: 'BaseFeatureWidget',
52
+ discardOnClose: true,
22
53
  heading: 'Feature details',
23
54
  configSchema,
24
55
  stateModel: stateModelFactory(pluginManager),
@@ -375,9 +375,12 @@ export default class PluginManager {
375
375
  * frozen object, so a hit can only ever come from this same instance and this
376
376
  * same track type. See ADR-031.
377
377
  *
378
- * The node is never mutated: admin edits replace the frozen entry (new
379
- * identity drops the WeakMap entry), and a non-admin's edits go to a private
380
- * session working copy, not here (ADR-032). Both levels are `WeakMap`s so
378
+ * The node is never mutated: every edit goes to a private session working
379
+ * copy, not here, and is stored as a delta whose merged config is a new
380
+ * object (ADR-032). In a session composing `SessionTracksManagerSessionMixin`,
381
+ * which every product does, `track.configuration` resolves to that working
382
+ * copy, so this memo serves `hydrateTrackConfig` and sessions without the
383
+ * mixin. Both levels are `WeakMap`s so
381
384
  * entries collect normally — no manual invalidation needed, which is why this
382
385
  * is a memo and not a cache with a lifecycle to expose.
383
386
  */
@@ -155,9 +155,12 @@ export default class PluginManager {
155
155
  * frozen object, so a hit can only ever come from this same instance and this
156
156
  * same track type. See ADR-031.
157
157
  *
158
- * The node is never mutated: admin edits replace the frozen entry (new
159
- * identity drops the WeakMap entry), and a non-admin's edits go to a private
160
- * session working copy, not here (ADR-032). Both levels are `WeakMap`s so
158
+ * The node is never mutated: every edit goes to a private session working
159
+ * copy, not here, and is stored as a delta whose merged config is a new
160
+ * object (ADR-032). In a session composing `SessionTracksManagerSessionMixin`,
161
+ * which every product does, `track.configuration` resolves to that working
162
+ * copy, so this memo serves `hydrateTrackConfig` and sessions without the
163
+ * mixin. Both levels are `WeakMap`s so
161
164
  * entries collect normally — no manual invalidation needed, which is why this
162
165
  * is a memo and not a cache with a lifecycle to expose.
163
166
  */