@apollo-annotation/shared 0.3.8 → 0.3.9
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/dist/Changes/AddAssemblyAndFeaturesFromFileChange.d.ts +3 -0
- package/dist/Changes/AddAssemblyAndFeaturesFromFileChange.js +5 -4
- package/dist/Changes/AddAssemblyAndFeaturesFromFileChange.js.map +1 -1
- package/dist/Changes/AddFeatureChange.js +14 -2
- package/dist/Changes/AddFeatureChange.js.map +1 -1
- package/dist/Changes/AddFeaturesFromFileChange.d.ts +3 -0
- package/dist/Changes/AddFeaturesFromFileChange.js +5 -2
- package/dist/Changes/AddFeaturesFromFileChange.js.map +1 -1
- package/dist/Changes/AddRefSeqAliasesChange.js +1 -4
- package/dist/Changes/AddRefSeqAliasesChange.js.map +1 -1
- package/dist/Changes/FromFileBaseChange.js +6 -6
- package/dist/Changes/FromFileBaseChange.js.map +1 -1
- package/dist/Checks/CDSCheck.js +5 -4
- package/dist/Checks/CDSCheck.js.map +1 -1
- package/dist/Checks/TranscriptCheck.js +12 -12
- package/dist/Checks/TranscriptCheck.js.map +1 -1
- package/dist/Checks/util.d.ts +2 -0
- package/dist/Checks/util.js +15 -0
- package/dist/Checks/util.js.map +1 -0
- package/dist/GFF3/annotationFeatureToGFF3.js +3 -1
- package/dist/GFF3/annotationFeatureToGFF3.js.map +1 -1
- package/dist/GFF3/gff3ToAnnotationFeature.js +1 -1
- package/dist/GFF3/gff3ToAnnotationFeature.js.map +1 -1
- package/dist/GFF3/gff3ToAnnotationFeature.test.js +3 -3
- package/dist/GFF3/gff3ToAnnotationFeature.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/Changes/AddAssemblyAndFeaturesFromFileChange.ts +6 -5
- package/src/Changes/AddFeatureChange.ts +16 -2
- package/src/Changes/AddFeaturesFromFileChange.ts +6 -1
- package/src/Changes/AddRefSeqAliasesChange.ts +1 -5
- package/src/Changes/FromFileBaseChange.ts +6 -6
- package/src/Checks/CDSCheck.ts +6 -4
- package/src/Checks/TranscriptCheck.ts +11 -12
- package/src/Checks/util.ts +13 -0
- package/src/GFF3/annotationFeatureToGFF3.ts +4 -1
- package/src/GFF3/gff3ToAnnotationFeature.test.ts +3 -3
- package/src/GFF3/gff3ToAnnotationFeature.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apollo-annotation/shared",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.9",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "yarn clean && tsc --build",
|
|
@@ -10,10 +10,10 @@
|
|
|
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.
|
|
14
|
-
"@apollo-annotation/mst": "^0.3.
|
|
15
|
-
"@apollo-annotation/schemas": "^0.3.
|
|
16
|
-
"@gmod/gff": "
|
|
13
|
+
"@apollo-annotation/common": "^0.3.9",
|
|
14
|
+
"@apollo-annotation/mst": "^0.3.9",
|
|
15
|
+
"@apollo-annotation/schemas": "^0.3.9",
|
|
16
|
+
"@gmod/gff": "^2.0.0",
|
|
17
17
|
"@gmod/indexedfasta": "^2.0.4",
|
|
18
18
|
"@jbrowse/core": "^3.6.5",
|
|
19
19
|
"bson-objectid": "^2.0.4",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"@nestjs/common": "^10.1.0",
|
|
26
26
|
"@nestjs/core": "^10.1.0",
|
|
27
27
|
"@types/chai": "^4.3.19",
|
|
28
|
-
"@types/node": "^
|
|
28
|
+
"@types/node": "^20.19.15",
|
|
29
29
|
"chai": "^5.1.1",
|
|
30
30
|
"chai-exclude": "^3.0.0",
|
|
31
31
|
"glob": "^11.0.0",
|
|
@@ -19,6 +19,7 @@ export interface SerializedAddAssemblyAndFeaturesFromFileChangeBase
|
|
|
19
19
|
export interface AddAssemblyAndFeaturesFromFileChangeDetails {
|
|
20
20
|
assemblyName: string
|
|
21
21
|
fileIds: { fa: string }
|
|
22
|
+
parseOptions?: { bufferSize: number }
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
export interface SerializedAddAssemblyAndFeaturesFromFileChangeSingle
|
|
@@ -68,7 +69,7 @@ export class AddAssemblyAndFeaturesFromFileChange extends FromFileBaseChange {
|
|
|
68
69
|
const { assemblyModel, checkModel, fileModel, filesService, user } = backend
|
|
69
70
|
const { assembly, changes, logger } = this
|
|
70
71
|
for (const change of changes) {
|
|
71
|
-
const { assemblyName, fileIds } = change
|
|
72
|
+
const { assemblyName, fileIds, parseOptions } = change
|
|
72
73
|
const fileId = fileIds.fa
|
|
73
74
|
|
|
74
75
|
const { FILE_UPLOAD_FOLDER } = process.env
|
|
@@ -110,13 +111,13 @@ export class AddAssemblyAndFeaturesFromFileChange extends FromFileBaseChange {
|
|
|
110
111
|
backend,
|
|
111
112
|
)
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
logger.debug?.(
|
|
115
|
-
`**************** LOOPATAAN KAIKKI FEATURET SEURAAVAKSI File type: "${fileDoc.type}"`,
|
|
116
|
-
)
|
|
114
|
+
const { bufferSize = 10_000 } = parseOptions ?? {}
|
|
117
115
|
const featureStream = filesService.parseGFF3(
|
|
118
116
|
filesService.getFileStream(fileDoc),
|
|
117
|
+
{ bufferSize },
|
|
119
118
|
)
|
|
119
|
+
// @ts-expect-error type is wrong here
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
120
121
|
for await (const f of featureStream) {
|
|
121
122
|
const gff3Feature = f as GFF3Feature
|
|
122
123
|
logger.verbose?.(`ENTRY=${JSON.stringify(gff3Feature)}`)
|
|
@@ -167,9 +167,23 @@ export class AddFeatureChange extends FeatureChange {
|
|
|
167
167
|
for (const change of changes) {
|
|
168
168
|
const { addedFeature, parentFeatureId } = change
|
|
169
169
|
if (parentFeatureId) {
|
|
170
|
-
|
|
170
|
+
let parentFeature = dataStore.getFeature(parentFeatureId)
|
|
171
|
+
// maybe the parent feature hasn't been loaded yet
|
|
171
172
|
if (!parentFeature) {
|
|
172
|
-
|
|
173
|
+
await dataStore.loadFeatures([
|
|
174
|
+
{
|
|
175
|
+
assemblyName: assembly,
|
|
176
|
+
refName: addedFeature.refSeq,
|
|
177
|
+
start: addedFeature.min,
|
|
178
|
+
end: addedFeature.max,
|
|
179
|
+
},
|
|
180
|
+
])
|
|
181
|
+
parentFeature = dataStore.getFeature(parentFeatureId)
|
|
182
|
+
if (!parentFeature) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`Could not find parent feature "${parentFeatureId}"`,
|
|
185
|
+
)
|
|
186
|
+
}
|
|
173
187
|
}
|
|
174
188
|
// create an ID for the parent feature if it does not have one
|
|
175
189
|
if (!parentFeature.attributes.get('_id')) {
|
|
@@ -18,6 +18,7 @@ export interface SerializedAddFeaturesFromFileChangeBase
|
|
|
18
18
|
|
|
19
19
|
export interface AddFeaturesFromFileChangeDetails {
|
|
20
20
|
fileId: string
|
|
21
|
+
parseOptions?: { bufferSize: number }
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export interface SerializedAddFeaturesFromFileChangeSingle
|
|
@@ -75,7 +76,7 @@ export class AddFeaturesFromFileChange extends FromFileBaseChange {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
for (const change of changes) {
|
|
78
|
-
const { fileId } = change
|
|
79
|
+
const { fileId, parseOptions } = change
|
|
79
80
|
|
|
80
81
|
const { FILE_UPLOAD_FOLDER } = process.env
|
|
81
82
|
if (!FILE_UPLOAD_FOLDER) {
|
|
@@ -89,10 +90,14 @@ export class AddFeaturesFromFileChange extends FromFileBaseChange {
|
|
|
89
90
|
logger.debug?.(`FileId "${fileId}", checksum "${fileDoc.checksum}"`)
|
|
90
91
|
|
|
91
92
|
// Read data from compressed file and parse the content
|
|
93
|
+
const { bufferSize = 10_000 } = parseOptions ?? {}
|
|
92
94
|
const featureStream = filesService.parseGFF3(
|
|
93
95
|
filesService.getFileStream(fileDoc),
|
|
96
|
+
{ bufferSize },
|
|
94
97
|
)
|
|
95
98
|
let featureCount = 0
|
|
99
|
+
// @ts-expect-error type is wrong here
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
96
101
|
for await (const f of featureStream) {
|
|
97
102
|
const gff3Feature = f as GFF3Feature
|
|
98
103
|
|
|
@@ -35,11 +35,7 @@ export class AddRefSeqAliasesChange extends AssemblySpecificChange {
|
|
|
35
35
|
if (!assembly) {
|
|
36
36
|
throw new Error(`assembly ${this.assembly} not found`)
|
|
37
37
|
}
|
|
38
|
-
const sessionAliases = assembly.refNameAliases
|
|
39
|
-
|
|
40
|
-
if (!sessionAliases) {
|
|
41
|
-
throw new Error('Session refNameAliases not found in assembly')
|
|
42
|
-
}
|
|
38
|
+
const sessionAliases = assembly.refNameAliases ?? {}
|
|
43
39
|
|
|
44
40
|
for (const refSeqAlias of this.refSeqAliases) {
|
|
45
41
|
const { aliases, refName } = refSeqAlias
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
|
2
1
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
4
|
-
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
5
2
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
6
3
|
import {
|
|
7
4
|
AssemblySpecificChange,
|
|
@@ -38,8 +35,11 @@ export abstract class FromFileBaseChange extends AssemblySpecificChange {
|
|
|
38
35
|
let parsingStarted = false
|
|
39
36
|
logger.debug?.('starting sequence stream')
|
|
40
37
|
let lineCount = 0
|
|
38
|
+
const decoder = new TextDecoder()
|
|
39
|
+
// @ts-expect-error type is wrong here
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
41
41
|
for await (const data of sequenceStream) {
|
|
42
|
-
const chunk =
|
|
42
|
+
const chunk = decoder.decode(data)
|
|
43
43
|
lastLineIsIncomplete = !chunk.endsWith('\n')
|
|
44
44
|
// chunk is small enough that you can split the whole thing into lines without having to make it into smaller chunks first.
|
|
45
45
|
const lines = chunk.split(/\r?\n/)
|
|
@@ -48,9 +48,9 @@ export abstract class FromFileBaseChange extends AssemblySpecificChange {
|
|
|
48
48
|
incompleteLine = ''
|
|
49
49
|
}
|
|
50
50
|
if (lastLineIsIncomplete) {
|
|
51
|
-
incompleteLine = lines.pop()
|
|
51
|
+
incompleteLine = lines.pop() ?? ''
|
|
52
52
|
}
|
|
53
|
-
for
|
|
53
|
+
for (const line of lines) {
|
|
54
54
|
lineCount++
|
|
55
55
|
if (lineCount % 1_000_000 === 0) {
|
|
56
56
|
logger.debug?.(`Processed ${lineCount} lines`)
|
package/src/Checks/CDSCheck.ts
CHANGED
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
import { intersection2 } from '@jbrowse/core/util'
|
|
7
7
|
import ObjectID from 'bson-objectid'
|
|
8
8
|
|
|
9
|
+
import { getPrintableId } from './util'
|
|
10
|
+
|
|
9
11
|
enum STOP_CODONS {
|
|
10
12
|
'TAG',
|
|
11
13
|
'TAA',
|
|
@@ -175,7 +177,7 @@ async function checkMRNA(
|
|
|
175
177
|
refSeq: refSeq.toString(),
|
|
176
178
|
start: cdsStart,
|
|
177
179
|
end: cdsStart,
|
|
178
|
-
message: `Unexpected start codon in feature "${
|
|
180
|
+
message: `Unexpected start codon "${start_codon}" in feature "${getPrintableId(feature)}": `,
|
|
179
181
|
})
|
|
180
182
|
}
|
|
181
183
|
|
|
@@ -189,7 +191,7 @@ async function checkMRNA(
|
|
|
189
191
|
refSeq: refSeq.toString(),
|
|
190
192
|
start: cdsEnd,
|
|
191
193
|
end: cdsEnd,
|
|
192
|
-
message: `Missing stop codon
|
|
194
|
+
message: `Missing stop codon in feature "${getPrintableId(feature)}"`,
|
|
193
195
|
})
|
|
194
196
|
}
|
|
195
197
|
} else {
|
|
@@ -201,7 +203,7 @@ async function checkMRNA(
|
|
|
201
203
|
refSeq: refSeq.toString(),
|
|
202
204
|
start: cdsEnd,
|
|
203
205
|
end: cdsEnd,
|
|
204
|
-
message: `Missing stop codon
|
|
206
|
+
message: `Missing stop codon in feature "${getPrintableId(feature)}"`,
|
|
205
207
|
})
|
|
206
208
|
}
|
|
207
209
|
for (const [idx, codon] of codons.entries()) {
|
|
@@ -220,7 +222,7 @@ async function checkMRNA(
|
|
|
220
222
|
refSeq: refSeq.toString(),
|
|
221
223
|
start: codonStart,
|
|
222
224
|
end: codonEnd,
|
|
223
|
-
message: `
|
|
225
|
+
message: `Internal stop codon in feature "${getPrintableId(feature)}"`,
|
|
224
226
|
})
|
|
225
227
|
}
|
|
226
228
|
}
|
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
import { revcom } from '@jbrowse/core/util'
|
|
7
7
|
import ObjectID from 'bson-objectid'
|
|
8
8
|
|
|
9
|
+
import { getPrintableId } from './util'
|
|
10
|
+
|
|
9
11
|
interface SpliceSequence {
|
|
10
12
|
fivePrimeSeq: string
|
|
11
13
|
fivePrimeMin: number
|
|
@@ -35,15 +37,17 @@ async function getSpliceSequences(
|
|
|
35
37
|
if (exons.length < 2) {
|
|
36
38
|
return []
|
|
37
39
|
}
|
|
40
|
+
exons.sort((a, b) => (a.min < b.min ? -1 : 1))
|
|
38
41
|
|
|
39
42
|
const spliceSeq: SpliceSequence[] = []
|
|
40
43
|
for (let i = 0; i < exons.length - 1; i++) {
|
|
41
44
|
let fivePrimeMin = exons[i].max
|
|
42
|
-
let threePrimeMin = exons[i + 1].min
|
|
45
|
+
let threePrimeMin = exons[i + 1].min
|
|
43
46
|
if (transcript.strand === -1) {
|
|
44
|
-
|
|
45
|
-
fivePrimeMin
|
|
46
|
-
|
|
47
|
+
;[threePrimeMin, fivePrimeMin] = [fivePrimeMin, threePrimeMin]
|
|
48
|
+
fivePrimeMin -= 2
|
|
49
|
+
} else {
|
|
50
|
+
threePrimeMin -= 2
|
|
47
51
|
}
|
|
48
52
|
|
|
49
53
|
let fivePrimeSeq = await getSequence(fivePrimeMin, fivePrimeMin + 2)
|
|
@@ -53,12 +57,7 @@ async function getSpliceSequences(
|
|
|
53
57
|
fivePrimeSeq = revcom(fivePrimeSeq)
|
|
54
58
|
}
|
|
55
59
|
|
|
56
|
-
spliceSeq.push({
|
|
57
|
-
fivePrimeSeq,
|
|
58
|
-
fivePrimeMin,
|
|
59
|
-
threePrimeSeq,
|
|
60
|
-
threePrimeMin,
|
|
61
|
-
})
|
|
60
|
+
spliceSeq.push({ fivePrimeSeq, fivePrimeMin, threePrimeSeq, threePrimeMin })
|
|
62
61
|
}
|
|
63
62
|
return spliceSeq
|
|
64
63
|
}
|
|
@@ -82,7 +81,7 @@ async function checkTranscript(
|
|
|
82
81
|
refSeq: feature.refSeq.toString(),
|
|
83
82
|
start: spliceSequence.fivePrimeMin,
|
|
84
83
|
end: spliceSequence.fivePrimeMin + 2,
|
|
85
|
-
message: `Unexpected 5
|
|
84
|
+
message: `Unexpected 5′ splice site in "${getPrintableId(feature)}". Expected: ${[...VALID_FIVE_PRIME_SEQ].join('|')}, got: ${spliceSequence.fivePrimeSeq}`,
|
|
86
85
|
})
|
|
87
86
|
}
|
|
88
87
|
if (
|
|
@@ -96,7 +95,7 @@ async function checkTranscript(
|
|
|
96
95
|
refSeq: feature.refSeq.toString(),
|
|
97
96
|
start: spliceSequence.threePrimeMin,
|
|
98
97
|
end: spliceSequence.threePrimeMin + 2,
|
|
99
|
-
message: `Unexpected 3
|
|
98
|
+
message: `Unexpected 3′ splice site in "${getPrintableId(feature)}". Expected: ${[...VALID_THREE_PRIME_SEQ].join('|')}, got: ${spliceSequence.threePrimeSeq}`,
|
|
100
99
|
})
|
|
101
100
|
}
|
|
102
101
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
2
|
+
|
|
3
|
+
export function getPrintableId(feature: AnnotationFeatureSnapshot): string {
|
|
4
|
+
const gff_id = feature.attributes?.gff_id?.join(', ')
|
|
5
|
+
if (gff_id) {
|
|
6
|
+
return `${gff_id} (_id: ${feature._id.toString()})`
|
|
7
|
+
}
|
|
8
|
+
const gff_name = feature.attributes?.gff_name?.join(', ')
|
|
9
|
+
if (gff_name) {
|
|
10
|
+
return `${gff_name} (_id: ${feature._id.toString()})`
|
|
11
|
+
}
|
|
12
|
+
return `_id: ${feature._id.toString()}`
|
|
13
|
+
}
|
|
@@ -101,7 +101,10 @@ export function annotationFeatureToGFF3(
|
|
|
101
101
|
score,
|
|
102
102
|
strand: feature.strand ? (feature.strand === 1 ? '+' : '-') : null,
|
|
103
103
|
phase: null,
|
|
104
|
-
attributes:
|
|
104
|
+
attributes:
|
|
105
|
+
Object.keys(attributes).length > 0
|
|
106
|
+
? (attributes as Record<string, string[]>)
|
|
107
|
+
: null,
|
|
105
108
|
derived_features: [],
|
|
106
109
|
child_features: prepareChildFeatures(
|
|
107
110
|
feature,
|
|
@@ -3,7 +3,7 @@ import { readFileSync } from 'node:fs'
|
|
|
3
3
|
import { describe, it } from 'node:test'
|
|
4
4
|
|
|
5
5
|
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
6
|
-
import
|
|
6
|
+
import { type GFF3Feature, parseStringSync } from '@gmod/gff'
|
|
7
7
|
import { assert, use } from 'chai'
|
|
8
8
|
import chaiExclude from 'chai-exclude'
|
|
9
9
|
|
|
@@ -116,7 +116,7 @@ function readFeatureFile(fn: string): GFF3Feature[] {
|
|
|
116
116
|
feature.push(line)
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
const inGff =
|
|
119
|
+
const inGff = parseStringSync(feature.join('\n')) as GFF3Feature[]
|
|
120
120
|
return inGff
|
|
121
121
|
}
|
|
122
122
|
|
|
@@ -232,7 +232,7 @@ describe('gff3ToAnnotationFeature', () => {
|
|
|
232
232
|
for (const testCase of testCases) {
|
|
233
233
|
const [description, featureLine, convertedFeature] = testCase
|
|
234
234
|
it(`converts ${description}`, () => {
|
|
235
|
-
const gff3Feature =
|
|
235
|
+
const gff3Feature = parseStringSync(featureLine, {
|
|
236
236
|
parseSequences: false,
|
|
237
237
|
})
|
|
238
238
|
const feature = gff3ToAnnotationFeature(gff3Feature[0])
|
|
@@ -115,7 +115,7 @@ function convertFeatureAttributes(
|
|
|
115
115
|
if (attributesCollections.length > 0) {
|
|
116
116
|
for (const attributesCollection of attributesCollections) {
|
|
117
117
|
for (const [key, val] of Object.entries(attributesCollection)) {
|
|
118
|
-
if (
|
|
118
|
+
if (key === 'Parent') {
|
|
119
119
|
continue
|
|
120
120
|
}
|
|
121
121
|
const newKey = isGFFReservedAttribute(key) ? gffToInternal[key] : key
|