@apollo-annotation/mst 0.3.4 → 0.3.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo-annotation/mst",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "main": "./dist/index.js",
5
5
  "scripts": {
6
6
  "build": "tsc"
@@ -1,10 +1,10 @@
1
1
  import { getSession, intersection2 } from '@jbrowse/core/util'
2
2
  import {
3
- IAnyModelType,
4
- IMSTMap,
5
- Instance,
6
- SnapshotIn,
7
- SnapshotOrInstance,
3
+ type IAnyModelType,
4
+ type IMSTMap,
5
+ type Instance,
6
+ type SnapshotIn,
7
+ type SnapshotOrInstance,
8
8
  cast,
9
9
  getParentOfType,
10
10
  getSnapshot,
@@ -23,7 +23,7 @@ export interface TranscriptPartLocation {
23
23
  }
24
24
 
25
25
  export interface TranscriptPartNonCoding extends TranscriptPartLocation {
26
- type: 'fivePrimeUTR' | 'threePrimeUTR' | 'intron'
26
+ type: 'fivePrimeUTR' | 'threePrimeUTR' | 'intron' | 'exon'
27
27
  }
28
28
 
29
29
  export interface TranscriptPartCoding extends TranscriptPartLocation {
@@ -126,6 +126,56 @@ export const AnnotationFeatureModel = types
126
126
  }
127
127
  return false
128
128
  },
129
+ get transcriptExonParts(): TranscriptParts {
130
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
131
+ const session = getSession(self) as any
132
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
133
+ const { apolloDataStore } = session
134
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
135
+ const { featureTypeOntology } = apolloDataStore.ontologyManager
136
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
137
+ if (!featureTypeOntology.isTypeOf(self.type, 'transcript')) {
138
+ throw new Error(
139
+ 'Feature is not a transcript or equivalent, cannot calculate exon locations',
140
+ )
141
+ }
142
+ const children = self.children as Children
143
+ if (!children) {
144
+ throw new Error('No exons in transcript')
145
+ }
146
+ const sortedChildren = [...children.values()]
147
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
148
+ .filter((child) => featureTypeOntology.isTypeOf(child.type, 'exon'))
149
+ .sort((a, b) => a.min - b.min)
150
+ let lastMax = self.min
151
+ const parts: TranscriptParts = []
152
+ for (const child of sortedChildren) {
153
+ if (child.min > lastMax) {
154
+ parts.push({
155
+ min: lastMax,
156
+ max: child.min,
157
+ type: 'intron',
158
+ })
159
+ }
160
+ parts.push({
161
+ min: child.min,
162
+ max: child.max,
163
+ type: 'exon',
164
+ })
165
+ lastMax = child.max
166
+ }
167
+ if (lastMax < self.max) {
168
+ parts.push({
169
+ min: lastMax,
170
+ max: self.max,
171
+ type: 'intron',
172
+ })
173
+ }
174
+ if (self.strand === -1) {
175
+ parts.reverse()
176
+ }
177
+ return parts
178
+ },
129
179
  get transcriptParts(): TranscriptParts[] {
130
180
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
131
181
  const session = getSession(self) as any
@@ -147,10 +197,11 @@ export const AnnotationFeatureModel = types
147
197
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
148
198
  (child) => featureTypeOntology.isTypeOf(child.type, 'CDS'),
149
199
  )
200
+ const transcriptParts: TranscriptParts[] = []
150
201
  if (cdsChildren.length === 0) {
151
- throw new Error('no CDS in transcript')
202
+ transcriptParts.push(this.transcriptExonParts)
203
+ return transcriptParts
152
204
  }
153
- const transcriptParts: TranscriptParts[] = []
154
205
  for (const cds of cdsChildren) {
155
206
  const { max: cdsMax, min: cdsMin } = cds
156
207
  const parts: TranscriptParts = []
@@ -240,6 +291,48 @@ export const AnnotationFeatureModel = types
240
291
  transcript.filter((transcriptPart) => transcriptPart.type === 'CDS'),
241
292
  )
242
293
  },
