@jbrowse/plugin-gff3 5.0.0-beta.1 → 5.0.0-beta.10

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.
@@ -22,17 +22,16 @@ export default class Gff3Adapter extends BaseFeatureDataAdapter {
22
22
  // that resident set small (8.5x on GENCODE-shaped input), and the
23
23
  // render path reads only a handful of attributes anyway — see
24
24
  // Gff3Feature.
25
- (lines, refName) => {
26
- const features = parseLinesLazy(lines);
27
- // stamped in place rather than through `{...feature, uniqueId}`:
28
- // these are freshly parsed objects nobody else holds, and the spread
29
- // copied every attribute of every top-level feature in the file to
30
- // add one key
31
- for (let i = 0; i < features.length; i++) {
32
- features[i].uniqueId = `${this.id}-${refName}-${i}`;
33
- }
34
- return features;
35
- }, 'Parsing GFF data');
25
+ //
26
+ // The id the tree entry carries is minted here, beside the feature
27
+ // rather than stamped onto it, so the parsed feature is the library's
28
+ // shape and Gff3Feature serializes it identically for both adapters.
29
+ (lines, refName) => parseLinesLazy(lines).map((feature, i) => ({
30
+ start: feature.start,
31
+ end: feature.end,
32
+ feature,
33
+ uniqueId: `${this.id}-${refName}-${i}`,
34
+ })), 'Parsing GFF data');
36
35
  return { header: headerLines.join('\n'), intervalTreeMap };
37
36
  },
38
37
  });
@@ -52,11 +51,14 @@ export default class Gff3Adapter extends BaseFeatureDataAdapter {
52
51
  const { intervalTreeMap } = await this.loadData(opts);
53
52
  const tree = intervalTreeMap[refName];
54
53
  if (tree) {
55
- for (const f of tree(opts.statusCallback).search([start, end])) {
56
- observer.next(new Gff3Feature(f, f.uniqueId));
54
+ for (const { feature, uniqueId } of tree(opts.statusCallback).search([
55
+ start,
56
+ end,
57
+ ])) {
58
+ observer.next(new Gff3Feature(feature, uniqueId));
57
59
  }
58
60
  }
59
61
  observer.complete();
60
- }, opts.stopToken);
62
+ }, opts.signal);
61
63
  }
62
64
  }
