@apollo-annotation/shared 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.
Files changed (86) hide show
  1. package/dist/Changes/AddAssemblyAndFeaturesFromFileChange.d.ts +1 -1
  2. package/dist/Changes/AddAssemblyFromExternalChange.d.ts +1 -1
  3. package/dist/Changes/AddAssemblyFromFileChange.d.ts +1 -1
  4. package/dist/Changes/AddAssemblyFromFileChange.js +3 -3
  5. package/dist/Changes/AddAssemblyFromFileChange.js.map +1 -1
  6. package/dist/Changes/AddFeatureChange.d.ts +2 -2
  7. package/dist/Changes/AddFeatureChange.js +1 -0
  8. package/dist/Changes/AddFeatureChange.js.map +1 -1
  9. package/dist/Changes/AddFeaturesFromFileChange.d.ts +1 -1
  10. package/dist/Changes/AddRefSeqAliasesChange.d.ts +1 -1
  11. package/dist/Changes/DeleteAssemblyChange.d.ts +1 -1
  12. package/dist/Changes/DeleteFeatureChange.d.ts +3 -3
  13. package/dist/Changes/DeleteUserChange.d.ts +1 -1
  14. package/dist/Changes/FeatureAttributeChange.d.ts +1 -1
  15. package/dist/Changes/FromFileBaseChange.d.ts +3 -3
  16. package/dist/Changes/FromFileBaseChange.js.map +1 -1
  17. package/dist/Changes/ImportJBrowseConfigChange.d.ts +1 -1
  18. package/dist/Changes/LocationEndChange.d.ts +1 -1
  19. package/dist/Changes/LocationStartChange.d.ts +1 -1
  20. package/dist/Changes/StrandChange.d.ts +1 -1
  21. package/dist/Changes/TypeChange.d.ts +1 -1
  22. package/dist/Changes/UserChange.d.ts +1 -1
  23. package/dist/Checks/CDSCheck.d.ts +2 -1
  24. package/dist/Checks/CDSCheck.js +98 -30
  25. package/dist/Checks/CDSCheck.js.map +1 -1
  26. package/dist/GFF3/annotationFeatureToGFF3.d.ts +2 -2
  27. package/dist/GFF3/annotationFeatureToGFF3.js +2 -0
  28. package/dist/GFF3/annotationFeatureToGFF3.js.map +1 -1
  29. package/dist/GFF3/annotationFeatureToGFF3.test.js +1 -1
  30. package/dist/GFF3/annotationFeatureToGFF3.test.js.map +1 -1
  31. package/dist/GFF3/gff3ToAnnotationFeature.d.ts +2 -2
  32. package/dist/GFF3/gff3ToAnnotationFeature.js +9 -2
  33. package/dist/GFF3/gff3ToAnnotationFeature.js.map +1 -1
  34. package/dist/GFF3/gff3ToAnnotationFeature.test.d.ts +1 -1
  35. package/dist/GFF3/gff3ToAnnotationFeature.test.js +1 -1
  36. package/dist/GFF3/gff3ToAnnotationFeature.test.js.map +1 -1
  37. package/dist/GFF3/gffReservedKeys.d.ts +7 -0
  38. package/dist/GFF3/gffReservedKeys.js +21 -1
  39. package/dist/GFF3/gffReservedKeys.js.map +1 -1
  40. package/dist/Messages.d.ts +2 -2
  41. package/dist/Operations/GetAssembliesOperation.d.ts +1 -1
  42. package/dist/Operations/GetFeaturesOperation.d.ts +1 -1
  43. package/dist/Validations/CoreValidation.d.ts +2 -2
  44. package/dist/Validations/CoreValidation.js +1 -1
  45. package/dist/Validations/CoreValidation.js.map +1 -1
  46. package/dist/Validations/ParentChildValidation.d.ts +5 -5
  47. package/dist/Validations/ParentChildValidation.js.map +1 -1
  48. package/dist/Validations/Validation.d.ts +5 -5
  49. package/dist/Validations/ValidationSet.d.ts +4 -4
  50. package/dist/Validations/ValidationSet.js.map +1 -1
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +4 -4
  53. package/src/Changes/AddAssemblyAndFeaturesFromFileChange.ts +6 -6
  54. package/src/Changes/AddAssemblyFromExternalChange.ts +5 -5
  55. package/src/Changes/AddAssemblyFromFileChange.ts +8 -8
  56. package/src/Changes/AddFeatureChange.ts +7 -6
  57. package/src/Changes/AddFeaturesFromFileChange.ts +6 -6
  58. package/src/Changes/AddRefSeqAliasesChange.ts +6 -6
  59. package/src/Changes/DeleteAssemblyChange.ts +4 -4
  60. package/src/Changes/DeleteFeatureChange.ts +7 -7
  61. package/src/Changes/DeleteUserChange.ts +5 -5
  62. package/src/Changes/FeatureAttributeChange.ts +6 -6
  63. package/src/Changes/FromFileBaseChange.ts +6 -3
  64. package/src/Changes/ImportJBrowseConfigChange.ts +4 -4
  65. package/src/Changes/LocationEndChange.ts +6 -6
  66. package/src/Changes/LocationStartChange.ts +6 -6
  67. package/src/Changes/StrandChange.ts +6 -6
  68. package/src/Changes/TypeChange.ts +6 -6
  69. package/src/Changes/UserChange.ts +5 -5
  70. package/src/Checks/CDSCheck.ts +113 -32
  71. package/src/GFF3/annotationFeatureToGFF3.test.ts +4 -2
  72. package/src/GFF3/annotationFeatureToGFF3.ts +6 -4
  73. package/src/GFF3/gff3ToAnnotationFeature.test.ts +3 -3
  74. package/src/GFF3/gff3ToAnnotationFeature.ts +11 -2
  75. package/src/GFF3/gffReservedKeys.ts +25 -0
  76. package/src/Messages.ts +2 -2
  77. package/src/Operations/GetAssembliesOperation.ts +3 -3
  78. package/src/Operations/GetFeaturesOperation.ts +4 -4
  79. package/src/Validations/CoreValidation.ts +4 -3
  80. package/src/Validations/ParentChildValidation.ts +7 -6
  81. package/src/Validations/Validation.ts +5 -5
  82. package/src/Validations/ValidationSet.ts +8 -4
  83. package/test_data/example01.json +3 -3
  84. package/test_data/example02.json +3 -3
  85. package/test_data/example04.json +3 -3
  86. package/test_data/gene_representations.gff3 +686 -1686
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo-annotation/shared",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "main": "./dist/index.js",
5
5
  "scripts": {
6
6
  "build": "yarn clean && tsc --build",
@@ -10,9 +10,9 @@
10
10
  "test:ci": "NODE_V8_COVERAGE=./coverage glob -c \"tsx --test --test-reporter spec --experimental-test-coverage \" \"**/*.test.ts\""
11
11
  },