294
+ get looksLikeGene(): boolean {
295
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
296
+ const session = getSession(self) as any
297
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
298
+ const { apolloDataStore } = session
299
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
300
+ const { featureTypeOntology } = apolloDataStore.ontologyManager
301
+ if (!featureTypeOntology) {
302
+ return false
303
+ }
304
+ const children = self.children as Children
305
+ if (!children?.size) {
306
+ return false
307
+ }
308
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
309
+ const isGene =
310
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
311
+ featureTypeOntology.isTypeOf(self.type, 'gene') ||
312
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
313
+ featureTypeOntology.isTypeOf(self.type, 'pseudogene')
314
+ if (!isGene) {
315
+ return false
316
+ }
317
+ for (const [, child] of children) {
318
+ if (
319
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
320
+ featureTypeOntology.isTypeOf(child.type, 'transcript') ||
321
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
322
+ featureTypeOntology.isTypeOf(child.type, 'pseudogenic_transcript')
323
+ ) {
324
+ const { children: grandChildren } = child
325
+ if (!grandChildren?.size) {
326
+ return false
327
+ }
328
+ return [...grandChildren.values()].some((grandchild) =>
329
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
330
+ featureTypeOntology.isTypeOf(grandchild.type, 'exon'),
331
+ )
332
+ }
333
+ }
334
+ return false
335
+ },
243
336
  }))
244
337
  .actions((self) => ({
245
338
  setAttributes(attributes: Map<string, string[]>) {
@@ -1,4 +1,4 @@
1
- import { Instance, SnapshotIn, types } from 'mobx-state-tree'
1
+ import { type Instance, type SnapshotIn, types } from 'mobx-state-tree'
2
2
 
3
3
  import { ApolloRefSeq } from './ApolloRefSeq'
4
4
 
@@ -1,14 +1,14 @@
1
1
  import { isContainedWithin } from '@jbrowse/core/util'
2
2
  import {
3
- Instance,
4
- SnapshotIn,
5
- SnapshotOrInstance,
3
+ type Instance,
4
+ type SnapshotIn,
5
+ type SnapshotOrInstance,
6
6
  types,
7
7
  } from 'mobx-state-tree'
8
8
 
9
9
  import {
10
10
  AnnotationFeatureModel,
11
- AnnotationFeatureSnapshot,
11
+ type AnnotationFeatureSnapshot,
12
12
  } from './AnnotationFeatureModel'
13
13
 
14
14
  export const Sequence = types.model({
@@ -43,7 +43,9 @@ export const ApolloRefSeq = types
43
43
  },
44
44
  addSequence(seq: SnapshotOrInstance<typeof Sequence>) {
45
45
  if (seq.sequence.length !== seq.stop - seq.start) {
46
- throw new Error('sequence does not match declared length')
46
+ throw new Error(
47
+ `sequence does not match declared length: ${JSON.stringify(seq)}`,
48
+ )
47
49
  }
48
50
  if (self.sequence.length === 0) {
49
51
  self.sequence.push(seq)
@@ -59,7 +61,13 @@ export const ApolloRefSeq = types
59
61
  stop: seq.stop,
60
62
  sequence: seq.sequence,
61
63
  })
62
- newSequences.sort((s1, s2) => s1.start - s2.start)
64
+ newSequences.sort((s1, s2) => {
65
+ if (s1.start === s2.start) {
66
+ return s1.stop - s2.stop
67
+ }
68
+ return s1.start - s2.start
69
+ })
70
+
63
71
  // eslint-disable-next-line unicorn/no-array-reduce
64
72
  const consolidatedSequences = newSequences.reduce<SequenceSnapshot[]>(
65
73
  (result, current) => {
@@ -69,10 +77,9 @@ export const ApolloRefSeq = types
69
77
  }
70
78
  if (lastRange.stop >= current.start) {
71
79
  if (current.stop > lastRange.stop) {
80
+ const overlapLength = lastRange.stop - current.start
72
81
  lastRange.stop = current.stop
73
- lastRange.sequence += current.sequence.slice(
74
- current.stop - lastRange.stop,
75
- )
82
+ lastRange.sequence += current.sequence.slice(overlapLength)
76
83
  }
77
84
  } else {
78
85
  result.push(current)
@@ -81,6 +88,13 @@ export const ApolloRefSeq = types
81
88
  },
82
89
  [],
83
90
  )
91
+ for (const seq of consolidatedSequences) {
92
+ if (seq.sequence.length !== seq.stop - seq.start) {
93
+ throw new Error(
94
+ 'Consolidated sequence does not match declared length',
95
+ )
96
+ }
97
+ }
84
98
  if (
85
99
  self.sequence.length === consolidatedSequences.length &&
86
100
  self.sequence.every(
@@ -1,10 +1,11 @@
1
- import { Instance, SnapshotIn, types } from 'mobx-state-tree'
1
+ import { type Instance, type SnapshotIn, types } from 'mobx-state-tree'
2
2
 
3
3
  import { AnnotationFeatureModel } from './AnnotationFeatureModel'
4
4
 
5
5
  export const CheckResult = types.model('CheckResult', {
6
6
  _id: types.identifier,
7
7
  name: types.string,
8
+ cause: types.string,
8
9
  ids: types.array(types.safeReference(AnnotationFeatureModel)),
9
10
  refSeq: types.string,
10
11
  start: types.number,