@@ -17,18 +17,16 @@ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record
17
17
  * ```
18
18
  */
19
19
  declare const Gff3Adapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
20
- /**
21
- * #slot
22
- * location of the GFF3 file. May be gzipped; it is decompressed and parsed
23
- * in full on first use, so the file has to fit in memory.
24
- */
20
+ type: {
21
+ type: "string";
22
+ } & {
23
+ defaultValue: string;
24
+ };
25
25
  readonly gffLocation: {
26
- readonly type: "fileLocation";
27
- readonly defaultValue: {
28
- readonly uri: "/path/to/my.gff";
29
- readonly locationType: "UriLocation";
30
- };
26
+ type: "fileLocation";
27
+ } & {
28
+ defaultValue: unknown;
31
29
  };
32
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
30
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
33
31
  export type Gff3AdapterConfig = Instance<typeof Gff3Adapter>;
34
32
  export default Gff3Adapter;
@@ -1,14 +1,6 @@
1
- import { ConfigurationSchema } from '@jbrowse/core/configuration';
1
+ import { ConfigurationSchema, expandUriShorthand, } from '@jbrowse/core/configuration';
2
2
  export function normalizeSnapshot(snap) {
3
- return snap.uri
4
- ? {
5
- ...snap,
6
- gffLocation: {
7
- uri: snap.uri,
8
- baseUri: snap.baseUri,
9
- },
10
- }
11
- : snap;
3
+ return expandUriShorthand(snap, 'gffLocation');
12
4
  }
13
5
  /**
14
6
  * #config Gff3Adapter
@@ -1,9 +1,5 @@
1
1
  import type { Feature, SimpleFeatureSerialized } from '@jbrowse/core/util/simpleFeature';
2
2
  import type { LazyGffFeature } from 'gff-nostream';
3
- /** A parsed GFF3 feature carrying the id the adapter minted for it. */
4
- export type IdentifiedGffFeature = LazyGffFeature & {
5
- uniqueId: string;
6
- };
7
3
  /**
8
4
  * A {@link Feature} over a GFF3 feature whose attributes are still raw column-9
9
5
  * text, resolving each one only when something asks for it.
@@ -26,7 +22,7 @@ export declare class Gff3Feature implements Feature {
26
22
  private uniqueId;
27
23
  private parentFeature?;
28
24
  private inflated?;
29
- constructor(data: IdentifiedGffFeature | LazyGffFeature, uniqueId: string, parentFeature?: Feature | undefined);
25
+ constructor(data: LazyGffFeature, uniqueId: string, parentFeature?: Feature | undefined);
30
26
  /**
31
27
  * A switch rather than a lookup table or a `data[name]` fallthrough: the
32
28
  * fixed columns are read tens of times per feature by the layout pass, and
@@ -1,13 +1,12 @@
1
1
  import { TabixIndexedFile } from '@gmod/tabix';
2
2
  import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
3
3
  import { downloadStatus } from '@jbrowse/core/util';
4
- import { sharedBgzfWorkerPool } from '@jbrowse/core/util/bgzfWorkerPool';
5
4
  import { decompressedBytesBudget } from '@jbrowse/core/util/cacheBudgets';
6
5
  import { openLocation, openTabixIndexFilehandle } from '@jbrowse/core/util/io';
7
6
  import { doesIntersect2 } from '@jbrowse/core/util/range';
8
7
  import { ObservableCreate } from '@jbrowse/core/util/rxjs';
9
8
  import { readTabixLinesRedispatched } from '@jbrowse/core/util/tabix';
10
- import { parseRecordsLazy } from 'gff-nostream';
9
+ import { hasIdAttribute, parseRecordsLazy } from 'gff-nostream';
11
10
  import { Gff3Feature } from '../Gff3Feature.js';
12
11
  export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
13
12
  configure = cachedSetup({
@@ -17,14 +16,13 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
17
16
  filehandle: openLocation(this.getConf('gffGzLocation'), this.pluginManager),
18
17
  ...openTabixIndexFilehandle(this.getConf(['index', 'location']), this.getConf(['index', 'indexType']), this.pluginManager),
19
18
  chunkCacheBudget: decompressedBytesBudget,
20
- bgzfWorkerPool: sharedBgzfWorkerPool(),
21
19
  });
20
+ // the index is a whole-file read, so its byte ticks turn the
21
+ // "Downloading index" label into a determinate bar
22
+ await gff.getReferenceSequenceNames({ onProgress });
22
23
  return {
23
24
  gff,
24
25
  dontRedispatchSet: new Set(this.getConf('dontRedispatch')),
25
- // the index is a whole-file read, so its byte ticks turn the
26
- // "Downloading index" label into a determinate bar
27
- header: await gff.getHeader({ onProgress }),
28
26
  };
29
27
  },
30
28
  });
@@ -33,8 +31,8 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
33
31
  return downloadStatus('Downloading index', opts.statusCallback, onProgress => gff.getReferenceSequenceNames({ ...opts, onProgress }));
34
32
  }
35
33
  async getHeader(opts = {}) {
36
- const { header } = await this.configure(opts);
37
- return header;
34
+ const { gff } = await this.configure(opts);
35
+ return gff.getHeader(opts);
38
36
  }
39
37
  // Index-only compressed-byte estimate (no feature download), used by the
40
38
  // feature-fetch RPC to short-circuit an over-budget region before pulling
@@ -47,7 +45,26 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
47
45
  return ObservableCreate(async (observer) => {
48
46
  try {
49
47
  const { gff, dontRedispatchSet } = await this.configure(opts);
50
- const lines = await readTabixLinesRedispatched(gff, query, dontRedispatchSet, opts);
48
+ // The bound exists to reach a record's children, so what disqualifies a
49
+ // record is having none. `ID` answers that exactly — nothing can name a
50
+ // parent that has no name — and gff-nostream decides it with the scan
51
+ // its linker uses, so a record the tree would attach children to is
52
+ // never one the bound leaves out. `dontRedispatch` can only approximate
53
+ // the same question by type: every NCBI `GCF_*_genomic.gff.gz` opens
54
+ // each reference with a chromosome-long `match` record no list named,
55
+ // and none of them has an `ID`. The list covers what `ID` cannot see: a
56
+ // record carrying an `ID` that nothing references, which hosted hg19
57
+ // RefSeq's chromosome-long `region` is.
58
+ const canHaveChildren = (line) => hasIdAttribute(line.line) && !dontRedispatchSet.has(line.type);
59
+ const lines = await readTabixLinesRedispatched(gff, query,
60
+ // A caller reading only top-level features is owed nothing by the
61
+ // flanks and pays for them anyway: they complete SUBFEATURE lists, and
62
+ // a top-level feature overlapping the query is in the query's own read
63
+ // already, since tabix returns every overlapping line and a child is
64
+ // contained in its parent. On an NCBI `GCF_*_genomic.gff.gz`, whose
65
+ // chromosome-long `match` widens the bound at every window, that is
66
+ // 193,008 lines parsed to keep 3 features — 2734 ms against 8 ms.
67
+ opts.topLevelOnly ? () => false : canHaveChildren, opts);
51
68
  // emit only top-level features intersecting the original query. the
52
69
  // byte offset stays on our own record and is used purely to mint a
53
70
  // stable id, so it never pollutes the feature's data
@@ -61,6 +78,6 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
61
78
  catch (e) {
62
79
  observer.error(e);
63
80
  }
64
- }, opts.stopToken);
81
+ }, opts.signal);
65
82
  }
66
83
  }
@@ -18,51 +18,38 @@ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record
18
18
  * ```