12
12
  "dependencies": {
13
- "@apollo-annotation/common": "^0.3.4",
14
- "@apollo-annotation/mst": "^0.3.4",
15
- "@apollo-annotation/schemas": "^0.3.4",
13
+ "@apollo-annotation/common": "^0.3.6",
14
+ "@apollo-annotation/mst": "^0.3.6",
15
+ "@apollo-annotation/schemas": "^0.3.6",
16
16
  "@gmod/gff": "1.2.0",
17
17
  "@gmod/indexedfasta": "^2.0.4",
18
18
  "@jbrowse/core": "^3.0.1",
@@ -1,13 +1,13 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
2
 
3
3
  import {
4
- ChangeOptions,
5
- ClientDataStore,
6
- LocalGFF3DataStore,
7
- SerializedAssemblySpecificChange,
8
- ServerDataStore,
4
+ type ChangeOptions,
5
+ type ClientDataStore,
6
+ type LocalGFF3DataStore,
7
+ type SerializedAssemblySpecificChange,
8
+ type ServerDataStore,
9
9
  } from '@apollo-annotation/common'
10
- import { GFF3Feature } from '@gmod/gff'
10
+ import { type GFF3Feature } from '@gmod/gff'
11
11
 
12
12
  import { FromFileBaseChange } from './FromFileBaseChange'
13
13
 
@@ -4,11 +4,11 @@
4
4
  /* eslint-disable @typescript-eslint/require-await */
5
5
  import {
6
6
  AssemblySpecificChange,
7
- ChangeOptions,
8
- ClientDataStore,
9
- LocalGFF3DataStore,
10
- SerializedAssemblySpecificChange,
11
- ServerDataStore,
7
+ type ChangeOptions,
8
+ type ClientDataStore,
9
+ type LocalGFF3DataStore,
10
+ type SerializedAssemblySpecificChange,
11
+ type ServerDataStore,
12
12
  } from '@apollo-annotation/common'
13
13
  import { BgzipIndexedFasta, IndexedFasta } from '@gmod/indexedfasta'
14
14
  import { RemoteFile } from 'generic-filehandle'
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/restrict-template-expressions */
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  import {
4
- ChangeOptions,
5
- ClientDataStore,
6
- LocalGFF3DataStore,
7
- SerializedAssemblySpecificChange,
8
- ServerDataStore,
4
+ type ChangeOptions,
5
+ type ClientDataStore,
6
+ type LocalGFF3DataStore,
7
+ type SerializedAssemblySpecificChange,
8
+ type ServerDataStore,
9
9
  } from '@apollo-annotation/common'
10
10
  import { BgzipIndexedFasta } from '@gmod/indexedfasta'
11
11
 
@@ -100,19 +100,19 @@ export class AddAssemblyFromFileChange extends FromFileBaseChange {
100
100
  const faDoc = await fileModel.findById(faId)
101
101
  const faChecksum = faDoc?.checksum
102
102
  if (!faChecksum) {
103
- throw new Error(`No checksum for file document ${faDoc}`)
103
+ throw new Error(`No checksum for file document ${faDoc?.id}`)
104
104
  }
105
105
 
106
106
  const faiDoc = await fileModel.findById(faiId)
107
107
  const faiChecksum = faiDoc?.checksum
108
108
  if (!faiChecksum) {
109
- throw new Error(`No checksum for file document ${faiDoc}`)
109
+ throw new Error(`No checksum for file document ${faiDoc?.id}`)
110
110
  }
111
111
 
112
112
  const gziDoc = await fileModel.findById(gziId)
113
113
  const gziChecksum = gziDoc?.checksum
114
114
  if (!gziChecksum) {
115
- throw new Error(`No checksum for file document ${gziDoc}`)
115
+ throw new Error(`No checksum for file document ${gziDoc?.id}`)
116
116
  }
117
117
 
118
118
  const fasta = filesService.getFileHandle(faDoc)
@@ -3,14 +3,14 @@
3
3
  /* eslint-disable @typescript-eslint/require-await */
4
4
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
5
5
  import {
6
- ChangeOptions,
7
- ClientDataStore,
6
+ type ChangeOptions,
7
+ type ClientDataStore,
8
8
  FeatureChange,
9
- LocalGFF3DataStore,
10
- SerializedFeatureChange,
11
- ServerDataStore,
9
+ type LocalGFF3DataStore,
10
+ type SerializedFeatureChange,
11
+ type ServerDataStore,
12
12
  } from '@apollo-annotation/common'
13
- import { AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
13
+ import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
14
14
 
15
15
  import { DeleteFeatureChange } from './DeleteFeatureChange'
16
16
 
@@ -143,6 +143,7 @@ export class AddFeatureChange extends FeatureChange {
143
143
  }
144
144
  attributes = {
145
145
  _id: [parentFeature._id.toString()],
146
+ // eslint-disable-next-line unicorn/prefer-structured-clone
146
147
  ...JSON.parse(JSON.stringify(attributes)),
147
148
  }
148
149
  parentFeature.attributes = attributes
@@ -1,12 +1,12 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
2
  import {
3
- ChangeOptions,
4
- ClientDataStore,
5
- LocalGFF3DataStore,
6
- SerializedAssemblySpecificChange,
7
- ServerDataStore,
3
+ type ChangeOptions,
4
+ type ClientDataStore,
5
+ type LocalGFF3DataStore,
6
+ type SerializedAssemblySpecificChange,
7
+ type ServerDataStore,
8
8
  } from '@apollo-annotation/common'
9
- import { GFF3Feature } from '@gmod/gff'
9
+ import { type GFF3Feature } from '@gmod/gff'
10
10
 
11
11
  import { FromFileBaseChange } from './FromFileBaseChange'
12
12
 
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  AssemblySpecificChange,
3
- Change,
4
- ChangeOptions,
5
- ClientDataStore,
6
- LocalGFF3DataStore,
7
- SerializedAssemblySpecificChange,
8
- ServerDataStore,
3
+ type Change,
4
+ type ChangeOptions,
5
+ type ClientDataStore,
6
+ type LocalGFF3DataStore,
7
+ type SerializedAssemblySpecificChange,
8
+ type ServerDataStore,
9
9
  } from '@apollo-annotation/common'
10
10
  import { getSession } from '@jbrowse/core/util'
11
11
 
@@ -4,10 +4,10 @@
4
4
  /* eslint-disable @typescript-eslint/no-unsafe-call */
5
5
  import {
6
6
  AssemblySpecificChange,
7
- ClientDataStore,
8
- LocalGFF3DataStore,
9
- SerializedAssemblySpecificChange,
10
- ServerDataStore,
7
+ type ClientDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedAssemblySpecificChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
12
  import { getSession } from '@jbrowse/core/util'
13
13
 
@@ -2,15 +2,15 @@
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
4
4
  import {
5
- ChangeOptions,
6
- ClientDataStore,
5
+ type ChangeOptions,
6
+ type ClientDataStore,
7
7
  FeatureChange,
8
- LocalGFF3DataStore,
9
- SerializedFeatureChange,
10
- ServerDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedFeatureChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
- import { AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
13
- import { Feature } from '@apollo-annotation/schemas'
12
+ import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
13
+ import { type Feature } from '@apollo-annotation/schemas'
14
14
 
15
15
  import { AddFeatureChange } from './AddFeatureChange'
16
16
 
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
2
  import {
3
3
  Change,
4
- ChangeOptions,
5
- ClientDataStore,
6
- LocalGFF3DataStore,
7
- SerializedChange,
8
- ServerDataStore,
4
+ type ChangeOptions,
5
+ type ClientDataStore,
6
+ type LocalGFF3DataStore,
7
+ type SerializedChange,
8
+ type ServerDataStore,
9
9
  } from '@apollo-annotation/common'
10
10
 
11
11
  export interface SerializedDeleteUserChangeBase extends SerializedChange {
@@ -2,14 +2,14 @@
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
4
4
  import {
5
- ChangeOptions,
6
- ClientDataStore,
5
+ type ChangeOptions,
6
+ type ClientDataStore,
7
7
  FeatureChange,
8
- LocalGFF3DataStore,
9
- SerializedFeatureChange,
10
- ServerDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedFeatureChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
- import { Feature, FeatureDocument } from '@apollo-annotation/schemas'
12
+ import { type Feature, type FeatureDocument } from '@apollo-annotation/schemas'
13
13
 
14
14
  interface SerializedFeatureAttributeChangeBase extends SerializedFeatureChange {
15
15
  typeName: 'FeatureAttributeChange'
@@ -5,10 +5,13 @@
5
5
  /* eslint-disable @typescript-eslint/no-unsafe-argument */
6
6
  import {
7
7
  AssemblySpecificChange,
8
- ServerDataStore,
8
+ type ServerDataStore,
9
9
  } from '@apollo-annotation/common'
10
- import { FileDocument, RefSeqDocument } from '@apollo-annotation/schemas'
11
- import { GFF3Feature } from '@gmod/gff'
10
+ import {
11
+ type FileDocument,
12
+ type RefSeqDocument,
13
+ } from '@apollo-annotation/schemas'
14
+ import { type GFF3Feature } from '@gmod/gff'
12
15
 
13
16
  import { gff3ToAnnotationFeature } from '../GFF3'
14
17
 
@@ -1,10 +1,10 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
2
  import {
3
3
  Change,
4
- ChangeOptions,
5
- ClientDataStore,
6
- LocalGFF3DataStore,
7
- ServerDataStore,
4
+ type ChangeOptions,
5
+ type ClientDataStore,
6
+ type LocalGFF3DataStore,
7
+ type ServerDataStore,
8
8
  } from '@apollo-annotation/common'
9
9
 
10
10
  interface JBrowseAssembly {
@@ -2,14 +2,14 @@
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
4
4
  import {
5
- ChangeOptions,
6
- ClientDataStore,
5
+ type ChangeOptions,
6
+ type ClientDataStore,
7
7
  FeatureChange,
8
- LocalGFF3DataStore,
9
- SerializedFeatureChange,
10
- ServerDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedFeatureChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
- import { Feature, FeatureDocument } from '@apollo-annotation/schemas'
12
+ import { type Feature, type FeatureDocument } from '@apollo-annotation/schemas'
13
13
 
14
14
  interface SerializedLocationEndChangeBase extends SerializedFeatureChange {
15
15
  typeName: 'LocationEndChange'
@@ -2,14 +2,14 @@
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
4
4
  import {
5
- ChangeOptions,
6
- ClientDataStore,
5
+ type ChangeOptions,
6
+ type ClientDataStore,
7
7
  FeatureChange,
8
- LocalGFF3DataStore,
9
- SerializedFeatureChange,
10
- ServerDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedFeatureChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
- import { Feature, FeatureDocument } from '@apollo-annotation/schemas'
12
+ import { type Feature, type FeatureDocument } from '@apollo-annotation/schemas'
13
13
 
14
14
  interface SerializedLocationStartChangeBase extends SerializedFeatureChange {
15
15
  typeName: 'LocationStartChange'
@@ -2,14 +2,14 @@
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
4
4
  import {
5
- ChangeOptions,
6
- ClientDataStore,
5
+ type ChangeOptions,
6
+ type ClientDataStore,
7
7
  FeatureChange,
8
- LocalGFF3DataStore,
9
- SerializedFeatureChange,
10
- ServerDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedFeatureChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
- import { Feature, FeatureDocument } from '@apollo-annotation/schemas'
12
+ import { type Feature, type FeatureDocument } from '@apollo-annotation/schemas'
13
13
 
14
14
  interface SerializedStrandChangeBase extends SerializedFeatureChange {
15
15
  typeName: 'StrandChange'
@@ -2,14 +2,14 @@
2
2
  /* eslint-disable @typescript-eslint/require-await */
3
3
  /* eslint-disable @typescript-eslint/no-unnecessary-condition */
4
4
  import {
5
- ChangeOptions,
6
- ClientDataStore,
5
+ type ChangeOptions,
6
+ type ClientDataStore,
7
7
  FeatureChange,
8
- LocalGFF3DataStore,
9
- SerializedFeatureChange,
10
- ServerDataStore,
8
+ type LocalGFF3DataStore,
9
+ type SerializedFeatureChange,
10
+ type ServerDataStore,
11
11
  } from '@apollo-annotation/common'
12
- import { Feature, FeatureDocument } from '@apollo-annotation/schemas'
12
+ import { type Feature, type FeatureDocument } from '@apollo-annotation/schemas'
13
13
 
14
14
  interface SerializedTypeChangeBase extends SerializedFeatureChange {
15
15
  typeName: 'TypeChange'
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/require-await */
2
2
  import {
3
3
  Change,
4
- ChangeOptions,
5
- ClientDataStore,
6
- LocalGFF3DataStore,
7
- SerializedChange,
8
- ServerDataStore,
4
+ type ChangeOptions,
5
+ type ClientDataStore,
6
+ type LocalGFF3DataStore,
7
+ type SerializedChange,
8
+ type ServerDataStore,
9
9
  } from '@apollo-annotation/common'
10
10
 
11
11
  export interface SerializedUserChangeBase extends SerializedChange {
@@ -1,7 +1,7 @@
1
1
  import { Check } from '@apollo-annotation/common'
2
2
  import {
3
- AnnotationFeatureSnapshot,
4
- CheckResultSnapshot,
3
+ type AnnotationFeatureSnapshot,
4
+ type CheckResultSnapshot,
5
5
  } from '@apollo-annotation/mst'
6
6
  import { intersection2 } from '@jbrowse/core/util'
7
7
  import ObjectID from 'bson-objectid'
@@ -12,6 +12,19 @@ enum STOP_CODONS {
12
12
  'TGA',
13
13
  }
14
14
 
15
+ enum START_CODONS {
16
+ 'ATG',
17
+ }
18
+
19
+ const CHECK_NAME = 'CDSCheck'
20
+
21
+ enum CAUSES {
22
+ 'InternalStopCodon',
23
+ 'MissingStartCodon',
24
+ 'MissingStopCodon',
25
+ 'MultipleOfThree',
26
+ }
27
+
15
28
  const iupacComplements: Record<string, string | undefined> = {
16
29
  G: 'C',
17
30
  A: 'T',
@@ -57,10 +70,11 @@ async function getCDSSequence(
57
70
  const sequences = await Promise.all(
58
71
  cdsLocation.map(({ max, min }) => getSequence(min, max)),
59
72
  )
73
+ let seq = sequences.join('')
60
74
  if (strand === -1) {
61
- return sequences.map((seq) => reverseComplement(seq)).join('')
75
+ seq = reverseComplement(seq)
62
76
  }
63
- return sequences.join('')
77
+ return seq
64
78
  }
65
79
 
66
80
  function splitSequenceInCodons(cds: string): string[] {
@@ -71,33 +85,59 @@ function splitSequenceInCodons(cds: string): string[] {
71
85
  return codons
72
86
  }
73
87
 
88
+ function cmp(pos: number, max: number, strand: -1 | 1 | undefined): boolean {
89
+ if (strand === -1) {
90
+ return pos > max
91
+ }
92
+ return pos < max
93
+ }
94
+
74
95
  function getOriginalCodonLocation(
75
96
  cdsLocation: CDSLocation,
76
97
  strand: 1 | -1 | undefined,
77
98
  index: number,
78
99
  ): [number, number] | undefined {
79
- let lengthToStart = index * 3
80
- let lengthToEnd = lengthToStart + 3
81
-
82
- let startLocation: number | undefined = undefined,
83
- endLocation: number | undefined = undefined
84
- for (const loc of cdsLocation) {
85
- const locLength = loc.max - loc.min
86
- if (startLocation === undefined && locLength > lengthToStart) {
87
- startLocation = loc.min + lengthToStart
88
- } else {
89
- lengthToStart -= locLength
90
- }
91
- if (endLocation === undefined && locLength > lengthToEnd) {
92
- endLocation = loc.min + lengthToEnd
93
- } else {
94
- lengthToEnd -= locLength
95
- }
96
- if (startLocation !== undefined && endLocation !== undefined) {
97
- return [startLocation, endLocation]
100
+ // Index 0 is the start codon, so reverse the CDS locations if strand is -1
101
+ const sortedLocation: CDSLocation = structuredClone(cdsLocation)
102
+ if (strand === -1) {
103
+ sortedLocation.sort((a, b) => (a.min < b.min ? 1 : -1))
104
+ } else {
105
+ sortedLocation.sort((a, b) => (a.min < b.min ? -1 : 1))
106
+ }
107
+ let i = 0
108
+ let currentStart: number | undefined = undefined
109
+ let currentEnd: number | undefined = undefined
110
+ for (let iloc = 0; iloc < sortedLocation.length; iloc++) {
111
+ const loc = sortedLocation[iloc]
112
+ const { phase } = loc
113
+ // On the reverse strand start iterating from the right and end on the left
114
+ const startAt = strand === -1 ? loc.max - phase : loc.min + phase
115
+ const endAt = strand === -1 ? loc.min : loc.max
116
+ for (
117
+ let pos = startAt;
118
+ cmp(pos, endAt, strand);
119
+ pos = strand === -1 ? pos - 3 : pos + 3
120
+ ) {
121
+ currentStart = pos
122
+ currentEnd = strand === -1 ? currentStart - 3 : currentStart + 3
123
+ // These if conditions occur if a codon is split between two exons
124
+ if (strand === -1 && currentEnd < loc.min) {
125
+ currentEnd =
126
+ sortedLocation[iloc + 1].max - sortedLocation[iloc + 1].phase
127
+ } else if (currentEnd > loc.max) {
128
+ currentEnd =
129
+ sortedLocation[iloc + 1].min + sortedLocation[iloc + 1].phase
130
+ }
131
+ if (i === index) {
132
+ return [currentStart, currentEnd].sort((a, b) => a - b) as [
133
+ number,
134
+ number,
135
+ ]
136
+ }
137
+ i++
98
138
  }
99
139
  }
100
- return
140
+ return undefined
101
141
  }
102
142
 
103
143
  async function checkMRNA(
@@ -106,7 +146,9 @@ async function checkMRNA(
106
146
  ): Promise<CheckResultSnapshot[]> {
107
147
  const checkResults: CheckResultSnapshot[] = []
108
148
  const { _id, max, min, refSeq, strand } = feature
149
+
109
150
  const cdsLocations = getCDSLocations(feature)
151
+
110
152
  if (!cdsLocations) {
111
153
  return checkResults
112
154
  }
@@ -115,22 +157,46 @@ async function checkMRNA(
115
157
  const sequence = await getCDSSequence(cdsLocation, strand, getSequence)
116
158
  const codons = splitSequenceInCodons(sequence)
117
159
  if (sequence.length % 3 === 0) {
118
- const lastCodon = codons.pop() // Last codon is supposed to be a stop
160
+ const start_codon = codons.at(0)
161
+ if (start_codon && !(start_codon.toUpperCase() in START_CODONS)) {
162
+ let cdsStart =
163
+ strand === -1
164
+ ? cdsLocation.at(-1)?.max ?? max
165
+ : cdsLocation.at(0)?.min ?? min
166
+ cdsStart = strand === -1 ? cdsStart - 3 : cdsStart
167
+ checkResults.push({
168
+ _id: new ObjectID().toHexString(),
169
+ name: CHECK_NAME,
170
+ cause: CAUSES[CAUSES.MissingStartCodon],
171
+ ids,
172
+ refSeq: refSeq.toString(),
173
+ start: cdsStart,
174
+ end: cdsStart,
175
+ message: `Unexpected start codon in feature "${_id}": ${start_codon}`,
176
+ })
177
+ }
178
+ const lastCodon = codons.at(-1) // Last codon is supposed to be a stop
119
179
  if (lastCodon && !(lastCodon.toUpperCase() in STOP_CODONS)) {
180
+ const cdsEnd =
181
+ strand === -1
182
+ ? cdsLocation.at(0)?.min ?? min
183
+ : cdsLocation.at(-1)?.max ?? max
120
184
  checkResults.push({
121
185
  _id: new ObjectID().toHexString(),
122
- name: 'MissingStopCodonCheck',
186
+ name: CHECK_NAME,
187
+ cause: CAUSES[CAUSES.MissingStopCodon],
123
188
  ids,
124
189
  refSeq: refSeq.toString(),
125
- start: max,
126
- end: max,
127
- message: `Missing stop codon`,
190
+ start: cdsEnd,
191
+ end: cdsEnd,
192
+ message: `Missing stop codon for feature "${_id}"`,
128
193
  })
129
194
  }
130
195
  } else {
131
196
  checkResults.push({
132
197
  _id: new ObjectID().toHexString(),
133
- name: 'MultipleOfThreeCheck',
198
+ name: CHECK_NAME,
199
+ cause: CAUSES[CAUSES.MultipleOfThree],
134
200
  ids,
135
201
  refSeq: refSeq.toString(),
136
202
  start: min,
@@ -139,12 +205,17 @@ async function checkMRNA(
139
205
  })
140
206
  }
141
207
  for (const [idx, codon] of codons.entries()) {
208
+ if (idx === codons.length - 1) {
209
+ // Don't test last codon as it is supposed to be a stop
210
+ break
211
+ }
142
212
  const location = getOriginalCodonLocation(cdsLocation, strand, idx)
143
213
  if (location && codon.toUpperCase() in STOP_CODONS) {
144
214
  const [codonStart, codonEnd] = location
145
215
  checkResults.push({
146
216
  _id: new ObjectID().toHexString(),
147
- name: 'InternalStopCodonCheck',
217
+ name: CHECK_NAME,
218
+ cause: CAUSES[CAUSES.InternalStopCodon],
148
219
  ids,
149
220
  refSeq: refSeq.toString(),
150
221
  start: codonStart,
@@ -196,13 +267,23 @@ function getCDSLocations(
196
267
  nextPhase = ((3 - ((loc.max - loc.min - phase + 3) % 3)) % 3) as 0 | 1 | 2
197
268
  return { ...loc, phase }
198
269
  })
270
+ phasedLocs.sort((a, b) => (a.min < b.min ? -1 : 1))
199
271
  cdsLocations.push(phasedLocs)
200
272
  }
273
+ if (cdsLocations.length > 1) {
274
+ cdsLocations.sort((a, b) => (a[0].min < b[0].min ? -1 : 1))
275
+ }
201
276
  return cdsLocations
202
277
  }
203
278
 
279
+ function getCauses(): string[] {
280
+ return Object.values(CAUSES).filter((x) =>
281
+ Number.isNaN(Number(x)),
282
+ ) as string[]
283
+ }
204
284
  export class CDSCheck extends Check {
205
- name = 'CDSCheck'
285
+ name = CHECK_NAME
286
+ causes = getCauses()
206
287
  version = 1
207
288
  default = true
208
289
 
@@ -1,10 +1,12 @@
1
1
  /* eslint-disable prefer-destructuring */
2
2
  /* eslint-disable @typescript-eslint/no-floating-promises */
3
3
  import { describe, it } from 'node:test'
4
+
5
+ import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
4
6
  import { assert } from 'chai'
5
- import { readAnnotationFeatureSnapshot } from './gff3ToAnnotationFeature.test'
7
+
6
8
  import { annotationFeatureToGFF3 } from './annotationFeatureToGFF3'
7
- import { AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
9
+ import { readAnnotationFeatureSnapshot } from './gff3ToAnnotationFeature.test'
8
10
 
9
11
  describe('annotationFeatureToGFF3', () => {
10
12
  it('Test mandatory columns', () => {
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable @typescript-eslint/no-unsafe-assignment */
2
2
 
3
3
  import {
4
- AnnotationFeatureSnapshot,
5
- TranscriptPartLocation,
6
- TranscriptPartNonCoding,
4
+ type AnnotationFeatureSnapshot,
5
+ type TranscriptPartLocation,
6
+ type TranscriptPartNonCoding,
7
7
  } from '@apollo-annotation/mst'
8
- import { GFF3Feature } from '@gmod/gff'
8
+ import { type GFF3Feature } from '@gmod/gff'
9
9
  import { intersection2 } from '@jbrowse/core/util'
10
10
 
11
11
  export function annotationFeatureToGFF3(
@@ -13,6 +13,7 @@ export function annotationFeatureToGFF3(
13
13
  parentId?: string,
14
14
  refSeqNames?: Record<string, string | undefined>,
15
15
  ): GFF3Feature {
16
+ // eslint-disable-next-line unicorn/prefer-structured-clone
16
17
  const attributes: Record<string, string[] | undefined> = JSON.parse(
17
18
  JSON.stringify(feature.attributes ?? {}),
18
19
  )
@@ -126,6 +127,7 @@ function prepareChildFeatures(
126
127
  const gffChild = annotationFeatureToGFF3(child, parentID, refSeqNames)
127
128
  if (child.type === 'CDS') {
128
129
  for (const loc of cdsLocations[cds_idx]) {
130
+ // eslint-disable-next-line unicorn/prefer-structured-clone
129
131
  const gffCds = JSON.parse(JSON.stringify(gffChild)) as GFF3Feature
130
132
  if (gffCds.length != 1) {
131
133
  // Do we need this check?