@jbrowse/plugin-gtf 4.3.0 → 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.
@@ -1,28 +1,11 @@
1
1
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
- import { IntervalTree } from '@jbrowse/core/util';
2
+ import type { GtfAdapterConfig } from './configSchema.ts';
3
3
  import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
- import type { Feature, SimpleFeatureSerialized } from '@jbrowse/core/util';
4
+ import type { Feature } from '@jbrowse/core/util';
5
5
  import type { Region } from '@jbrowse/core/util/types';
6
- import type { Observer } from 'rxjs';
7
- type StatusCallback = (arg: string) => void;
8
- type SimpleFeat = SimpleFeatureSerialized;
9
- export default class GtfAdapter extends BaseFeatureDataAdapter {
10
- calculatedIntervalTreeMap: Record<string, IntervalTree<SimpleFeat>>;
11
- gtfFeatures?: Promise<{
12
- header: string;
13
- intervalTreeMap: Record<string, (sc?: StatusCallback) => IntervalTree<SimpleFeat>>;
14
- }>;
15
- private loadDataP;
6
+ export default class GtfAdapter extends BaseFeatureDataAdapter<GtfAdapterConfig> {
16
7
  private loadData;
17
8
  getRefNames(opts?: BaseOptions): Promise<string[]>;
18
9
  getHeader(opts?: BaseOptions): Promise<string>;
19
10
  getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
20
- getFeaturesHelper({ query, opts, observer, allowRedispatch, originalQuery, }: {
21
- query: Region;
22
- opts: BaseOptions;
23
- observer: Observer<Feature>;
24
- allowRedispatch: boolean;
25
- originalQuery?: Region;
26
- }): Promise<void>;
27
11
  }
28
- export {};
@@ -1,65 +1,33 @@
1
- import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
- import { IntervalTree, SimpleFeature, doesIntersect2, fetchAndMaybeUnzip, max, min, } from '@jbrowse/core/util';
1
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
2
+ import { SimpleFeature, fetchAndMaybeUnzip } from '@jbrowse/core/util';
3
3
  import { openLocation } from '@jbrowse/core/util/io';
4
- import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
4
+ import { groupLinesByRef, makeFeatureIntervalTreeMap, } from '@jbrowse/core/util/parseLineByLine';
5
5
  import { ObservableCreate } from '@jbrowse/core/util/rxjs';
6
- import { parseStringSync } from 'gtf-nostream';
7
- import { featureData } from "../util.js";
6
+ import { aggregateGtfFeatures, parseGtfToFeatures } from '../util.js';
8
7
  export default class GtfAdapter extends BaseFeatureDataAdapter {
9
- calculatedIntervalTreeMap = {};
10
- gtfFeatures;
11
- async loadDataP(opts) {
12
- const loc = openLocation(this.getConf('gtfLocation'), this.pluginManager);
13
- const buffer = await fetchAndMaybeUnzip(loc, opts);
14
- const headerLines = [];
15
- const featureMap = {};
16
- parseLineByLine(buffer, line => {
17
- if (line.startsWith('#')) {
18
- headerLines.push(line);
19
- }
20
- else if (line.startsWith('>')) {
21
- return false;
22
- }
23
- else {
24
- const ret = line.indexOf('\t');
25
- const refName = line.slice(0, ret);
26
- if (!featureMap[refName]) {
27
- featureMap[refName] = '';
28
- }
29
- featureMap[refName] += `${line}\n`;
30
- }
31
- return true;
32
- }, opts?.statusCallback);
33
- const intervalTreeMap = Object.fromEntries(Object.entries(featureMap).map(([refName, lines]) => [
34
- refName,
35
- (sc) => {
36
- if (!this.calculatedIntervalTreeMap[refName]) {
37
- sc?.('Parsing GTF data');
38
- const intervalTree = new IntervalTree();
39
- for (const obj of parseStringSync(lines)
40
- .flat()
41
- .map((f, i) => featureData(f, `${this.id}-${refName}-${i}`))) {
42
- intervalTree.insert([obj.start, obj.end], obj);
43
- }
44
- this.calculatedIntervalTreeMap[refName] = intervalTree;
45
- }
46
- return this.calculatedIntervalTreeMap[refName];
47
- },
48
- ]));
49
- return {
50
- header: headerLines.join('\n'),
51
- intervalTreeMap,
52
- };
53
- }
54
- async loadData(opts = {}) {
55
- if (!this.gtfFeatures) {
56
- this.gtfFeatures = this.loadDataP(opts).catch((e) => {
57
- this.gtfFeatures = undefined;
58
- throw e;
59
- });
60
- }
61
- return this.gtfFeatures;
62
- }
8
+ // the whole file is resident after one load, so genes are aggregated once
9
+ // here and stored in the interval tree already spanning all their
10
+ // transcripts; getFeatures is then a plain tree search with no per-query
11
+ // aggregation or redispatch. Progress comes from inside the load itself
12
+ // rather than a label wrapped around it
13
+ loadData = cachedSetup({
14
+ setup: async (opts) => {
15
+ const aggregateField = this.getConf('aggregateField');
16
+ const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('gtfLocation'), this.pluginManager), opts);
17
+ const { headerLines, linesByRef } = groupLinesByRef(buffer, opts.statusCallback);
18
+ const intervalTreeMap = makeFeatureIntervalTreeMap(linesByRef, (lines, refName) => aggregateGtfFeatures({
19
+ feats: parseGtfToFeatures(lines.map(line => ({ line })), (_record, i) => `${this.id}-${refName}-${i}`),
20
+ aggregateField,
21
+ refName,
22
+ idPrefix: this.id,
23
+ // whole-ref bounds so nothing is clipped at load; the tree search
24
+ // in getFeatures does the per-query clipping instead
25
+ regionStart: 0,
26
+ regionEnd: Number.MAX_SAFE_INTEGER,
27
+ }), 'Parsing GTF data');
28
+ return { header: headerLines.join('\n'), intervalTreeMap };
29
+ },
30
+ });
63
31
  async getRefNames(opts = {}) {
64
32
  const { intervalTreeMap } = await this.loadData(opts);
65
33
  return Object.keys(intervalTreeMap);
@@ -71,94 +39,21 @@ export default class GtfAdapter extends BaseFeatureDataAdapter {
71
39
  getFeatures(query, opts = {}) {
72
40
  return ObservableCreate(async (observer) => {
73
41
  try {
74
- await this.getFeaturesHelper({
75
- query,
76
- opts,
77
- observer,
78
- allowRedispatch: true,
79
- });
80
- }
81
- catch (e) {
82
- observer.error(e);
83
- }
84
- }, opts.stopToken);
85
- }
86
- async getFeaturesHelper({ query, opts, observer, allowRedispatch, originalQuery = query, }) {
87
- const aggregateField = this.getConf('aggregateField');
88
- const { start, end, refName } = query;
89
- const { intervalTreeMap } = await this.loadData(opts);
90
- const feats = intervalTreeMap[refName]?.(opts.statusCallback).search([
91
- start,
92
- end,
93
- ]);
94
- if (feats) {
95
- if (allowRedispatch && feats.length) {
96
- let minStart = Number.POSITIVE_INFINITY;
97
- let maxEnd = Number.NEGATIVE_INFINITY;
98
- let hasAnyAggregateField = false;
99
- for (const feat of feats) {
100
- if (feat.start < minStart) {
101
- minStart = feat.start;
102
- }
103
- if (feat.end > maxEnd) {
104
- maxEnd = feat.end;
42
+ const { intervalTreeMap } = await this.loadData(opts);
43
+ const tree = intervalTreeMap[query.refName];
44
+ if (tree) {
45
+ for (const feat of tree(opts.statusCallback).search([
46
+ query.start,
47
+ query.end,
48
+ ])) {
49
+ observer.next(new SimpleFeature({ id: feat.uniqueId, data: feat }));
105
50
  }
106
- if (feat[aggregateField]) {
107
- hasAnyAggregateField = true;
108
- }
109
- }
110
- if (hasAnyAggregateField &&
111
- (maxEnd > query.end || minStart < query.start)) {
112
- await this.getFeaturesHelper({
113
- query: {
114
- ...query,
115
- start: minStart - 500_000,
116
- end: maxEnd + 500_000,
117
- },
118
- opts,
119
- observer,
120
- allowRedispatch: false,
121
- originalQuery: query,
122
- });
123
- return;
124
- }
125
- }
126
- const parentAggregation = {};
127
- for (const feat of feats) {
128
- const aggr = feat[aggregateField];
129
- if (!parentAggregation[aggr]) {
130
- parentAggregation[aggr] = [];
131
- }
132
- if (aggr) {
133
- parentAggregation[aggr].push(feat);
134
- }
135
- else {
136
- observer.next(new SimpleFeature({
137
- id: feat.uniqueId,
138
- data: feat,
139
- }));
140
51
  }
52
+ observer.complete();
141
53
  }
142
- for (const [name, subfeatures] of Object.entries(parentAggregation)) {
143
- const s = min(subfeatures.map(f => f.start));
144
- const e = max(subfeatures.map(f => f.end));
145
- if (doesIntersect2(s, e, originalQuery.start, originalQuery.end)) {
146
- const { uniqueId, strand } = subfeatures[0];
147
- observer.next(new SimpleFeature({
148
- id: `${uniqueId}-parent`,
149
- data: {
150
- type: 'gene',
151
- subfeatures,
152
- strand,
153
- name,
154
- start: s,
155
- end: e,
156
- refName: query.refName,
157
- },
158
- }));
159
- }
54
+ catch (e) {
55
+ observer.error(e);
160
56
  }
161
- }
162
- observer.complete();
57
+ }, opts.signal);
163
58
  }
164
59
  }
@@ -1,16 +1,38 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config GtfAdapter
5
+ * #category adapter
6
+ * #trackType FeatureTrack
7
+ * #fileFormat feature | GTF (plain) | Loaded entirely into memory; for small files
8
+ * used to load plain-text GTF files (optionally gzipped). Loads the whole file
9
+ * into memory, so prefer the GtfTabixAdapter for large files.
10
+ *
11
+ * #example
12
+ * The `uri` shorthand works for plain or gzipped GTF:
13
+ * ```js
14
+ * {
15
+ * type: 'GtfAdapter',
16
+ * uri: 'https://example.com/genes.gtf',
17
+ * }
18
+ * ```
19
+ */
1
20
  declare const GtfAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
2
- gtfLocation: {
3
- type: string;
4
- description: string;
5
- defaultValue: {
6
- uri: string;
7
- locationType: string;
8
- };
21
+ type: {
22
+ type: "string";
23
+ } & {
24
+ defaultValue: string;
25
+ };
26
+ readonly gtfLocation: {
27
+ type: "fileLocation";
28
+ } & {
29
+ defaultValue: unknown;
9
30
  };
10
- aggregateField: {
11
- type: string;
12
- description: string;
31
+ readonly aggregateField: {
32
+ type: "string";
33
+ } & {
13
34
  defaultValue: string;
14
35
  };
15
- }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
36
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
37
+ export type GtfAdapterConfig = Instance<typeof GtfAdapter>;
16
38
  export default GtfAdapter;
@@ -1,6 +1,28 @@
1
- import { ConfigurationSchema } from '@jbrowse/core/configuration';
2
- function x() { }
1
+ import { ConfigurationSchema, expandUriShorthand, } from '@jbrowse/core/configuration';
2
+ export function normalizeSnapshot(snap) {
3
+ return expandUriShorthand(snap, 'gtfLocation');
4
+ }
5
+ /**
6
+ * #config GtfAdapter
7
+ * #category adapter
8
+ * #trackType FeatureTrack
9
+ * #fileFormat feature | GTF (plain) | Loaded entirely into memory; for small files
10
+ * used to load plain-text GTF files (optionally gzipped). Loads the whole file
11
+ * into memory, so prefer the GtfTabixAdapter for large files.
12
+ *
13
+ * #example
14
+ * The `uri` shorthand works for plain or gzipped GTF:
15
+ * ```js
16
+ * {
17
+ * type: 'GtfAdapter',
18
+ * uri: 'https://example.com/genes.gtf',
19
+ * }
20
+ * ```
21
+ */
3
22
  const GtfAdapter = ConfigurationSchema('GtfAdapter', {
23
+ /**
24
+ * #slot
25
+ */
4
26
  gtfLocation: {
5
27
  type: 'fileLocation',
6
28
  description: 'path to gtf file, also allows for gzipped gtf',
@@ -9,23 +31,28 @@ const GtfAdapter = ConfigurationSchema('GtfAdapter', {
9
31
  locationType: 'UriLocation',
10
32
  },
11
33
  },
34
+ /**
35
+ * #slot
36
+ */
12
37
  aggregateField: {
13
38
  type: 'string',
14
- description: 'field used to aggregate multiple transcripts into a single parent gene feature',
39
+ description: 'attribute naming the parent gene that transcripts are aggregated into. transcripts are grouped by gene_id where the file has one (gene names are not unique within a reference), so this is the gene label, and the grouping key only for files with no gene_id',
15
40
  defaultValue: 'gene_name',
16
41
  },
17
42
  }, {
18
43
  explicitlyTyped: true,
19
- preProcessSnapshot: snap => {
20
- return snap.uri
21
- ? {
22
- ...snap,
23
- gtfLocation: {
24
- uri: snap.uri,
25
- baseUri: snap.baseUri,
26
- },
27
- }
28
- : snap;
29
- },
44
+ /**
45
+ * #preProcessSnapshot
46
+ *
47
+ *
48
+ * preprocessor to allow minimal config:
49
+ * ```json
50
+ * {
51
+ * "type": "GtfAdapter",
52
+ * "uri": "yourfile.gtf"
53
+ * }
54
+ * ```
55
+ */
56
+ preProcessSnapshot: normalizeSnapshot,
30
57
  });
31
58
  export default GtfAdapter;
@@ -1,10 +1,11 @@
1
1
  import { AdapterType } from '@jbrowse/core/pluggableElementTypes';
2
- import configSchema from "./configSchema.js";
2
+ import configSchema, { normalizeSnapshot } from './configSchema.js';
3
3
  export default function GtfAdapterF(pluginManager) {
4
4
  pluginManager.addAdapterType(() => new AdapterType({
5
5
  name: 'GtfAdapter',
6
6
  displayName: 'GTF adapter',
7
+ normalizeSnapshot,
7
8
  configSchema,
8
- getAdapterClass: () => import("./GtfAdapter.js").then(r => r.default),
9
+ getAdapterClass: () => import('./GtfAdapter.js').then(r => r.default),
9
10
  }));
10
11
  }
@@ -0,0 +1,12 @@
1
+ import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
2
+ import type { GtfTabixAdapterConfig } from './configSchema.ts';
3
+ import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
+ import type { Feature } from '@jbrowse/core/util';
5
+ import type { Region } from '@jbrowse/core/util/types';
6
+ export default class GtfTabixAdapter extends BaseFeatureDataAdapter<GtfTabixAdapterConfig> {
7
+ private configure;
8
+ getRefNames(opts?: BaseOptions): Promise<string[]>;
9
+ getHeader(opts?: BaseOptions): Promise<string>;
10
+ getRegionByteSize(regions: Region[], opts?: BaseOptions): Promise<number>;
11
+ getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
12
+ }
@@ -0,0 +1,77 @@
1
+ import { TabixIndexedFile } from '@gmod/tabix';
2
+ import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
3
+ import { SimpleFeature, downloadStatus } from '@jbrowse/core/util';
4
+ import { decompressedBytesBudget } from '@jbrowse/core/util/cacheBudgets';
5
+ import { openLocation, openTabixIndexFilehandle } from '@jbrowse/core/util/io';
6
+ import { ObservableCreate } from '@jbrowse/core/util/rxjs';
7
+ import { readTabixLinesRedispatched } from '@jbrowse/core/util/tabix';
8
+ import { aggregateGtfFeatures, parseGtfToFeatures } from '../util.js';
9
+ export default class GtfTabixAdapter extends BaseFeatureDataAdapter {
10
+ configure = cachedSetup({
11
+ label: 'Downloading index',
12
+ setup: async (_opts, onProgress) => {
13
+ const gtf = new TabixIndexedFile({
14
+ filehandle: openLocation(this.getConf('gtfGzLocation'), this.pluginManager),
15
+ ...openTabixIndexFilehandle(this.getConf(['index', 'location']), this.getConf(['index', 'indexType']), this.pluginManager),
16
+ chunkCacheBudget: decompressedBytesBudget,
17
+ });
18
+ return {
19
+ gtf,
20
+ dontRedispatchSet: new Set(this.getConf('dontRedispatch')),
21
+ // the index is a whole-file read, so its byte ticks turn the
22
+ // "Downloading index" label into a determinate bar
23
+ header: await gtf.getHeader({ onProgress }),
24
+ };
25
+ },
26
+ });
27
+ async getRefNames(opts = {}) {
28
+ const { gtf } = await this.configure(opts);
29
+ return downloadStatus('Downloading index', opts.statusCallback, onProgress => gtf.getReferenceSequenceNames({ ...opts, onProgress }));
30
+ }
31
+ async getHeader(opts = {}) {
32
+ const { header } = await this.configure(opts);
33
+ return header;
34
+ }
35
+ // Index-only compressed-byte estimate (no feature download), used by the
36
+ // feature-fetch RPC to short-circuit an over-budget region before pulling
37
+ // every line — see executeRenderFeatureData.
38
+ async getRegionByteSize(regions, opts = {}) {
39
+ const { gtf } = await this.configure(opts);
40
+ return gtf.bytesForRegions(regions, opts);
41
+ }
42
+ getFeatures(query, opts = {}) {
43
+ return ObservableCreate(async (observer) => {
44
+ try {
45
+ const { gtf, dontRedispatchSet } = await this.configure(opts);
46
+ // The type list alone, and `opts.topLevelOnly` is deliberately not
47
+ // honoured — both for the same reason. A GTF line has no `ID`/`Parent`,
48
+ // so there is no cheap "can this have children"; and a GTF top-level
49
+ // feature is not a line at all, it is synthesized by
50
+ // `aggregateGtfFeatures` from the transcripts in the FETCHED set, whose
51
+ // span it takes from them. So the argument that lets GFF3 skip the
52
+ // flanks — a top-level feature overlapping the query is already in the
53
+ // query's own read — does not transfer, and a narrower bound could draw
54
+ // a gene short rather than merely flat. Nothing is lost by declining:
55
+ // no GTF record shape makes this bound expensive (the fixtures top out
56
+ // at 19 kb, against GFF3's chromosome-long `match`).
57
+ const lines = await readTabixLinesRedispatched(gtf, query, line => !dontRedispatchSet.has(line.type), opts);
58
+ const feats = parseGtfToFeatures(lines, record => `${this.id}-offset-${record.offset}`);
59
+ const aggregated = aggregateGtfFeatures({
60
+ feats,
61
+ aggregateField: this.getConf('aggregateField'),
62
+ refName: query.refName,
63
+ idPrefix: this.id,
64
+ regionStart: query.start,
65
+ regionEnd: query.end,
66
+ });
67
+ for (const feat of aggregated) {
68
+ observer.next(new SimpleFeature({ id: feat.uniqueId, data: feat }));
69
+ }
70
+ observer.complete();
71
+ }
72
+ catch (e) {
73
+ observer.error(e);
74
+ }
75
+ }, opts.signal);
76
+ }
77
+ }
@@ -0,0 +1,60 @@
1
+ import type { Instance } from '@jbrowse/mobx-state-tree';
2
+ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
3
+ /**
4
+ * #config GtfTabixAdapter
5
+ * #category adapter
6
+ * #trackType FeatureTrack
7
+ * #fileFormat feature | GTF (tabix)
8
+ * used to load bgzip-compressed, tabix-indexed GTF files
9
+ *
10
+ * #example
11
+ * The `uri` shorthand auto-resolves the `.tbi` index; add `csi: true` for a
12
+ * `.csi` index instead:
13
+ * ```js
14
+ * {
15
+ * type: 'GtfTabixAdapter',
16
+ * uri: 'https://example.com/genes.gtf.gz',
17
+ * }
18
+ * ```
19
+ */
20
+ declare const GtfTabixAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
21
+ readonly densityAdapter: {
22
+ type: "maybeFrozen";
23
+ };
24
+ type: {
25
+ type: "string";
26
+ } & {
27
+ defaultValue: string;
28
+ };
29
+ readonly gtfGzLocation: {
30
+ type: "fileLocation";
31
+ } & {
32
+ defaultValue: unknown;
33
+ };
34
+ readonly index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
35
+ readonly indexType: {
36
+ type: "stringEnum";
37
+ } & {
38
+ model: import("@jbrowse/mobx-state-tree").ISimpleType<"CSI" | "TBI">;
39
+ } & {
40
+ defaultValue: string;
41
+ };
42
+ readonly location: {
43
+ type: "fileLocation";
44
+ } & {
45
+ defaultValue: unknown;
46
+ };
47
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
48
+ readonly dontRedispatch: {
49
+ type: "stringArray";
50
+ } & {
51
+ defaultValue: unknown;
52
+ };
53
+ readonly aggregateField: {
54
+ type: "string";
55
+ } & {
56
+ defaultValue: string;
57
+ };
58
+ }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
59
+ export type GtfTabixAdapterConfig = Instance<typeof GtfTabixAdapter>;
60
+ export default GtfTabixAdapter;
@@ -0,0 +1,93 @@
1
+ import { ConfigurationSchema, expandTabixShorthand, tabixIndexSchema, } from '@jbrowse/core/configuration';
2
+ import { densityAdapterConfigSchemaFields } from '@jbrowse/core/data_adapters/BaseAdapter';
3
+ export function normalizeSnapshot(snap) {
4
+ return expandTabixShorthand(snap, 'gtfGzLocation');
5
+ }
6
+ /**
7
+ * #config GtfTabixAdapter
8
+ * #category adapter
9
+ * #trackType FeatureTrack
10
+ * #fileFormat feature | GTF (tabix)
11
+ * used to load bgzip-compressed, tabix-indexed GTF files
12
+ *
13
+ * #example
14
+ * The `uri` shorthand auto-resolves the `.tbi` index; add `csi: true` for a
15
+ * `.csi` index instead:
16
+ * ```js
17
+ * {
18
+ * type: 'GtfTabixAdapter',
19
+ * uri: 'https://example.com/genes.gtf.gz',
20
+ * }
21
+ * ```
22
+ */
23
+ const GtfTabixAdapter = ConfigurationSchema('GtfTabixAdapter', {
24
+ /**
25
+ * #slot
26
+ * location of the bgzip-compressed GTF, sorted by position. Must be bgzip
27
+ * rather than plain gzip, which tabix cannot index.
28
+ */
29
+ gtfGzLocation: {
30
+ type: 'fileLocation',
31
+ defaultValue: {
32
+ uri: '/path/to/my.gtf.gz',
33
+ locationType: 'UriLocation',
34
+ },
35
+ },
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(),
42
+ /**
43
+ * #slot
44
+ * the GtfTabixAdapter has to "redispatch" if it fetches a region and
45
+ * features it finds inside that region extend outside the region we
46
+ * requested. you can disable this for certain feature types to avoid
47
+ * fetching e.g. the entire chromosome
48
+ *
49
+ * the defaults are the whole-sequence records the common annotation sources
50
+ * emit: `region` (NCBI), `supercontig`/`scaffold` (Ensembl, for
51
+ * non-chromosomal sequences), plus `chromosome` and `contig`. They span an
52
+ * entire reference and have no children, so letting one expand the fetch
53
+ * would pull a whole chromosome to gain nothing
54
+ */
55
+ dontRedispatch: {
56
+ type: 'stringArray',
57
+ defaultValue: [
58
+ 'chromosome',
59
+ 'region',
60
+ 'contig',
61
+ 'supercontig',
62
+ 'scaffold',
63
+ ],
64
+ },
65
+ /**
66
+ * #slot
67
+ */
68
+ aggregateField: {
69
+ type: 'string',
70
+ description: 'attribute naming the parent gene that transcripts are aggregated into. transcripts are grouped by gene_id where the file has one (gene names are not unique within a reference), so this is the gene label, and the grouping key only for files with no gene_id',
71
+ defaultValue: 'gene_name',
72
+ },
73
+ ...densityAdapterConfigSchemaFields,
74
+ }, {
75
+ explicitlyTyped: true,
76
+ /**
77
+ * #preProcessSnapshot
78
+ *
79
+ *
80
+ * preprocessor to allow minimal config, assumes tbi index at
81
+ * yourfile.gtf.gz.tbi (or .csi if csi:true):
82
+ *
83
+ * ```json
84
+ * {
85
+ * "type": "GtfTabixAdapter",
86
+ * "uri": "yourfile.gtf.gz",
87
+ * "csi": true
88
+ * }
89
+ * ```
90
+ */
91
+ preProcessSnapshot: normalizeSnapshot,
92
+ });
93
+ export default GtfTabixAdapter;
@@ -0,0 +1,2 @@
1
+ import type PluginManager from '@jbrowse/core/PluginManager';
2
+ export default function GtfTabixAdapterF(pluginManager: PluginManager): void;
@@ -0,0 +1,11 @@
1
+ import { AdapterType } from '@jbrowse/core/pluggableElementTypes';
2
+ import configSchema, { normalizeSnapshot } from './configSchema.js';
3
+ export default function GtfTabixAdapterF(pluginManager) {
4
+ pluginManager.addAdapterType(() => new AdapterType({
5
+ name: 'GtfTabixAdapter',
6
+ displayName: 'GTF tabix adapter',
7
+ normalizeSnapshot,
8
+ configSchema,
9
+ getAdapterClass: () => import('./GtfTabixAdapter.js').then(r => r.default),
10
+ }));
11
+ }
package/esm/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import Plugin from '@jbrowse/core/Plugin';
2
- import GtfAdapterF from "./GtfAdapter/index.js";
3
- import GuessAdapterF from "./GuessAdapter/index.js";
2
+ import GtfAdapterF from './GtfAdapter/index.js';
3
+ import GtfTabixAdapterF from './GtfTabixAdapter/index.js';
4
4
  export default class GtfPlugin extends Plugin {
5
5
  name = 'GTFPlugin';
6
6
  install(pluginManager) {
7
7
  GtfAdapterF(pluginManager);
8
- GuessAdapterF(pluginManager);
8
+ GtfTabixAdapterF(pluginManager);
9
9
  }
10
10
  }