19
19
  */
20
20
  declare const Gff3TabixAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
21
- /**
22
- * #slot
23
- * location of the bgzip-compressed GFF3, sorted by position. Must be bgzip
24
- * rather than plain gzip, which tabix cannot index.
25
- */
21
+ readonly densityAdapter: {
22
+ type: "maybeFrozen";
23
+ };
24
+ type: {
25
+ type: "string";
26
+ } & {
27
+ defaultValue: string;
28
+ };
26
29
  readonly gffGzLocation: {
27
- readonly type: "fileLocation";
28
- readonly defaultValue: {
29
- readonly uri: "/path/to/my.gff.gz";
30
- readonly locationType: "UriLocation";
31
- };
30
+ type: "fileLocation";
31
+ } & {
32
+ defaultValue: unknown;
32
33
  };
33
34
  readonly index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
34
35
  readonly indexType: {
35
- readonly model: import("@jbrowse/mobx-state-tree").ISimpleType<"CSI" | "TBI">;
36
- readonly type: 'stringEnum';
37
- readonly defaultValue: 'TBI';
38
- readonly description: '`TBI` is the usual `tabix` output. `CSI` is required for a reference longer than 512 Mb, which TBI cannot address.';
36
+ type: "stringEnum";
37
+ } & {
38
+ model: import("@jbrowse/mobx-state-tree").ISimpleType<"CSI" | "TBI">;
39
+ } & {
40
+ defaultValue: string;
39
41
  };
40
42
  readonly location: {
41
- readonly type: 'fileLocation';
42
- readonly defaultValue: {
43
- readonly uri: '/path/to/my.gz.tbi';
44
- readonly locationType: 'UriLocation';
45
- };
46
- readonly description: 'location of the tabix index. Only needed when it is not named `<file>.tbi` (or `.csi`), which is what the `uri` shorthand assumes.';
43
+ type: "fileLocation";
44
+ } & {
45
+ defaultValue: unknown;
47
46
  };
