@apollo-annotation/shared 0.1.17 → 0.1.19
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 +13 -7
- package/src/Changes/AddAssemblyAndFeaturesFromFileChange.ts +7 -4
- package/src/Changes/AddAssemblyFromFileChange.ts +3 -2
- package/src/Changes/AddFeatureChange.ts +2 -3
- package/src/Changes/AddFeaturesFromFileChange.ts +8 -3
- package/src/Changes/AddRefSeqAliasesChange.ts +88 -0
- package/src/Changes/DeleteAssemblyChange.ts +1 -1
- package/src/Changes/DeleteFeatureChange.ts +1 -1
- package/src/Changes/FeatureAttributeChange.ts +1 -1
- package/src/Changes/FromFileBaseChange.ts +221 -0
- package/src/Changes/ImportJBrowseConfigChange.ts +116 -0
- package/src/Changes/LocationEndChange.ts +25 -18
- package/src/Changes/LocationStartChange.ts +25 -18
- package/src/Changes/TypeChange.ts +1 -1
- package/src/Changes/index.ts +6 -6
- package/src/Checks/CDSCheck.ts +251 -249
- package/src/Common/jwtPayload.ts +1 -1
- package/src/GFF3/gff3ToAnnotationFeature.test.ts +49 -0
- package/src/GFF3/gff3ToAnnotationFeature.ts +257 -0
- package/src/GFF3/gffReservedKeys.ts +61 -0
- package/src/GFF3/index.ts +2 -0
- package/src/Operations/GetFeaturesOperation.ts +2 -2
- package/src/Validations/ParentChildValidation.ts +5 -5
- package/src/index.ts +1 -0
- package/src/util.ts +15 -12
- package/tsconfig.json +4 -4
- package/src/Changes/DiscontinuousLocationEndChange.ts +0 -182
- package/src/Changes/DiscontinuousLocationStartChange.ts +0 -182
package/src/Checks/CDSCheck.ts
CHANGED
|
@@ -3,225 +3,225 @@ import {
|
|
|
3
3
|
AnnotationFeatureSnapshot,
|
|
4
4
|
CheckResultSnapshot,
|
|
5
5
|
} from '@apollo-annotation/mst'
|
|
6
|
-
import ObjectID from 'bson-objectid'
|
|
6
|
+
// import ObjectID from 'bson-objectid'
|
|
7
7
|
|
|
8
|
-
enum STOP_CODONS {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
8
|
+
// enum STOP_CODONS {
|
|
9
|
+
// 'TAG',
|
|
10
|
+
// 'TAA',
|
|
11
|
+
// 'TGA',
|
|
12
|
+
// }
|
|
13
13
|
|
|
14
|
-
const iupacComplements: Record<string, string | undefined> = {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
14
|
+
// const iupacComplements: Record<string, string | undefined> = {
|
|
15
|
+
// G: 'C',
|
|
16
|
+
// A: 'T',
|
|
17
|
+
// T: 'A',
|
|
18
|
+
// C: 'G',
|
|
19
|
+
// R /* G or A */: 'Y',
|
|
20
|
+
// Y /* T or C */: 'R',
|
|
21
|
+
// M /* A or C */: 'K',
|
|
22
|
+
// K /* G or T */: 'M',
|
|
23
|
+
// S /* G or C */: 'S',
|
|
24
|
+
// W /* A or T */: 'W',
|
|
25
|
+
// H /* A or C or T */: 'D',
|
|
26
|
+
// B /* G or T or C */: 'V',
|
|
27
|
+
// V /* G or C or A */: 'B',
|
|
28
|
+
// D /* G or A or T */: 'H',
|
|
29
|
+
// N /* G or A or T or C */: 'N',
|
|
30
|
+
// }
|
|
31
31
|
|
|
32
|
-
function reverseComplement(dna: string): string {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
32
|
+
// function reverseComplement(dna: string): string {
|
|
33
|
+
// const complement: string[] = []
|
|
34
|
+
// for (const nt of dna) {
|
|
35
|
+
// const rc = iupacComplements[nt.toUpperCase()]
|
|
36
|
+
// if (rc === undefined) {
|
|
37
|
+
// throw new TypeError(`Cannot complement nucleotide: "${nt}"`)
|
|
38
|
+
// }
|
|
39
|
+
// if (nt === nt.toLowerCase()) {
|
|
40
|
+
// complement.push(rc.toLowerCase())
|
|
41
|
+
// } else {
|
|
42
|
+
// complement.push(rc)
|
|
43
|
+
// }
|
|
44
|
+
// }
|
|
45
|
+
// return complement.reverse().join('')
|
|
46
|
+
// }
|
|
47
47
|
|
|
48
|
-
async function getSequenceFromSingleFeature(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
48
|
+
// async function getSequenceFromSingleFeature(
|
|
49
|
+
// feature: AnnotationFeatureSnapshot,
|
|
50
|
+
// getSequence: (start: number, end: number) => Promise<string>,
|
|
51
|
+
// ) {
|
|
52
|
+
// let seq = ''
|
|
53
|
+
// if (
|
|
54
|
+
// feature.discontinuousLocations !== undefined &&
|
|
55
|
+
// feature.discontinuousLocations.length > 0
|
|
56
|
+
// ) {
|
|
57
|
+
// for (const loc of feature.discontinuousLocations) {
|
|
58
|
+
// seq = seq + (await getSequence(loc.start, loc.end))
|
|
59
|
+
// }
|
|
60
|
+
// } else {
|
|
61
|
+
// seq = await getSequence(feature.start, feature.end)
|
|
62
|
+
// }
|
|
63
|
+
// if (feature.strand === -1) {
|
|
64
|
+
// return reverseComplement(seq)
|
|
65
|
+
// }
|
|
66
|
+
// return seq
|
|
67
|
+
// }
|
|
68
68
|
|
|
69
|
-
async function getSequenceFromMultipleFeatures(
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
69
|
+
// async function getSequenceFromMultipleFeatures(
|
|
70
|
+
// features: AnnotationFeatureSnapshot[],
|
|
71
|
+
// getSequence: (start: number, end: number) => Promise<string>,
|
|
72
|
+
// ) {
|
|
73
|
+
// const strands = features.map((feature) => feature.strand)
|
|
74
|
+
// if (!strands.every((strand) => strand === strands[0])) {
|
|
75
|
+
// throw new Error(
|
|
76
|
+
// `Strands do not match in features: "${features
|
|
77
|
+
// .map((f) => f._id)
|
|
78
|
+
// .join(', ')}"`,
|
|
79
|
+
// )
|
|
80
|
+
// }
|
|
81
|
+
// let seq = ''
|
|
82
|
+
// for (const feature of features) {
|
|
83
|
+
// seq = seq + (await getSequence(feature.start, feature.end))
|
|
84
|
+
// }
|
|
85
|
+
// if (strands[0] === -1) {
|
|
86
|
+
// return reverseComplement(seq)
|
|
87
|
+
// }
|
|
88
|
+
// return seq
|
|
89
|
+
// }
|
|
90
90
|
|
|
91
|
-
function splitSequenceInCodons(cds: string): string[] {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
91
|
+
// function splitSequenceInCodons(cds: string): string[] {
|
|
92
|
+
// const codons: string[] = []
|
|
93
|
+
// for (let i = 0; i <= cds.length - 3; i += 3) {
|
|
94
|
+
// codons.push(cds.slice(i, i + 3))
|
|
95
|
+
// }
|
|
96
|
+
// return codons
|
|
97
|
+
// }
|
|
98
98
|
|
|
99
|
-
function getOriginalCodonLocation(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
): [number, number] {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
99
|
+
// function getOriginalCodonLocation(
|
|
100
|
+
// feature: AnnotationFeatureSnapshot | AnnotationFeatureSnapshot[],
|
|
101
|
+
// index: number,
|
|
102
|
+
// ): [number, number] {
|
|
103
|
+
// let lengthToStart = index * 3
|
|
104
|
+
// let lengthToEnd = lengthToStart + 3
|
|
105
|
+
// if (Array.isArray(feature)) {
|
|
106
|
+
// let startLocation: number | undefined = undefined,
|
|
107
|
+
// endLocation: number | undefined = undefined
|
|
108
|
+
// for (const f of feature) {
|
|
109
|
+
// const featureLength = f.end - f.start
|
|
110
|
+
// if (startLocation === undefined && featureLength > lengthToStart) {
|
|
111
|
+
// startLocation = f.start + lengthToStart
|
|
112
|
+
// } else {
|
|
113
|
+
// lengthToStart -= featureLength
|
|
114
|
+
// }
|
|
115
|
+
// if (endLocation === undefined && featureLength > lengthToEnd) {
|
|
116
|
+
// endLocation = f.start + lengthToEnd
|
|
117
|
+
// } else {
|
|
118
|
+
// lengthToEnd -= featureLength
|
|
119
|
+
// }
|
|
120
|
+
// if (startLocation !== undefined && endLocation !== undefined) {
|
|
121
|
+
// return [startLocation, endLocation]
|
|
122
|
+
// }
|
|
123
|
+
// }
|
|
124
|
+
// throw new Error('Could not determine original CDS location')
|
|
125
|
+
// } else {
|
|
126
|
+
// if (
|
|
127
|
+
// feature.discontinuousLocations !== undefined &&
|
|
128
|
+
// feature.discontinuousLocations.length > 0
|
|
129
|
+
// ) {
|
|
130
|
+
// let startLocation: number | undefined = undefined,
|
|
131
|
+
// endLocation: number | undefined = undefined
|
|
132
|
+
// for (const loc of feature.discontinuousLocations) {
|
|
133
|
+
// const locLength = loc.end - loc.start
|
|
134
|
+
// if (startLocation === undefined && locLength > lengthToStart) {
|
|
135
|
+
// startLocation = loc.start + lengthToStart
|
|
136
|
+
// } else {
|
|
137
|
+
// lengthToStart -= locLength
|
|
138
|
+
// }
|
|
139
|
+
// if (endLocation === undefined && locLength > lengthToEnd) {
|
|
140
|
+
// endLocation = loc.start + lengthToEnd
|
|
141
|
+
// } else {
|
|
142
|
+
// lengthToEnd -= locLength
|
|
143
|
+
// }
|
|
144
|
+
// if (startLocation !== undefined && endLocation !== undefined) {
|
|
145
|
+
// return [startLocation, endLocation]
|
|
146
|
+
// }
|
|
147
|
+
// }
|
|
148
|
+
// throw new Error('Could not determine original CDS location')
|
|
149
|
+
// } else {
|
|
150
|
+
// return [feature.start + lengthToStart, feature.start + lengthToEnd]
|
|
151
|
+
// }
|
|
152
|
+
// }
|
|
153
|
+
// }
|
|
154
154
|
|
|
155
|
-
async function checkCDS(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
): Promise<CheckResultSnapshot[]> {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
155
|
+
// async function checkCDS(
|
|
156
|
+
// feature: AnnotationFeatureSnapshot | AnnotationFeatureSnapshot[],
|
|
157
|
+
// getSequence: (start: number, end: number) => Promise<string>,
|
|
158
|
+
// ): Promise<CheckResultSnapshot[]> {
|
|
159
|
+
// const checkResults: CheckResultSnapshot[] = []
|
|
160
|
+
// let _id: string,
|
|
161
|
+
// ids: string[],
|
|
162
|
+
// start: number,
|
|
163
|
+
// end: number,
|
|
164
|
+
// refSeq: string,
|
|
165
|
+
// sequence: string
|
|
166
|
+
// if (Array.isArray(feature)) {
|
|
167
|
+
// sequence = await getSequenceFromMultipleFeatures(feature, getSequence)
|
|
168
|
+
// ids = feature.map((f) => f._id)
|
|
169
|
+
// _id = ids.join(',')
|
|
170
|
+
// ;[{ refSeq, start }] = feature
|
|
171
|
+
// const lastFeature = feature.at(-1)
|
|
172
|
+
// if (!lastFeature) {
|
|
173
|
+
// throw new Error('Zero-length feature array encountered')
|
|
174
|
+
// }
|
|
175
|
+
// ;({ end } = lastFeature)
|
|
176
|
+
// } else {
|
|
177
|
+
// sequence = await getSequenceFromSingleFeature(feature, getSequence)
|
|
178
|
+
// ;({ _id, end, refSeq, start } = feature)
|
|
179
|
+
// ids = [_id]
|
|
180
|
+
// }
|
|
181
|
+
// const codons = splitSequenceInCodons(sequence)
|
|
182
|
+
// if (sequence.length % 3 === 0) {
|
|
183
|
+
// const lastCodon = codons.pop() // Last codon is supposed to be a stop
|
|
184
|
+
// if (!lastCodon) {
|
|
185
|
+
// throw new Error(`No sequence found for feature "${_id}"`)
|
|
186
|
+
// }
|
|
187
|
+
// if (!(lastCodon.toUpperCase() in STOP_CODONS)) {
|
|
188
|
+
// checkResults.push({
|
|
189
|
+
// _id: new ObjectID().toHexString(),
|
|
190
|
+
// name: 'MissingStopCodonCheck',
|
|
191
|
+
// ids,
|
|
192
|
+
// refSeq: refSeq.toString(),
|
|
193
|
+
// start: end,
|
|
194
|
+
// end,
|
|
195
|
+
// message: `Feature "${_id}" is missing a stop codon`,
|
|
196
|
+
// })
|
|
197
|
+
// }
|
|
198
|
+
// } else {
|
|
199
|
+
// checkResults.push({
|
|
200
|
+
// _id: new ObjectID().toHexString(),
|
|
201
|
+
// name: 'MultipleOfThreeCheck',
|
|
202
|
+
// ids,
|
|
203
|
+
// refSeq: refSeq.toString(),
|
|
204
|
+
// start,
|
|
205
|
+
// end,
|
|
206
|
+
// message: `The coding sequence for feature "${_id}" is not a multiple of three`,
|
|
207
|
+
// })
|
|
208
|
+
// }
|
|
209
|
+
// for (const [idx, codon] of codons.entries()) {
|
|
210
|
+
// const [codonStart, codonEnd] = getOriginalCodonLocation(feature, idx)
|
|
211
|
+
// if (codon.toUpperCase() in STOP_CODONS) {
|
|
212
|
+
// checkResults.push({
|
|
213
|
+
// _id: new ObjectID().toHexString(),
|
|
214
|
+
// name: 'InternalStopCodonCheck',
|
|
215
|
+
// ids,
|
|
216
|
+
// refSeq: refSeq.toString(),
|
|
217
|
+
// start: codonStart,
|
|
218
|
+
// end: codonEnd,
|
|
219
|
+
// message: `The coding sequence for feature "${_id}" has an internal stop codon`,
|
|
220
|
+
// })
|
|
221
|
+
// }
|
|
222
|
+
// }
|
|
223
|
+
// return checkResults
|
|
224
|
+
// }
|
|
225
225
|
|
|
226
226
|
export class CDSCheck extends Check {
|
|
227
227
|
name = 'CDSCheck'
|
|
@@ -229,47 +229,49 @@ export class CDSCheck extends Check {
|
|
|
229
229
|
default = true
|
|
230
230
|
|
|
231
231
|
async checkFeature(
|
|
232
|
-
|
|
233
|
-
|
|
232
|
+
_feature: AnnotationFeatureSnapshot,
|
|
233
|
+
_getSequence: (start: number, end: number) => Promise<string>,
|
|
234
234
|
): Promise<CheckResultSnapshot[]> {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
await Promise.resolve()
|
|
236
|
+
return []
|
|
237
|
+
// if (feature.type === 'CDS') {
|
|
238
|
+
// return checkCDS(feature, getSequence)
|
|
239
|
+
// }
|
|
238
240
|
|
|
239
|
-
if (!feature.children) {
|
|
240
|
-
|
|
241
|
-
}
|
|
241
|
+
// if (!feature.children) {
|
|
242
|
+
// return []
|
|
243
|
+
// }
|
|
242
244
|
|
|
243
|
-
if (feature.type !== 'mRNA') {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
}
|
|
245
|
+
// if (feature.type !== 'mRNA') {
|
|
246
|
+
// const checkResults: CheckResultSnapshot[] = []
|
|
247
|
+
// for (const child of Object.values(feature.children)) {
|
|
248
|
+
// checkResults.push(...(await this.checkFeature(child, getSequence)))
|
|
249
|
+
// }
|
|
250
|
+
// return checkResults
|
|
251
|
+
// }
|
|
250
252
|
|
|
251
|
-
const cdsChildren = Object.values(feature.children).filter(
|
|
252
|
-
|
|
253
|
-
)
|
|
254
|
-
if (cdsChildren.length === 0) {
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
const cdsChildrenWithDiscontinuousLocations = cdsChildren.filter(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
)
|
|
261
|
-
if (cdsChildrenWithDiscontinuousLocations.length === 0) {
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
if (cdsChildrenWithDiscontinuousLocations.length === cdsChildren.length) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
throw new Error(
|
|
272
|
-
|
|
273
|
-
)
|
|
253
|
+
// const cdsChildren = Object.values(feature.children).filter(
|
|
254
|
+
// (child) => child.type === 'CDS',
|
|
255
|
+
// )
|
|
256
|
+
// if (cdsChildren.length === 0) {
|
|
257
|
+
// throw new Error(`mRNA "${feature._id}" has no CDS children`)
|
|
258
|
+
// }
|
|
259
|
+
// const cdsChildrenWithDiscontinuousLocations = cdsChildren.filter(
|
|
260
|
+
// (child) =>
|
|
261
|
+
// child.discontinuousLocations && child.discontinuousLocations.length > 0,
|
|
262
|
+
// )
|
|
263
|
+
// if (cdsChildrenWithDiscontinuousLocations.length === 0) {
|
|
264
|
+
// return checkCDS(cdsChildren, getSequence)
|
|
265
|
+
// }
|
|
266
|
+
// if (cdsChildrenWithDiscontinuousLocations.length === cdsChildren.length) {
|
|
267
|
+
// const checkResults: CheckResultSnapshot[] = []
|
|
268
|
+
// for (const child of cdsChildren) {
|
|
269
|
+
// checkResults.push(...(await this.checkFeature(child, getSequence)))
|
|
270
|
+
// }
|
|
271
|
+
// return checkResults
|
|
272
|
+
// }
|
|
273
|
+
// throw new Error(
|
|
274
|
+
// `Mix of CDS with and without discontinuous locations found in mRNA "${feature._id}"`,
|
|
275
|
+
// )
|
|
274
276
|
}
|
|
275
277
|
}
|
package/src/Common/jwtPayload.ts
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
2
|
+
import { strict as assert } from 'node:assert'
|
|
3
|
+
import { describe, it } from 'node:test'
|
|
4
|
+
import gff from '@gmod/gff'
|
|
5
|
+
|
|
6
|
+
import { gff3ToAnnotationFeature } from './gff3ToAnnotationFeature'
|
|
7
|
+
import { AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
8
|
+
|
|
9
|
+
const testCases: [string, string, AnnotationFeatureSnapshot][] = [
|
|
10
|
+
[
|
|
11
|
+
'a feature with no children',
|
|
12
|
+
'ctgA example remark 1000 2000 . . . Name=Remark:hga;Alias=hga\n',
|
|
13
|
+
{
|
|
14
|
+
_id: '66c51f3e002c683eaf98a223',
|
|
15
|
+
refSeq: 'ctgA',
|
|
16
|
+
type: 'remark',
|
|
17
|
+
min: 999,
|
|
18
|
+
max: 2000,
|
|
19
|
+
attributes: {
|
|
20
|
+
gff_source: ['example'],
|
|
21
|
+
gff_name: ['Remark:hga'],
|
|
22
|
+
gff_alias: ['hga'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
function compareFeatures(
|
|
29
|
+
feature1: AnnotationFeatureSnapshot,
|
|
30
|
+
feature2: AnnotationFeatureSnapshot,
|
|
31
|
+
) {
|
|
32
|
+
assert.deepEqual(
|
|
33
|
+
{ ...feature1, _id: undefined },
|
|
34
|
+
{ ...feature2, _id: undefined },
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
describe('gff3ToAnnotationFeature', () => {
|
|
39
|
+
for (const testCase of testCases) {
|
|
40
|
+
const [description, featureLine, convertedFeature] = testCase
|
|
41
|
+
it(`converts ${description}`, () => {
|
|
42
|
+
const gff3Feature = gff.parseStringSync(featureLine, {
|
|
43
|
+
parseSequences: false,
|
|
44
|
+
})
|
|
45
|
+
const feature = gff3ToAnnotationFeature(gff3Feature[0])
|
|
46
|
+
compareFeatures(convertedFeature, feature)
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
})
|