@jbrowse/cli 5.0.0-beta.10 → 5.0.0-beta.11

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.
@@ -1,5 +1,5 @@
1
1
  import fs from 'node:fs';
2
- import { adapterTypesToTrackTypeMap, formats, matchFormat, resolveIndexType, sidecarCandidateNames, trackTypeForAdapter, } from '@jbrowse/add-track-core';
2
+ import { adapterTypesToTrackTypeMap, fileNameOf, formats, matchFormat, resolveIndexType, sidecarCandidateNames, trackTypeForAdapter, } from '@jbrowse/add-track-core';
3
3
  import { isURL } from '../../types/common.js';
4
4
  import { densitySidecarPath } from '../shared/density.js';
5
5
  import { configManifest } from '../validate/configManifest.generated.js';
@@ -134,14 +134,6 @@ export function makeLocationProtocol(protocol) {
134
134
  throw new Error(`invalid protocol ${protocol}`);
135
135
  };
136
136
  }
137
- /**
138
- * The bare filename the format table matches against — the same thing
139
- * `@jbrowse/core`'s `getFileName` hands the guesser chain, so a path and a URL
140
- * with a presigned query string both reduce to what the regexes expect.
141
- */
142
- export function fileNameOf(location) {
143
- return (location.replaceAll('\\', '/').split('/').at(-1)?.split(/[?#]/)[0] ?? '');
144
- }
145
137
  // resolves the file-layout spec that both the adapter config and the copied
146
138
  // file set derive from, honoring an explicit --adapterType. `typeOverride` is
147
139
  // the label to stamp on the adapter when the extension's layout is reused under
@@ -2757,7 +2757,8 @@ export const configManifest = {
2757
2757
  "DotplotDisplay",
2758
2758
  "LinearSyntenyDisplay",
2759
2759
  "LGVSyntenyDisplay",
2760
- "MultiWaySyntenyDisplay"
2760
+ "MultiWaySyntenyDisplay",
2761
+ "LinearMarkDisplay"
2761
2762
  ]
2762
2763
  },
2763
2764
  "GWASTrack": {
@@ -3124,7 +3125,6 @@ export const configManifest = {
3124
3125
  "id",
3125
3126
  "type",
3126
3127
  "configuration",
3127
- "filterSetting",
3128
3128
  "pinnedFeatureIds",
3129
3129
  "soloFeatureIds",
3130
3130
  "soloApplied",
@@ -5101,7 +5101,6 @@ export const configManifest = {
5101
5101
  "id",
5102
5102
  "type",
5103
5103
  "configuration",
5104
- "filterSetting",
5105
5104
  "pinnedFeatureIds",
5106
5105
  "soloFeatureIds",
5107
5106
  "soloApplied",
@@ -5346,8 +5345,7 @@ export const configManifest = {
5346
5345
  "runClustering",
5347
5346
  "clusterRegion",
5348
5347
  "sortRowsBy",
5349
- "configuration",
5350
- "filterSetting"
5348
+ "configuration"
5351
5349
  ]
5352
5350
  },
5353
5351
  "LDTrackDisplay": {
@@ -6442,7 +6440,6 @@ export const configManifest = {
6442
6440
  "clusterRegion",
6443
6441
  "sortRowsBy",
6444
6442
  "configuration",
6445
- "filterSetting",
6446
6443
  "indexSnp",
6447
6444
  "indexSnpPinned"
6448
6445
  ]
@@ -6923,14 +6920,17 @@ export const configManifest = {
6923
6920
  "minimalTicks",
6924
6921
  "jexlFilters"
6925
6922
  ],
6923
+ "aliases": [
6924
+ "LinearArcDisplay",
6925
+ "LinearPairedArcDisplay"
6926
+ ],
6926
6927
  "stateModelProps": [
6927
6928
  "id",
6928
6929
  "type",
6929
6930
  "runClustering",
6930
6931
  "clusterRegion",
6931
6932
  "sortRowsBy",
6932
- "configuration",
6933
- "filterSetting"
6933
+ "configuration"
6934
6934
  ]
6935
6935
  }
6936
6936
  },
@@ -7431,6 +7431,7 @@ export const configManifest = {
7431
7431
  "assemblyNames",
7432
7432
  "drawCigar",
7433
7433
  "showGridlines",
7434
+ "showTickLabels",
7434
7435
  "lockAspectRatio",
7435
7436
  "lineWidth",
7436
7437
  "minIdentity",
@@ -7558,6 +7559,9 @@ export const configManifest = {
7558
7559
  "*": [
7559
7560
  "heightPreConfig"
7560
7561
  ],
7562
+ "LinearBasicDisplay": [
7563
+ "jexlFiltersSetting"
7564
+ ],
7561
7565
  "LinearAlignmentsDisplay": [
7562
7566
  "PileupDisplay",
7563
7567
  "SNPCoverageDisplay",
@@ -7568,6 +7572,9 @@ export const configManifest = {
7568
7572
  "hideMismatchesSetting",
7569
7573
  "trackMaxHeight"
7570
7574
  ],
7575
+ "LinearVariantDisplay": [
7576
+ "jexlFiltersSetting"
7577
+ ],
7571
7578
  "LinearMultiSampleVariantDisplay": [
7572
7579
  "clusterTree",
7573
7580
  "jexlFilters",
@@ -5,7 +5,7 @@ export const configJsonSchema = JSON.parse(`
5
5
  "$schema": "https://json-schema.org/draft/2020-12/schema",
6
6
  "$id": "https://jbrowse.org/jb2/schema/v5/config.json",
7
7
  "title": "JBrowse config.json",
8
- "description": "The JBrowse 5.0.0-beta.10 config.json: assemblies, tracks, connections, site-wide configuration and a default session. Generated from the registered types by \`pnpm autogen\`.",
8
+ "description": "The JBrowse 5.0.0-beta.11 config.json: assemblies, tracks, connections, site-wide configuration and a default session. Generated from the registered types by \`pnpm autogen\`.",
9
9
  "type": "object",
10
10
  "properties": {
11
11
  "$schema": {
@@ -8656,7 +8656,11 @@ export const configJsonSchema = JSON.parse(`
8656
8656
  ],
8657
8657
  "properties": {
8658
8658
  "type": {
8659
- "const": "LinearMarkDisplay"
8659
+ "enum": [
8660
+ "LinearMarkDisplay",
8661
+ "LinearArcDisplay",
8662
+ "LinearPairedArcDisplay"
8663
+ ]
8660
8664
  },
8661
8665
  "displayId": {
8662
8666
  "type": "string"
@@ -11907,6 +11911,9 @@ export const configJsonSchema = JSON.parse(`
11907
11911
  },
11908
11912
  {
11909
11913
  "$ref": "#/$defs/MultiWaySyntenyDisplaySlots/properties/fetchSizeLimit"
11914
+ },
11915
+ {
11916
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/fetchSizeLimit"
11910
11917
  }
11911
11918
  ]
11912
11919
  },
@@ -11917,6 +11924,9 @@ export const configJsonSchema = JSON.parse(`
11917
11924
  },
11918
11925
  {
11919
11926
  "$ref": "#/$defs/MultiWaySyntenyDisplaySlots/properties/forceLoad"
11927
+ },
11928
+ {
11929
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/forceLoad"
11920
11930
  }
11921
11931
  ]
11922
11932
  },
@@ -11927,6 +11937,9 @@ export const configJsonSchema = JSON.parse(`
11927
11937
  },
11928
11938
  {
11929
11939
  "$ref": "#/$defs/MultiWaySyntenyDisplaySlots/properties/height"
11940
+ },
11941
+ {
11942
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/height"
11930
11943
  }
11931
11944
  ]
11932
11945
  },
@@ -11950,10 +11963,24 @@ export const configJsonSchema = JSON.parse(`
11950
11963
  "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/growMaxHeight"
11951
11964
  },
11952
11965
  "densityTier": {
11953
- "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/densityTier"
11966
+ "anyOf": [
11967
+ {
11968
+ "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/densityTier"
11969
+ },
11970
+ {
11971
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/densityTier"
11972
+ }
11973
+ ]
11954
11974
  },
11955
11975
  "densityTierBpPerPx": {
11956
- "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/densityTierBpPerPx"
11976
+ "anyOf": [
11977
+ {
11978
+ "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/densityTierBpPerPx"
11979
+ },
11980
+ {
11981
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/densityTierBpPerPx"
11982
+ }
11983
+ ]
11957
11984
  },
11958
11985
  "readConnectionsLineWidth": {
11959
11986
  "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/readConnectionsLineWidth"
@@ -11987,13 +12014,27 @@ export const configJsonSchema = JSON.parse(`
11987
12014
  "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/filterBy"
11988
12015
  },
11989
12016
  "facet": {
11990
- "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/facet"
12017
+ "anyOf": [
12018
+ {
12019
+ "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/facet"
12020
+ },
12021
+ {
12022
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/facet"
12023
+ }
12024
+ ]
11991
12025
  },
11992
12026
  "collapseGroupRows": {
11993
12027
  "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/collapseGroupRows"
11994
12028
  },
11995
12029
  "scales": {
11996
- "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/scales"
12030
+ "anyOf": [
12031
+ {
12032
+ "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/scales"
12033
+ },
12034
+ {
12035
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/scales"
12036
+ }
12037
+ ]
11997
12038
  },
11998
12039
  "mismatchAlpha": {
11999
12040
  "$ref": "#/$defs/LGVSyntenyDisplaySlots/properties/mismatchAlpha"
@@ -12008,6 +12049,9 @@ export const configJsonSchema = JSON.parse(`
12008
12049
  },
12009
12050
  {
12010
12051
  "$ref": "#/$defs/MultiWaySyntenyDisplaySlots/properties/showLegend"
12052
+ },
12053
+ {
12054
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/showLegend"
12011
12055
  }
12012
12056
  ]
12013
12057
  },
@@ -12140,6 +12184,51 @@ export const configJsonSchema = JSON.parse(`
12140
12184
  },
12141
12185
  "splitStrands": {
12142
12186
  "$ref": "#/$defs/MultiWaySyntenyDisplaySlots/properties/splitStrands"
12187
+ },
12188
+ "marks": {
12189
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/marks"
12190
+ },
12191
+ "transform": {
12192
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/transform"
12193
+ },
12194
+ "rows": {
12195
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/rows"
12196
+ },
12197
+ "rowColor": {
12198
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/rowColor"
12199
+ },
12200
+ "showTree": {
12201
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/showTree"
12202
+ },
12203
+ "showBranchLength": {
12204
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/showBranchLength"
12205
+ },
12206
+ "showRowLabels": {
12207
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/showRowLabels"
12208
+ },
12209
+ "treeAreaWidth": {
12210
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/treeAreaWidth"
12211
+ },
12212
+ "rowHeight": {
12213
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/rowHeight"
12214
+ },
12215
+ "origin": {
12216
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/origin"
12217
+ },
12218
+ "minWidthPx": {
12219
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/minWidthPx"
12220
+ },
12221
+ "filter": {
12222
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/filter"
12223
+ },
12224
+ "displayCrossHatches": {
12225
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/displayCrossHatches"
12226
+ },
12227
+ "minimalTicks": {
12228
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/minimalTicks"
12229
+ },
12230
+ "jexlFilters": {
12231
+ "$ref": "#/$defs/LinearMarkDisplaySlots/properties/jexlFilters"
12143
12232
  }
12144
12233
  },
12145
12234
  "patternProperties": {
@@ -14268,7 +14357,11 @@ export const configJsonSchema = JSON.parse(`
14268
14357
  "type": "object",
14269
14358
  "properties": {
14270
14359
  "type": {
14271
- "const": "LinearMarkDisplay"
14360
+ "enum": [
14361
+ "LinearMarkDisplay",
14362
+ "LinearArcDisplay",
14363
+ "LinearPairedArcDisplay"
14364
+ ]
14272
14365
  }
14273
14366
  },
14274
14367
  "required": [
@@ -15073,12 +15166,6 @@ export const configJsonSchema = JSON.parse(`
15073
15166
  "LinearBasicDisplayState": {
15074
15167
  "type": "object",
15075
15168
  "properties": {
15076
- "filterSetting": {
15077
- "type": "array",
15078
- "items": {
15079
- "type": "string"
15080
- }
15081
- },
15082
15169
  "pinnedFeatureIds": {
15083
15170
  "type": "array",
15084
15171
  "items": {
@@ -15136,6 +15223,10 @@ export const configJsonSchema = JSON.parse(`
15136
15223
  "heightPreConfig": {
15137
15224
  "deprecated": true,
15138
15225
  "description": "Legacy display-instance key: a migration lifts it onto the setting that replaced it."
15226
+ },
15227
+ "jexlFiltersSetting": {
15228
+ "deprecated": true,
15229
+ "description": "Legacy display-instance key: a migration lifts it onto the setting that replaced it."
15139
15230
  }
15140
15231
  }
15141
15232
  },
@@ -15659,12 +15750,6 @@ export const configJsonSchema = JSON.parse(`
15659
15750
  "LinearVariantDisplayState": {
15660
15751
  "type": "object",
15661
15752
  "properties": {
15662
- "filterSetting": {
15663
- "type": "array",
15664
- "items": {
15665
- "type": "string"
15666
- }
15667
- },
15668
15753
  "pinnedFeatureIds": {
15669
15754
  "type": "array",
15670
15755
  "items": {
@@ -15722,6 +15807,10 @@ export const configJsonSchema = JSON.parse(`
15722
15807
  "heightPreConfig": {
15723
15808
  "deprecated": true,
15724
15809
  "description": "Legacy display-instance key: a migration lifts it onto the setting that replaced it."
15810
+ },
15811
+ "jexlFiltersSetting": {
15812
+ "deprecated": true,
15813
+ "description": "Legacy display-instance key: a migration lifts it onto the setting that replaced it."
15725
15814
  }
15726
15815
  }
15727
15816
  },
@@ -15770,12 +15859,6 @@ export const configJsonSchema = JSON.parse(`
15770
15859
  "type": "string"
15771
15860
  },
15772
15861
  "sortRowsBy": {},
15773
- "filterSetting": {
15774
- "type": "array",
15775
- "items": {
15776
- "type": "string"
15777
- }
15778
- },
15779
15862
  "heightPreConfig": {
15780
15863
  "deprecated": true,
15781
15864
  "description": "Legacy display-instance key: a migration lifts it onto the setting that replaced it."
@@ -16126,12 +16209,6 @@ export const configJsonSchema = JSON.parse(`
16126
16209
  "type": "string"
16127
16210
  },
16128
16211
  "sortRowsBy": {},
16129
- "filterSetting": {
16130
- "type": "array",
16131
- "items": {
16132
- "type": "string"
16133
- }
16134
- },
16135
16212
  "indexSnp": {
16136
16213
  "type": "string"
16137
16214
  },
@@ -16189,12 +16266,6 @@ export const configJsonSchema = JSON.parse(`
16189
16266
  "type": "string"
16190
16267
  },
16191
16268
  "sortRowsBy": {},
16192
- "filterSetting": {
16193
- "type": "array",
16194
- "items": {
16195
- "type": "string"
16196
- }
16197
- },
16198
16269
  "heightPreConfig": {
16199
16270
  "deprecated": true,
16200
16271
  "description": "Legacy display-instance key: a migration lifts it onto the setting that replaced it."
@@ -16212,7 +16283,11 @@ export const configJsonSchema = JSON.parse(`
16212
16283
  ],
16213
16284
  "properties": {
16214
16285
  "type": {
16215
- "const": "LinearMarkDisplay"
16286
+ "enum": [
16287
+ "LinearMarkDisplay",
16288
+ "LinearArcDisplay",
16289
+ "LinearPairedArcDisplay"
16290
+ ]
16216
16291
  },
16217
16292
  "id": {
16218
16293
  "type": "string"
@@ -17075,7 +17150,11 @@ export const configJsonSchema = JSON.parse(`
17075
17150
  "type": "object",
17076
17151
  "properties": {
17077
17152
  "type": {
17078
- "const": "LinearMarkDisplay"
17153
+ "enum": [
17154
+ "LinearMarkDisplay",
17155
+ "LinearArcDisplay",
17156
+ "LinearPairedArcDisplay"
17157
+ ]
17079
17158
  }
17080
17159
  },
17081
17160
  "required": [
@@ -18979,6 +19058,9 @@ export const configJsonSchema = JSON.parse(`
18979
19058
  "showGridlines": {
18980
19059
  "type": "boolean"
18981
19060
  },
19061
+ "showTickLabels": {
19062
+ "type": "boolean"
19063
+ },
18982
19064
  "lockAspectRatio": {
18983
19065
  "type": "boolean"
18984
19066
  },
@@ -1,8 +1,8 @@
1
1
  // Generated by scripts/generateMarkRules.ts from plugins/marks/src/LinearMarkDisplay/markProblems.ts: do not edit, `pnpm autogen` rewrites it.
2
2
  import { AUTO_BIN } from './autoBin.js';
3
3
  import { FEATURE_FIELD_PRESETS, aggregateFieldName, colorProblems, fieldScaleOf, isJexl, SHAPE_NAMES, isNamedColor, paintedScale, scaleEndProblems, universalPresetOf, } from './markRuleFacts.js';
4
- import { MARK_SPECS, rampResolvesPerRegion, readsValue } from './markSpecs.js';
5
- import { DEFAULT_AGGREGATE_OP, BIN_OVERLAP_FIELD, DEFAULT_BIN_AS, DEFAULT_BIN_FIELD, DEFAULT_COVERAGE_AS, DEFAULT_FORMULA_AS, DEFAULT_LINE_INTERPOLATE, DEFAULT_ROW_PROPORTION, DEFAULT_LINK_SHAPE, DEFAULT_MARK_TYPE, CELLS_FIELDS, DEFAULT_PILEUP_AS, DEFAULT_PILEUP_FIELDS, DEFAULT_TEXT_FIELD, DEFAULT_X2, MATE_FIELDS, } from './markVocabulary.js';
4
+ import { MARK_SPECS, readsValue } from './markSpecs.js';
5
+ import { DEFAULT_AGGREGATE_OP, BIN_OVERLAP_FIELD, DEFAULT_BIN_AS, DEFAULT_BIN_FIELD, DEFAULT_COVERAGE_AS, DEFAULT_FORMULA_AS, DEFAULT_LINE_INTERPOLATE, DEFAULT_ROW_PROPORTION, DEFAULT_LINK_SHAPE, DEFAULT_MARK_TYPE, CELLS_FIELDS, DEFAULT_PILEUP_AS, DEFAULT_PILEUP_FIELDS, DEFAULT_TEXT_FIELD, DEFAULT_X2, MATE_FIELDS, MAX_THRESHOLD_CUTS, } from './markVocabulary.js';
6
6
  import { stepChannels } from './stepChannels.js';
7
7
  /**
8
8
  * The level of every rule of the list, by the stable id a report and a test
@@ -27,6 +27,8 @@ export const MARK_RULES = {
27
27
  'threshold-cuts': 'warning',
28
28
  /** A threshold colour naming no cut, so every value paints one colour. */
29
29
  'threshold-no-cuts': 'warning',
30
+ /** A threshold colour naming more cuts than it paints, so a value past the eighth takes the ninth colour. */
31
+ 'threshold-cut-count': 'warning',
30
32
  /** A threshold `range` not one colour longer than its cuts. */
31
33
  'threshold-range': 'warning',
32
34
  /** A `domain` on a linear or log colour, whose ends are `domainMin` and `domainMax`. */
@@ -39,8 +41,6 @@ export const MARK_RULES = {
39
41
  'field-spells-constant': 'warning',
40
42
  /** A colour's or a shape's `labels` naming values its `domain` does not list, or no categorical scale's. */
41
43
  'labels-domain': 'warning',
42
- /** A text's colour ramp with an open end, whose colours then differ from one region to the next. */
43
- 'unpinned-text-ramp': 'warning',
44
44
  /** A `minBpPerPx` not below the mark's `maxBpPerPx`, so the mark never draws. */
45
45
  'empty-zoom-range': 'error',
46
46
  /** A `filter` or `formula` whose `expr` is not a `jexl:` expression. */
@@ -59,6 +59,8 @@ export const MARK_RULES = {
59
59
  'step-field-expression': 'error',
60
60
  /** A `y` naming a field that no `aggregate` or `coverage` step before it writes. */
61
61
  'unwritten-y': 'error',
62
+ /** Another channel naming a field that no `aggregate` or `coverage` step before it writes, so it reads no value; the field a `facet` or `rows` splits on counts as written. */
63
+ 'unwritten-field': 'warning',
62
64
  /** A mark other than a span drawn beside one that stacks rows, standing in the first of them. */
63
65
  'value-beside-rows': 'warning',
64
66
  /** Two `pileup` steps packing one plot, whose rows share numbers. */
@@ -120,11 +122,6 @@ function stepsOf(mark) {
120
122
  function colorScaleOf({ scale, field = '' }) {
121
123
  return paintedScale({ scale, field }, fieldScaleOf(FEATURE_FIELD_PRESETS, field));
122
124
  }
123
- function rampColor(mark) {
124
- const color = mark.encoding?.color ?? {};
125
- const painted = colorScaleOf(color);
126
- return painted === 'linear' || painted === 'log' ? color : undefined;
127
- }
128
125
  function sizeFieldOf(size) {
129
126
  return typeof size === 'string'
130
127
  ? size
@@ -381,7 +378,34 @@ function stepProblems(steps, list = 'transform') {
381
378
  }
382
379
  return problems;
383
380
  }
384
- function ownProblems(mark, display, section) {
381
+ // Each field a mark's channels read besides `y`, by the slot naming it: the
382
+ // channels its type reads, a colour's or a shape's field where it is a scale,
383
+ // a text's field as its default leaves it, and a link's size field.
384
+ function channelFields(mark, spec) {
385
+ const encoding = mark.encoding ?? {};
386
+ const { x, x2, row, color = {}, shape, text = DEFAULT_TEXT_FIELD } = encoding;
387
+ const reads = (channel) => spec.channels.includes(channel);
388
+ const named = [
389
+ ['encoding.x', x],
390
+ ['encoding.x2', typeof x2 === 'string' ? x2 : x2?.pos],
391
+ ['encoding.x2.chrom', typeof x2 === 'object' ? x2.chrom : undefined],
392
+ ['encoding.row', reads('row') ? row : undefined],
393
+ [
394
+ 'encoding.color.field',
395
+ reads('color') && colorScaleOf(color) !== 'none'
396
+ ? fieldOf(color)
397
+ : undefined,
398
+ ],
399
+ ['encoding.shape.field', reads('shape') ? fieldOf(shape) : undefined],
400
+ ['encoding.text', reads('text') ? text : undefined],
401
+ [
402
+ 'encoding.size.field',
403
+ spec.size === 'channel' ? sizeFieldOf(encoding.size) : undefined,
404
+ ],
405
+ ];
406
+ return named.flatMap(([slot, field]) => field && !isJexl(field) ? [[slot, field]] : []);
407
+ }
408
+ function ownProblems(mark, display, section, split) {
385
409
  const type = markTypeOf(mark);
386
410
  const problems = [];
387
411
  const y = mark.encoding?.y;
@@ -430,6 +454,10 @@ function ownProblems(mark, display, section) {
430
454
  (color.domain ?? []).length === 0) {
431
455
  problems.push(found('threshold-no-cuts', 'encoding.color.domain', 'a threshold names its cut points in domain, and with none every value paints the first colour'));
432
456
  }
457
+ const cutCount = (color.domain ?? []).filter(cut => Number.isFinite(Number(cut))).length;
458
+ if (colorScaleOf(color) === 'threshold' && cutCount > MAX_THRESHOLD_CUTS) {
459
+ problems.push(found('threshold-cut-count', 'encoding.color.domain', `a threshold paints ${MAX_THRESHOLD_CUTS} cuts, and these ${cutCount} leave a value past the ${MAX_THRESHOLD_CUTS}th in the ${MAX_THRESHOLD_CUTS + 1}th colour`));
460
+ }
433
461
  problems.push(...shapeLabelProblems(mark.encoding?.shape));
434
462
  problems.push(...constantAsFieldProblems(mark.encoding));
435
463
  if (typeof size === 'object') {
@@ -437,14 +465,6 @@ function ownProblems(mark, display, section) {
437
465
  problems.push(found(rule, `encoding.size.${slot}`, message));
438
466
  }
439
467
  }
440
- const ramp = rampColor(mark);
441
- if (ramp) {
442
- const { domainMin, domainMax } = ramp;
443
- if (rampResolvesPerRegion(type) &&
444
- (domainMin === undefined || domainMax === undefined)) {
445
- problems.push(found('unpinned-text-ramp', `encoding.color.${domainMin === undefined ? 'domainMin' : 'domainMax'}`, `a ${type}'s ramp resolves an open end against each region's own extremes, so its colours agree across regions only with domainMin and domainMax both pinned`));
446
- }
447
- }
448
468
  const { minBpPerPx = 0, maxBpPerPx = 0 } = mark;
449
469
  if (minBpPerPx > 0 && maxBpPerPx > 0 && minBpPerPx >= maxBpPerPx) {
450
470
  problems.push(found('empty-zoom-range', 'minBpPerPx', `never draws: minBpPerPx ${minBpPerPx} is not below maxBpPerPx ${maxBpPerPx}`));
@@ -454,8 +474,19 @@ function ownProblems(mark, display, section) {
454
474
  problems.push(found('two-packings', 'transform', `packs rows of its own over the ${packsIn(section) ? "facet's" : "display's"} pileup, and the two share row numbers; one pileup packs every mark`));
455
475
  }
456
476
  const fields = madeFields([...display, ...section, ...stepsOf(mark)]);
457
- if (fields && y && !isJexl(y) && !fields.has(y)) {
458
- problems.push(found('unwritten-y', 'encoding.y', `reads "${y}", which no step before it writes; they leave ${[...fields].join(', ')}`));
477
+ if (fields) {
478
+ if (split) {
479
+ fields.add(split);
480
+ }
481
+ const leaves = `which no step before it writes; they leave ${[...fields].join(', ')}`;
482
+ if (y && !isJexl(y) && !fields.has(y)) {
483
+ problems.push(found('unwritten-y', 'encoding.y', `reads "${y}", ${leaves}`));
484
+ }
485
+ for (const [slot, field] of channelFields(mark, spec)) {
486
+ if (!fields.has(field)) {
487
+ problems.push(found('unwritten-field', slot, `reads "${field}", ${leaves}`));
488
+ }
489
+ }
459
490
  }
460
491
  return problems;
461
492
  }
@@ -468,6 +499,13 @@ function ownProblems(mark, display, section) {
468
499
  export function markProblems({ marks, facet, transform = [], rows, scales, }) {
469
500
  const faceted = named(facet?.field);
470
501
  const drawsRows = named(rows?.field) && !faceted;
502
+ // the field the sections or rows are split on, which every section's rows
503
+ // keep through the steps that make rows
504
+ const split = faceted
505
+ ? String(facet?.field)
506
+ : drawsRows
507
+ ? String(rows?.field)
508
+ : undefined;
471
509
  const section = readable(facet?.transform ?? []);
472
510
  const display = readable(transform);
473
511
  const shared = [...display, ...section];
@@ -489,7 +527,10 @@ export function markProblems({ marks, facet, transform = [], rows, scales, }) {
489
527
  : []),
490
528
  ...(drawsRows ? packingsUnderRows(marks, transform, section) : []),
491
529
  ...marks.flatMap((mark, i) => mark
492
- ? ownProblems(mark, display, section).map(p => ({ mark: i, ...p }))
530
+ ? ownProblems(mark, display, section, split).map(p => ({
531
+ mark: i,
532
+ ...p,
533
+ }))
493
534
  : []),
494
535
  ];
495
536
  for (const [i, mark] of marks.entries()) {
@@ -12,46 +12,39 @@ export const MARK_SPECS = {
12
12
  bar: {
13
13
  channels: ['y', 'row', 'color'],
14
14
  value: 'required',
15
- ramp: 'display',
16
15
  hit: 'rows',
17
16
  },
18
17
  point: {
19
18
  channels: ['y', 'row', 'color', 'shape'],
20
19
  value: 'required',
21
- ramp: 'display',
22
20
  hit: 'index',
23
21
  size: 'constant',
24
22
  },
25
23
  rule: {
26
24
  channels: ['y', 'row', 'color'],
27
25
  value: 'required',
28
- ramp: 'display',
29
26
  hit: 'rows',
30
27
  size: 'constant',
31
28
  },
32
29
  line: {
33
30
  channels: ['y', 'row', 'color'],
34
31
  value: 'required',
35
- ramp: 'display',
36
32
  hit: 'rows',
37
33
  size: 'constant',
38
34
  },
39
35
  span: {
40
36
  channels: ['row', 'color'],
41
37
  value: 'none',
42
- ramp: 'display',
43
38
  hit: 'rows',
44
39
  },
45
40
  text: {
46
41
  channels: ['y', 'row', 'color', 'text'],
47
42
  value: 'optional',
48
- ramp: 'worker',
49
43
  hit: false,
50
44
  },
51
45
  link: {
52
46
  channels: ['y', 'row', 'color', 'size'],
53
47
  value: 'optional',
54
- ramp: 'display',
55
48
  hit: 'index',
56
49
  farFoot: true,
57
50
  size: 'channel',
@@ -72,23 +65,18 @@ export function plotsValue(type) {
72
65
  export function hitsByIndex(type) {
73
66
  return specOf(type).hit === 'index';
74
67
  }
75
- /** Whether a mark type's ramp colour resolves per region, in the worker. */
76
- export function rampResolvesPerRegion(type) {
77
- return specOf(type).ramp === 'worker';
78
- }
79
68
  /**
80
- * The lanes a mark asks the worker to fill: its type's channels, a ramp's raw
81
- * values beside the colour where the display resolves the ramp, and the hit
82
- * index where the mark answers a hover through one. The encoder fills whichever of
83
- * `color` and `colorValue` the colour declaration calls for.
69
+ * The lanes a mark asks the worker to fill: its type's channels, the colour
70
+ * lanes `colorLanesOf` chose for its declaration, and the hit index where the
71
+ * mark answers a hover through one.
84
72
  */
85
- export function markLanes(type) {
73
+ export function markLanes(type, colorLanes) {
86
74
  const spec = specOf(type);
87
75
  return [
88
76
  ...spec.channels.flatMap((channel) => channel === 'shape'
89
77
  ? ['glyph']
90
- : channel === 'color' && spec.ramp === 'display'
91
- ? [channel, 'colorValue']
78
+ : channel === 'color'
79
+ ? colorLanes
92
80
  : [channel]),
93
81
  ...(spec.farFoot ? ['x2Ref'] : []),
94
82
  ...(hitsByIndex(type) ? ['index'] : []),
@@ -26,6 +26,8 @@ export const DEFAULT_LINK_SHAPE = 'dome';
26
26
  export const DEFAULT_LINK_STROKE_PX = 2;
27
27
  /** The fraction of its row a span fills where its `rowProportion` is left unwritten. */
28
28
  export const DEFAULT_ROW_PROPORTION = 1;
29
+ /** The cuts a threshold colour paints, render-core's `MAX_COLOR_CUTS`. */
30
+ export const MAX_THRESHOLD_CUTS = 8;
29
31
  export const SIZE_SCALES = ['linear', 'log'];
30
32
  export const MARK_SOURCES = ['features', 'density'];
31
33
  export const DEFAULT_MARK_SOURCE = 'features';
@@ -8,6 +8,7 @@
8
8
  // loading normally with the setting doing nothing.
9
9
  //
10
10
  // Pure: no filesystem, no process exit. The command wrapper owns both.
11
+ import { fileNameOf, isLooseTrackConfig, matchFormat, } from '@jbrowse/add-track-core';
11
12
  import { configManifest } from './configManifest.generated.js';
12
13
  import { displayDefaultsForTrackType } from './displayDefaultKeys.js';
13
14
  import { isRecord, liftToSnapshot } from './liftConfig.js';
@@ -103,7 +104,7 @@ function checkPluggable(obj, group, groupLabel, where, report) {
103
104
  }
104
105
  function checkTrack(track, index, manifest, report, ctx) {
105
106
  const where = `tracks[${index}]`;
106
- const loose = typeof track.uri === 'string' && !('adapter' in track);
107
+ const loose = isLooseTrackConfig(track);
107
108
  const trackId = track.trackId;
108
109
  if (typeof trackId === 'string' && trackId) {
109
110
  if (ctx.seenTrackIds.has(trackId)) {
@@ -129,6 +130,19 @@ function checkTrack(track, index, manifest, report, ctx) {
129
130
  }
130
131
  }
131
132
  }
133
+ if (loose) {
134
+ const file = fileNameOf(track.uri);
135
+ const spec = matchFormat(file)?.spec;
136
+ if (!spec || !('adapterType' in spec)) {
137
+ const message = `JBrowse infers no track from "${file}", so the track fails to load: give it an "adapter"`;
138
+ if (ctx.declaresPlugins) {
139
+ report.warn(`${where}.uri`, `${message}, unless a plugin it declares guesses this extension`);
140
+ }
141
+ else {
142
+ report.error(`${where}.uri`, message);
143
+ }
144
+ }
145
+ }
132
146
  checkPluggable(track, manifest.tracks, 'track', where, report);
133
147
  if (!loose) {
134
148
  checkPluggable(track.adapter, manifest.adapters, 'adapter', `${where}.adapter`, report);
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const version = '5.0.0-beta.10';
1
+ export const version = '5.0.0-beta.11';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/cli",
3
- "version": "5.0.0-beta.10",
3
+ "version": "5.0.0-beta.11",
4
4
  "type": "module",
5
5
  "description": "A command line tool for working with JBrowse 2",
6
6
  "keywords": [
@@ -31,9 +31,9 @@
31
31
  "cli-progress": "^3.12.0",
32
32
  "serve-handler": "^6.1.7",
33
33
  "tmp": "^0.2.7",
34
- "@jbrowse/add-track-core": "^5.0.0-beta.10",
35
- "@jbrowse/cigar-utils": "^5.0.0-beta.10",
36
- "@jbrowse/text-indexing-core": "^5.0.0-beta.10"
34
+ "@jbrowse/add-track-core": "^5.0.0-beta.11",
35
+ "@jbrowse/text-indexing-core": "^5.0.0-beta.11",
36
+ "@jbrowse/cigar-utils": "^5.0.0-beta.11"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"