48
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
49
- /**
50
- * #slot
51
- * the Gff3TabixAdapter has to "redispatch" if it fetches a region and
52
- * features it finds inside that region extend outside the region we requested.
53
- * you can disable this for certain feature types to avoid fetching e.g. the
54
- * entire chromosome
55
- *
56
- * the defaults are the whole-sequence records the common GFF3 sources emit:
57
- * `region` (NCBI), `supercontig`/`scaffold` (Ensembl, for non-chromosomal
58
- * sequences), plus `chromosome` and `contig`. They span an entire reference
59
- * and have no children, so letting one expand the fetch would pull a whole
60
- * chromosome to gain nothing
61
- */
47
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
62
48
  readonly dontRedispatch: {
63
- readonly type: "stringArray";
64
- readonly defaultValue: readonly ["chromosome", "region", "contig", "supercontig", "scaffold"];
49
+ type: "stringArray";
50
+ } & {
51
+ defaultValue: unknown;
65
52
  };
66
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
53
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
67
54
  export type Gff3TabixAdapterConfig = Instance<typeof Gff3TabixAdapter>;
68
55
  export default Gff3TabixAdapter;
@@ -1,4 +1,5 @@
1
- import { ConfigurationSchema, expandTabixShorthand, tabixIndexFields, } from '@jbrowse/core/configuration';
1
+ import { ConfigurationSchema, expandTabixShorthand, tabixIndexSchema, } from '@jbrowse/core/configuration';
2
+ import { densityAdapterConfigSchemaFields } from '@jbrowse/core/data_adapters/BaseAdapter';
2
3
  export function normalizeSnapshot(snap) {
3
4
  return expandTabixShorthand(snap, 'gffGzLocation');
4
5
  }
@@ -32,7 +33,12 @@ const Gff3TabixAdapter = ConfigurationSchema('Gff3TabixAdapter', {
32
33
  locationType: 'UriLocation',
33
34
  },
34
35
  },
35
- index: ConfigurationSchema('TabixIndex', { ...tabixIndexFields }),
36
+ /**
37
+ * #slot
38
+ * where the tabix index is and which kind it is. The `uri` shorthand derives
39
+ * both, so a config using it states neither.
40
+ */
41
+ index: tabixIndexSchema(),
36
42
  /**
37
43
  * #slot
38
44
  * the Gff3TabixAdapter has to "redispatch" if it fetches a region and
@@ -56,6 +62,7 @@ const Gff3TabixAdapter = ConfigurationSchema('Gff3TabixAdapter', {
56
62
  'scaffold',
57
63
  ],
58
64
  },
65
+ ...densityAdapterConfigSchemaFields,
59
66
  }, {
60
67
  explicitlyTyped: true,
61
68
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-gff3",
3
- "version": "5.0.0-beta.1",
3
+ "version": "5.0.0-beta.10",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 gff3.",
6
6
  "keywords": [
@@ -21,12 +21,12 @@
21
21
  "esm"
22
22
  ],
23
23
  "dependencies": {
24
- "@gmod/tabix": "^3.8.2",
25
- "@jbrowse/mobx-state-tree": "^6.5.1",
26
- "gff-nostream": "^5.3.0",
27
- "mobx": "^7.0.3",
24
+ "@gmod/tabix": "^3.8.3",
25
+ "@jbrowse/mobx-state-tree": "^6.6.1",
26
+ "gff-nostream": "^5.5.0",
27
+ "mobx": "^7.0.5",
28
28
  "rxjs": "^7.8.2",
29
- "@jbrowse/core": "^5.0.0-beta.1"
29
+ "@jbrowse/core": "^5.0.0-beta.10"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"