@apollo-annotation/shared 0.3.7 → 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 +6 -5
- package/dist/Changes/AddAssemblyAndFeaturesFromFileChange.js.map +1 -1
- package/dist/Changes/AddAssemblyFromFileChange.js +1 -1
- package/dist/Changes/AddAssemblyFromFileChange.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 +2 -7
- 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/Changes/ImportJBrowseConfigChange.js +1 -1
- package/dist/Changes/ImportJBrowseConfigChange.js.map +1 -1
- package/dist/Changes/MergeExonsChange.d.ts +0 -1
- package/dist/Changes/MergeExonsChange.js +14 -30
- package/dist/Changes/MergeExonsChange.js.map +1 -1
- package/dist/Changes/MergeTranscriptsChange.d.ts +1 -3
- package/dist/Changes/MergeTranscriptsChange.js +55 -56
- package/dist/Changes/MergeTranscriptsChange.js.map +1 -1
- package/dist/Checks/CDSCheck.d.ts +1 -1
- package/dist/Checks/CDSCheck.js +12 -12
- package/dist/Checks/CDSCheck.js.map +1 -1
- package/dist/Checks/TranscriptCheck.d.ts +9 -0
- package/dist/Checks/TranscriptCheck.js +109 -0
- package/dist/Checks/TranscriptCheck.js.map +1 -0
- package/dist/Checks/index.d.ts +1 -0
- package/dist/Checks/index.js +1 -0
- package/dist/Checks/index.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 +4 -4
- package/dist/GFF3/gff3ToAnnotationFeature.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/util.d.ts +3 -0
- package/dist/util.js +33 -0
- package/dist/util.js.map +1 -1
- package/package.json +9 -9
- package/src/Changes/AddAssemblyAndFeaturesFromFileChange.ts +8 -6
- package/src/Changes/AddAssemblyFromFileChange.ts +1 -1
- package/src/Changes/AddFeatureChange.ts +16 -2
- package/src/Changes/AddFeaturesFromFileChange.ts +6 -1
- package/src/Changes/AddRefSeqAliasesChange.ts +2 -8
- package/src/Changes/FromFileBaseChange.ts +6 -6
- package/src/Changes/ImportJBrowseConfigChange.ts +1 -1
- package/src/Changes/MergeExonsChange.ts +52 -36
- package/src/Changes/MergeTranscriptsChange.ts +82 -67
- package/src/Checks/CDSCheck.ts +15 -13
- package/src/Checks/TranscriptCheck.ts +138 -0
- package/src/Checks/index.ts +1 -0
- package/src/Checks/util.ts +13 -0
- package/src/GFF3/annotationFeatureToGFF3.ts +4 -1
- package/src/GFF3/gff3ToAnnotationFeature.test.ts +4 -4
- package/src/GFF3/gff3ToAnnotationFeature.ts +1 -1
- package/src/util.ts +37 -0
- package/test_data/example01.json +20 -20
- package/test_data/example02.json +38 -38
- package/test_data/example04.json +57 -57
- package/test_data/gene_representations.gff3 +1054 -276
package/dist/util.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { type Feature } from '@apollo-annotation/schemas';
|
|
2
|
+
import { type IKeyValueMap } from 'mobx';
|
|
2
3
|
export declare function splitStringIntoChunks(input: string, chunkSize: number): string[];
|
|
3
4
|
export declare function getPrintableId(feature: Feature): string;
|
|
5
|
+
export declare function attributesToRecords(attributes: IKeyValueMap<readonly string[] | undefined> | undefined): Record<string, string[] | undefined>;
|
|
6
|
+
export declare function stringifyAttributes(attributes: Record<string, string[] | undefined> | undefined): string;
|
package/dist/util.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.splitStringIntoChunks = splitStringIntoChunks;
|
|
4
4
|
exports.getPrintableId = getPrintableId;
|
|
5
|
+
exports.attributesToRecords = attributesToRecords;
|
|
6
|
+
exports.stringifyAttributes = stringifyAttributes;
|
|
5
7
|
function splitStringIntoChunks(input, chunkSize) {
|
|
6
8
|
const chunks = [];
|
|
7
9
|
for (let i = 0; i < input.length; i += chunkSize) {
|
|
@@ -22,4 +24,35 @@ function getPrintableId(feature) {
|
|
|
22
24
|
}
|
|
23
25
|
return `_id: ${feature._id.toString()}`;
|
|
24
26
|
}
|
|
27
|
+
function attributesToRecords(attributes) {
|
|
28
|
+
const records = {};
|
|
29
|
+
if (!attributes) {
|
|
30
|
+
return records;
|
|
31
|
+
}
|
|
32
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
33
|
+
records[key] = value?.slice();
|
|
34
|
+
}
|
|
35
|
+
return records;
|
|
36
|
+
}
|
|
37
|
+
function stringifyAttributes(attributes) {
|
|
38
|
+
if (!attributes) {
|
|
39
|
+
return '';
|
|
40
|
+
}
|
|
41
|
+
const str = [];
|
|
42
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
43
|
+
let attributeName = key;
|
|
44
|
+
if (attributeName.startsWith('gff_')) {
|
|
45
|
+
attributeName = attributeName.slice(4);
|
|
46
|
+
attributeName =
|
|
47
|
+
attributeName.charAt(0).toUpperCase() + attributeName.slice(1);
|
|
48
|
+
}
|
|
49
|
+
if (value) {
|
|
50
|
+
str.push(`${attributeName}=${value.join(',')}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
str.push(attributeName);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return encodeURIComponent(str.join(';'));
|
|
57
|
+
}
|
|
25
58
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;AAIA,sDAUC;AAED,wCAWC;AAED,kDAWC;AAED,kDAqBC;AA3DD,SAAgB,qBAAqB,CACnC,KAAa,EACb,SAAiB;IAEjB,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAA;QAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAgB,cAAc,CAAC,OAAgB;IAC7C,MAAM,EAAE,GAAG,OAAuC,CAAA;IAClD,MAAM,MAAM,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACrD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,MAAM,UAAU,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAA;IACxD,CAAC;IACD,MAAM,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACzD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,QAAQ,QAAQ,UAAU,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAA;IAC5D,CAAC;IACD,OAAO,QAAQ,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAA;AACzC,CAAC;AAED,SAAgB,mBAAmB,CACjC,UAAmE;IAEnE,MAAM,OAAO,GAAyC,EAAE,CAAA;IACxD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,OAAO,CAAA;IAChB,CAAC;IACD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,CAAA;IAC/B,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAgB,mBAAmB,CACjC,UAA4D;IAE5D,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,CAAA;IACX,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,CAAA;IACd,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACtD,IAAI,aAAa,GAAG,GAAG,CAAA;QACvB,IAAI,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,aAAa,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACtC,aAAa;gBACX,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAClE,CAAC;QACD,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACjD,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;IACD,OAAO,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAC1C,CAAC"}
|
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,12 +10,12 @@
|
|
|
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
|
-
"@jbrowse/core": "^3.
|
|
18
|
+
"@jbrowse/core": "^3.6.5",
|
|
19
19
|
"bson-objectid": "^2.0.4",
|
|
20
20
|
"generic-filehandle": "^3.0.0",
|
|
21
21
|
"jwt-decode": "^3.1.2",
|
|
@@ -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",
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"typescript": "^5.5.3"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@mui/material": "^
|
|
43
|
-
"@mui/x-data-grid": "^
|
|
42
|
+
"@mui/material": "^7.0.0",
|
|
43
|
+
"@mui/x-data-grid": "^8.0.0",
|
|
44
44
|
"mobx": "^6.6.1",
|
|
45
45
|
"mobx-react": "^7.2.1",
|
|
46
46
|
"mobx-state-tree": "^5.4.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
|
|
@@ -90,7 +91,8 @@ export class AddAssemblyAndFeaturesFromFileChange extends FromFileBaseChange {
|
|
|
90
91
|
throw new Error(`Assembly "${assemblyName}" already exists`)
|
|
91
92
|
}
|
|
92
93
|
// get checks
|
|
93
|
-
const checkDocs = await checkModel.find({
|
|
94
|
+
const checkDocs = await checkModel.find({ isDefault: true }).exec()
|
|
95
|
+
|
|
94
96
|
const checks = checkDocs.map((checkDoc) => checkDoc._id.toHexString())
|
|
95
97
|
// Add assembly
|
|
96
98
|
const [newAssemblyDoc] = await assemblyModel.create([
|
|
@@ -109,13 +111,13 @@ export class AddAssemblyAndFeaturesFromFileChange extends FromFileBaseChange {
|
|
|
109
111
|
backend,
|
|
110
112
|
)
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
logger.debug?.(
|
|
114
|
-
`**************** LOOPATAAN KAIKKI FEATURET SEURAAVAKSI File type: "${fileDoc.type}"`,
|
|
115
|
-
)
|
|
114
|
+
const { bufferSize = 10_000 } = parseOptions ?? {}
|
|
116
115
|
const featureStream = filesService.parseGFF3(
|
|
117
116
|
filesService.getFileStream(fileDoc),
|
|
117
|
+
{ bufferSize },
|
|
118
118
|
)
|
|
119
|
+
// @ts-expect-error type is wrong here
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/await-thenable
|
|
119
121
|
for await (const f of featureStream) {
|
|
120
122
|
const gff3Feature = f as GFF3Feature
|
|
121
123
|
logger.verbose?.(`ENTRY=${JSON.stringify(gff3Feature)}`)
|
|
@@ -128,7 +128,7 @@ export class AddAssemblyFromFileChange extends FromFileBaseChange {
|
|
|
128
128
|
if (assemblyDoc) {
|
|
129
129
|
throw new Error(`Assembly "${assemblyName}" already exists`)
|
|
130
130
|
}
|
|
131
|
-
const checkDocs = await checkModel.find({
|
|
131
|
+
const checkDocs = await checkModel.find({ isDefault: true }).exec()
|
|
132
132
|
const checks = checkDocs.map((checkDoc) => checkDoc._id.toHexString())
|
|
133
133
|
const [newAssemblyDoc] = await assemblyModel.create([
|
|
134
134
|
{
|
|
@@ -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,21 +35,15 @@ 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
|
-
const sessionLCAliases = assembly.lowerCaseRefNameAliases
|
|
40
|
-
|
|
41
|
-
if (!sessionAliases || !sessionLCAliases) {
|
|
42
|
-
throw new Error('Session refNameAliases not found in assembly')
|
|
43
|
-
}
|
|
38
|
+
const sessionAliases = assembly.refNameAliases ?? {}
|
|
44
39
|
|
|
45
40
|
for (const refSeqAlias of this.refSeqAliases) {
|
|
46
41
|
const { aliases, refName } = refSeqAlias
|
|
47
42
|
for (const alias of aliases) {
|
|
48
43
|
sessionAliases[alias] = refName
|
|
49
|
-
sessionLCAliases[alias.toLowerCase()] = refName
|
|
50
44
|
}
|
|
51
45
|
}
|
|
52
|
-
assembly.setRefNameAliases(sessionAliases
|
|
46
|
+
assembly.setRefNameAliases(sessionAliases)
|
|
53
47
|
return Promise.resolve()
|
|
54
48
|
}
|
|
55
49
|
|
|
@@ -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`)
|
|
@@ -75,7 +75,7 @@ export function filterJBrowseConfig(config: JBrowseConfig): JBrowseConfig {
|
|
|
75
75
|
filteredConfig.plugins = plugins.filter((p) => p.name !== 'Apollo')
|
|
76
76
|
}
|
|
77
77
|
if (tracks) {
|
|
78
|
-
filteredConfig.
|
|
78
|
+
filteredConfig.tracks = tracks.filter((t) => t.type !== 'ApolloTrack')
|
|
79
79
|
}
|
|
80
80
|
return filteredConfig
|
|
81
81
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable unicorn/prefer-structured-clone */
|
|
1
2
|
/* eslint-disable @typescript-eslint/require-await */
|
|
2
3
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
3
4
|
|
|
@@ -11,6 +12,8 @@ import {
|
|
|
11
12
|
} from '@apollo-annotation/common'
|
|
12
13
|
import { type AnnotationFeatureSnapshot } from '@apollo-annotation/mst'
|
|
13
14
|
|
|
15
|
+
import { attributesToRecords, stringifyAttributes } from '../util'
|
|
16
|
+
|
|
14
17
|
import { findAndDeleteChildFeature } from './DeleteFeatureChange'
|
|
15
18
|
import { UndoMergeExonsChange } from './UndoMergeExonsChange'
|
|
16
19
|
|
|
@@ -89,7 +92,15 @@ export class MergeExonsChange extends FeatureChange {
|
|
|
89
92
|
}
|
|
90
93
|
mergedExon.min = Math.min(firstExon.min, secondExon.min)
|
|
91
94
|
mergedExon.max = Math.max(firstExon.max, secondExon.max)
|
|
92
|
-
|
|
95
|
+
|
|
96
|
+
const mergedAttributes: Record<string, string[]> = mergedExon.attributes
|
|
97
|
+
? JSON.parse(JSON.stringify(mergedExon.attributes))
|
|
98
|
+
: {}
|
|
99
|
+
mergedAttributes.merged_with = [
|
|
100
|
+
stringifyAttributes(attributesToRecords(secondExon.attributes)),
|
|
101
|
+
]
|
|
102
|
+
mergedExon.attributes = mergedAttributes
|
|
103
|
+
|
|
93
104
|
const deletedIds = findAndDeleteChildFeature(
|
|
94
105
|
topLevelFeature,
|
|
95
106
|
secondExon._id,
|
|
@@ -123,11 +134,16 @@ export class MergeExonsChange extends FeatureChange {
|
|
|
123
134
|
}
|
|
124
135
|
mergedExon.setMin(Math.min(firstExon.min, secondExon.min))
|
|
125
136
|
mergedExon.setMax(Math.max(firstExon.max, secondExon.max))
|
|
126
|
-
|
|
127
|
-
mergedExon.
|
|
128
|
-
|
|
129
|
-
|
|
137
|
+
|
|
138
|
+
const mrg = mergedExon.attributes.get('merged_with')?.slice() ?? []
|
|
139
|
+
const mergedWith = stringifyAttributes(
|
|
140
|
+
attributesToRecords(secondExon.attributes),
|
|
141
|
+
)
|
|
142
|
+
if (!mrg.includes(mergedWith)) {
|
|
143
|
+
mrg.push(mergedWith)
|
|
130
144
|
}
|
|
145
|
+
mergedExon.setAttribute('merged_with', mrg)
|
|
146
|
+
|
|
131
147
|
mergedExon.parent?.deleteChild(secondExon._id)
|
|
132
148
|
}
|
|
133
149
|
}
|
|
@@ -151,35 +167,35 @@ export class MergeExonsChange extends FeatureChange {
|
|
|
151
167
|
)
|
|
152
168
|
}
|
|
153
169
|
|
|
154
|
-
mergeAttributes(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
): Record<string, string[]> {
|
|
158
|
-
|
|
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
|
-
}
|
|
170
|
+
// mergeAttributes(
|
|
171
|
+
// firstExon: AnnotationFeatureSnapshot,
|
|
172
|
+
// secondExon: AnnotationFeatureSnapshot,
|
|
173
|
+
// ): Record<string, string[]> {
|
|
174
|
+
// let mergedAttrs: Record<string, string[]> = {}
|
|
175
|
+
// if (firstExon.attributes) {
|
|
176
|
+
// // eslint-disable-next-line unicorn/prefer-structured-clone
|
|
177
|
+
// mergedAttrs = JSON.parse(JSON.stringify(firstExon.attributes))
|
|
178
|
+
// }
|
|
179
|
+
|
|
180
|
+
// if (secondExon.attributes) {
|
|
181
|
+
// // eslint-disable-next-line unicorn/prefer-structured-clone
|
|
182
|
+
// const attrs: Record<string, string[]> = JSON.parse(
|
|
183
|
+
// JSON.stringify(secondExon.attributes),
|
|
184
|
+
// )
|
|
185
|
+
// for (const key of Object.keys(attrs)) {
|
|
186
|
+
// if (key === '_id' || key === 'gff_id') {
|
|
187
|
+
// continue
|
|
188
|
+
// }
|
|
189
|
+
// if (!Object.keys(mergedAttrs).includes(key)) {
|
|
190
|
+
// mergedAttrs[key] = []
|
|
191
|
+
// }
|
|
192
|
+
// attrs[key].map((x) => {
|
|
193
|
+
// if (!mergedAttrs[key].includes(x)) {
|
|
194
|
+
// mergedAttrs[key].push(x)
|
|
195
|
+
// }
|
|
196
|
+
// })
|
|
197
|
+
// }
|
|
198
|
+
// }
|
|
199
|
+
// return mergedAttrs
|
|
200
|
+
// }
|
|
185
201
|
}
|
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
} from '@apollo-annotation/mst'
|
|
17
17
|
import { type Feature } from '@apollo-annotation/schemas'
|
|
18
18
|
import { doesIntersect2 } from '@jbrowse/core/util'
|
|
19
|
+
import { getSnapshot } from 'mobx-state-tree'
|
|
20
|
+
|
|
21
|
+
import { attributesToRecords, stringifyAttributes } from '../util'
|
|
19
22
|
|
|
20
23
|
import { findAndDeleteChildFeature } from './DeleteFeatureChange'
|
|
21
24
|
import { UndoMergeTranscriptsChange } from './UndoMergeTranscriptsChange'
|
|
@@ -42,6 +45,7 @@ interface SerializedMergeTranscriptsChangeMultiple
|
|
|
42
45
|
export type SerializedMergeTranscriptsChange =
|
|
43
46
|
| SerializedMergeTranscriptsChangeSingle
|
|
44
47
|
| SerializedMergeTranscriptsChangeMultiple
|
|
48
|
+
|
|
45
49
|
export class MergeTranscriptsChange extends FeatureChange {
|
|
46
50
|
typeName = 'MergeTranscriptsChange' as const
|
|
47
51
|
changes: MergeTranscriptsChangeDetails[]
|
|
@@ -50,6 +54,10 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
50
54
|
super(json, options)
|
|
51
55
|
this.changes = 'changes' in json ? json.changes : [json]
|
|
52
56
|
}
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/class-literal-property-style
|
|
58
|
+
get notification() {
|
|
59
|
+
return 'Transcripts successfully merged'
|
|
60
|
+
}
|
|
53
61
|
|
|
54
62
|
toJSON(): SerializedMergeTranscriptsChange {
|
|
55
63
|
const { assembly, changedIds, changes, typeName } = this
|
|
@@ -111,7 +119,21 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
111
119
|
) {
|
|
112
120
|
firstTranscript.min = Math.min(firstTranscript.min, secondTranscript.min)
|
|
113
121
|
firstTranscript.max = Math.max(firstTranscript.max, secondTranscript.max)
|
|
114
|
-
|
|
122
|
+
|
|
123
|
+
const mergedAttributes: Record<string, string[]> =
|
|
124
|
+
firstTranscript.attributes
|
|
125
|
+
? JSON.parse(JSON.stringify(firstTranscript.attributes))
|
|
126
|
+
: {}
|
|
127
|
+
if (secondTranscript.attributes) {
|
|
128
|
+
if (!Object.keys(mergedAttributes).includes('merged_with')) {
|
|
129
|
+
mergedAttributes.merged_with = []
|
|
130
|
+
}
|
|
131
|
+
mergedAttributes.merged_with.push(
|
|
132
|
+
stringifyAttributes(attributesToRecords(secondTranscript.attributes)),
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
firstTranscript.attributes = mergedAttributes
|
|
136
|
+
|
|
115
137
|
if (secondTranscript.children) {
|
|
116
138
|
for (const [, secondFeatureChild] of Object.entries(
|
|
117
139
|
secondTranscript.children,
|
|
@@ -133,9 +155,13 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
133
155
|
}
|
|
134
156
|
let merged = false
|
|
135
157
|
let mrgChild: Feature | undefined
|
|
136
|
-
|
|
158
|
+
let toDelete
|
|
159
|
+
for (const [, firstFeatureChild] of firstTranscript.children) {
|
|
137
160
|
if (!merged || !mrgChild) {
|
|
161
|
+
toDelete = false
|
|
138
162
|
mrgChild = firstFeatureChild
|
|
163
|
+
} else {
|
|
164
|
+
toDelete = true
|
|
139
165
|
}
|
|
140
166
|
if (
|
|
141
167
|
mrgChild.type === secondFeatureChild.type &&
|
|
@@ -163,9 +189,36 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
163
189
|
mrgChild.max,
|
|
164
190
|
firstFeatureChild.max,
|
|
165
191
|
)
|
|
166
|
-
|
|
167
|
-
mrgChild.attributes
|
|
168
|
-
|
|
192
|
+
|
|
193
|
+
if (!mrgChild.attributes) {
|
|
194
|
+
mrgChild.attributes = {}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const mrgChildAttr: Record<string, string[]> = JSON.parse(
|
|
198
|
+
JSON.stringify(mrgChild.attributes),
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
if (!Object.keys(mrgChildAttr).includes('merged_with')) {
|
|
202
|
+
mrgChildAttr.merged_with = []
|
|
203
|
+
}
|
|
204
|
+
const mergedWithAttributes = mrgChildAttr.merged_with
|
|
205
|
+
mergedWithAttributes.push(
|
|
206
|
+
stringifyAttributes(
|
|
207
|
+
attributesToRecords(secondFeatureChild.attributes),
|
|
208
|
+
),
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if (toDelete) {
|
|
212
|
+
const recs: Record<string, string[] | undefined> =
|
|
213
|
+
firstFeatureChild.attributes
|
|
214
|
+
? JSON.parse(JSON.stringify(firstFeatureChild.attributes))
|
|
215
|
+
: undefined
|
|
216
|
+
mergedWithAttributes.push(stringifyAttributes(recs))
|
|
217
|
+
firstTranscript.children.delete(firstFeatureChild._id.toString())
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
mrgChildAttr.merged_with = [...new Set(mergedWithAttributes)]
|
|
221
|
+
mrgChild.attributes = mrgChildAttr
|
|
169
222
|
merged = true
|
|
170
223
|
}
|
|
171
224
|
}
|
|
@@ -215,7 +268,16 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
215
268
|
firstTranscript.setMin(Math.min(firstTranscript.min, secondTranscript.min))
|
|
216
269
|
firstTranscript.setMax(Math.max(firstTranscript.max, secondTranscript.max))
|
|
217
270
|
|
|
218
|
-
|
|
271
|
+
const mrg = firstTranscript.attributes.get('merged_with')?.slice() ?? []
|
|
272
|
+
const mergedWith = stringifyAttributes(
|
|
273
|
+
attributesToRecords(secondTranscript.attributes),
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
if (!mrg.includes(mergedWith)) {
|
|
277
|
+
// executeOnClient runs twice (?!) so avoid adding this key again
|
|
278
|
+
mrg.push(mergedWith)
|
|
279
|
+
}
|
|
280
|
+
firstTranscript.setAttribute('merged_with', mrg)
|
|
219
281
|
|
|
220
282
|
if (secondTranscript.children) {
|
|
221
283
|
for (const [, secondFeatureChild] of Object.entries(
|
|
@@ -269,15 +331,20 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
269
331
|
Math.max(secondFeatureChild.max, mrgChild.max, firstFeatureChild.max),
|
|
270
332
|
)
|
|
271
333
|
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
334
|
+
const mergedWithAttributes =
|
|
335
|
+
mrgChild.attributes.get('merged_with')?.slice() ?? []
|
|
336
|
+
mergedWithAttributes.push(
|
|
337
|
+
stringifyAttributes(
|
|
338
|
+
attributesToRecords(secondFeatureChild.attributes),
|
|
339
|
+
),
|
|
340
|
+
)
|
|
278
341
|
if (toDelete) {
|
|
342
|
+
mergedWithAttributes.push(
|
|
343
|
+
stringifyAttributes(getSnapshot(firstFeatureChild).attributes),
|
|
344
|
+
)
|
|
279
345
|
firstTranscript.deleteChild(firstFeatureChild._id)
|
|
280
346
|
}
|
|
347
|
+
mrgChild.setAttribute('merged_with', [...new Set(mergedWithAttributes)])
|
|
281
348
|
merged = true
|
|
282
349
|
}
|
|
283
350
|
}
|
|
@@ -288,71 +355,19 @@ export class MergeTranscriptsChange extends FeatureChange {
|
|
|
288
355
|
})
|
|
289
356
|
}
|
|
290
357
|
|
|
291
|
-
if (
|
|
358
|
+
if (merged && mrgChild) {
|
|
359
|
+
firstTranscript.addChild(getSnapshot(mrgChild))
|
|
360
|
+
} else {
|
|
292
361
|
// This secondFeatureChild has no overlap with any feature in the
|
|
293
362
|
// receiving transcript so we add it as it is to the receiving transcript
|
|
294
363
|
firstTranscript.addChild(secondFeatureChild)
|
|
295
364
|
}
|
|
296
365
|
}
|
|
297
366
|
|
|
298
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
299
|
-
isAnnotationFeature(obj: any): obj is AnnotationFeature {
|
|
300
|
-
return (
|
|
301
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
302
|
-
typeof obj.setMin === 'function' &&
|
|
303
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
304
|
-
typeof obj.setMax === 'function' &&
|
|
305
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
306
|
-
typeof obj.addChild === 'function' &&
|
|
307
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
308
|
-
typeof obj.deleteChild === 'function'
|
|
309
|
-
)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
367
|
async executeOnLocalGFF3(_backend: LocalGFF3DataStore) {
|
|
313
368
|
throw new Error('executeOnLocalGFF3 not implemented')
|
|
314
369
|
}
|
|
315
370
|
|
|
316
|
-
/* Merge attributes from source into destination */
|
|
317
|
-
mergeAttributes(
|
|
318
|
-
destination: Feature | AnnotationFeature,
|
|
319
|
-
source: AnnotationFeatureSnapshot,
|
|
320
|
-
): Record<string, string[]> {
|
|
321
|
-
const destAttrs: Record<string, string[]> = destination.attributes
|
|
322
|
-
? JSON.parse(JSON.stringify(destination.attributes))
|
|
323
|
-
: {}
|
|
324
|
-
if (source.attributes) {
|
|
325
|
-
const sourceAttrs: Record<string, string[]> = JSON.parse(
|
|
326
|
-
JSON.stringify(source.attributes),
|
|
327
|
-
)
|
|
328
|
-
Object.entries(sourceAttrs).map(([key, value]) => {
|
|
329
|
-
if (!(key in destAttrs)) {
|
|
330
|
-
destAttrs[key] = []
|
|
331
|
-
}
|
|
332
|
-
value.map((x) => {
|
|
333
|
-
if (!destAttrs[key].includes(x)) {
|
|
334
|
-
destAttrs[key].push(x)
|
|
335
|
-
}
|
|
336
|
-
})
|
|
337
|
-
})
|
|
338
|
-
}
|
|
339
|
-
return destAttrs
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
mergeTranscriptAttributes(
|
|
343
|
-
firstTranscript: Feature | AnnotationFeature,
|
|
344
|
-
secondTranscript: AnnotationFeatureSnapshot,
|
|
345
|
-
) {
|
|
346
|
-
const txAttrs = this.mergeAttributes(firstTranscript, secondTranscript)
|
|
347
|
-
if (this.isAnnotationFeature(firstTranscript)) {
|
|
348
|
-
Object.entries(txAttrs).map(([key, value]) => {
|
|
349
|
-
firstTranscript.setAttribute(key, value)
|
|
350
|
-
})
|
|
351
|
-
} else {
|
|
352
|
-
firstTranscript.attributes = txAttrs
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
371
|
getInverse() {
|
|
357
372
|
const { assembly, changedIds, changes, logger } = this
|
|
358
373
|
const inverseChangedIds = [...changedIds].reverse()
|