@datagrok/sequence-translator 1.0.5 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/detectors.js +10 -8
- package/dist/package-test.js +46 -31
- package/dist/package.js +116 -85
- package/package.json +8 -4
- package/src/__jest__/remote.test.ts +4 -4
- package/src/__jest__/test-node.ts +3 -2
- package/src/autostart/registration.ts +49 -37
- package/src/structures-works/converters.ts +3 -3
- package/src/structures-works/from-monomers.ts +1 -1
- package/src/structures-works/map.ts +6 -0
- package/src/structures-works/mol-transformations.ts +17 -15
- package/src/structures-works/save-sense-antisense.ts +24 -11
- package/src/structures-works/sequence-codes-tools.ts +12 -4
- package/test-SequenceTranslator-d3cbf13cf137-2cb8277f.html +276 -0
- package/test-SequenceTranslator-4f0c8bae6479-6545fe31.html +0 -276
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/sequence-translator",
|
|
3
3
|
"friendlyName": "Sequence Translator",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.6",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Vadym Kovadlo",
|
|
7
7
|
"email": "vkovadlo@datagrok.ai"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@datagrok-libraries/utils": "^0.1.0",
|
|
17
17
|
"@types/react": "^18.0.15",
|
|
18
|
-
"datagrok-api": "^1.
|
|
18
|
+
"datagrok-api": "^1.6.0",
|
|
19
19
|
"datagrok-tools": "^4.1.2",
|
|
20
20
|
"npm": "^8.11.0",
|
|
21
21
|
"openchemlib": "6.0.1",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"release-sequencetranslator-public": "grok publish public --release",
|
|
34
34
|
"debug-sequencetranslator-local": "grok publish local",
|
|
35
35
|
"release-sequencetranslator-local": "grok publish local --release",
|
|
36
|
-
"test": "
|
|
36
|
+
"test": "jest",
|
|
37
37
|
"test-dev": "set HOST=dev && jest",
|
|
38
38
|
"test-local": "set HOST=localhost && jest"
|
|
39
39
|
},
|
|
@@ -54,7 +54,11 @@
|
|
|
54
54
|
"puppeteer": "^13.7.0",
|
|
55
55
|
"ts-jest": "^27.0.0",
|
|
56
56
|
"webpack": "^5.31.0",
|
|
57
|
-
"webpack-cli": "^4.6.0"
|
|
57
|
+
"webpack-cli": "^4.6.0",
|
|
58
|
+
"@types/js-yaml": "^4.0.5",
|
|
59
|
+
"js-yaml": "^4.1.0",
|
|
60
|
+
"@types/node-fetch": "^2.6.2",
|
|
61
|
+
"node-fetch": "^2.6.7"
|
|
58
62
|
},
|
|
59
63
|
"category": "Bioinformatics"
|
|
60
64
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import * as utils from './test-node';
|
|
6
6
|
import puppeteer from 'puppeteer';
|
|
7
7
|
|
|
8
|
-
const P_START_TIMEOUT: number =
|
|
8
|
+
const P_START_TIMEOUT: number = 3600000;
|
|
9
9
|
let browser: puppeteer.Browser;
|
|
10
10
|
let page: puppeteer.Page;
|
|
11
11
|
|
|
@@ -51,10 +51,10 @@ it('TEST', async () => {
|
|
|
51
51
|
let failReport = '';
|
|
52
52
|
for (let i = 0; i < df.rowCount; i++) {
|
|
53
53
|
if (cStatus.get(i)) {
|
|
54
|
-
passReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
54
|
+
passReport += `Test result : Success : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
55
55
|
} else {
|
|
56
56
|
failed = true;
|
|
57
|
-
failReport += `Test result : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
57
|
+
failReport += `Test result : Failed : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
resolve({failReport, passReport, failed});
|
|
@@ -65,4 +65,4 @@ it('TEST', async () => {
|
|
|
65
65
|
console.log(r.passReport);
|
|
66
66
|
// @ts-ignore
|
|
67
67
|
expect(r.failed).checkOutput(false, r.failReport);
|
|
68
|
-
},
|
|
68
|
+
}, 3600000);
|
|
@@ -67,6 +67,7 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
let page = await browser.newPage();
|
|
70
|
+
await page.setDefaultNavigationTimeout(0);
|
|
70
71
|
await page.goto(`${url}/oauth/`);
|
|
71
72
|
await page.setCookie({name: 'auth', value: token});
|
|
72
73
|
await page.evaluate((token: any) => {
|
|
@@ -74,8 +75,8 @@ export async function getBrowserPage(puppeteer: any): Promise<{browser: any, pag
|
|
|
74
75
|
}, token);
|
|
75
76
|
await page.goto(url);
|
|
76
77
|
try {
|
|
77
|
-
await page.waitForSelector('.grok-preloader');
|
|
78
|
-
await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout:
|
|
78
|
+
await page.waitForSelector('.grok-preloader', { timeout: 1800000 });
|
|
79
|
+
await page.waitForFunction(() => document.querySelector('.grok-preloader') == null, {timeout: 3600000});
|
|
79
80
|
} catch (error) {
|
|
80
81
|
throw error;
|
|
81
82
|
}
|
|
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
|
|
|
4
4
|
import {siRnaAxolabsToGcrs, gcrsToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12,
|
|
5
5
|
} from '../structures-works/converters';
|
|
6
6
|
import {map, COL_NAMES, MODIFICATIONS} from '../structures-works/map';
|
|
7
|
-
import {getFormat} from '../structures-works/sequence-codes-tools';
|
|
7
|
+
import {getFormat, isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
8
8
|
import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
9
9
|
|
|
10
10
|
import {SALTS_CSV} from '../salts';
|
|
@@ -13,16 +13,6 @@ import {ICDS} from '../ICDs';
|
|
|
13
13
|
import {SOURCES} from '../sources';
|
|
14
14
|
import {IDPS} from '../IDPs';
|
|
15
15
|
|
|
16
|
-
const weightsObj: {[code: string]: number} = {};
|
|
17
|
-
for (const synthesizer of Object.keys(map)) {
|
|
18
|
-
for (const technology of Object.keys(map[synthesizer])) {
|
|
19
|
-
for (const code of Object.keys(map[synthesizer][technology]))
|
|
20
|
-
weightsObj[code] ?? map[synthesizer][technology][code].weight;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
for (const [key, value] of Object.entries(MODIFICATIONS))
|
|
24
|
-
weightsObj[key] = value.molecularWeight;
|
|
25
|
-
|
|
26
16
|
|
|
27
17
|
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
28
18
|
return array.sort(function(a, b) {return b.length - a.length;});
|
|
@@ -56,7 +46,7 @@ async function saveTableAsSdFile(table: DG.DataFrame) {
|
|
|
56
46
|
const typeColumn = table.getCol(COL_NAMES.TYPE);
|
|
57
47
|
let result = '';
|
|
58
48
|
for (let i = 0; i < table.rowCount; i++) {
|
|
59
|
-
const format = getFormat(structureColumn.get(i))!;
|
|
49
|
+
const format = 'Janssen GCRS Codes'; //getFormat(structureColumn.get(i))!;
|
|
60
50
|
result += (typeColumn.get(i) == 'SS') ?
|
|
61
51
|
sequenceToMolV3000(structureColumn.get(i), false, true, format) + '\n' + `> <Sequence>\nSense Strand\n\n` :
|
|
62
52
|
sequenceToMolV3000(structureColumn.get(i), true, true, format) + '\n' + `> <Sequence>\nAnti Sense\n\n`;
|
|
@@ -78,14 +68,16 @@ export function autostartOligoSdFileSubscription() {
|
|
|
78
68
|
if (v.dataFrame.columns.contains(COL_NAMES.TYPE))
|
|
79
69
|
oligoSdFile(v.dataFrame);
|
|
80
70
|
grok.events.onContextMenu.subscribe((args) => {
|
|
81
|
-
const seqCol = args.args.context.table.currentCol;
|
|
82
|
-
if (DG.Detector.sampleCategories(seqCol,
|
|
71
|
+
const seqCol = args.args.context.table.currentCol; // /^[fsACGUacgu]{6,}$/
|
|
72
|
+
if (DG.Detector.sampleCategories(seqCol,
|
|
73
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|f|s|A|C|G|U|a|c|g|u){6,}$/.test(s))) {
|
|
83
74
|
args.args.menu.item('Convert Axolabs to GCRS', () => {
|
|
84
75
|
args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
|
|
85
76
|
return siRnaAxolabsToGcrs(seqCol.get(i));
|
|
86
77
|
});
|
|
87
|
-
});
|
|
88
|
-
} else if (DG.Detector.sampleCategories(seqCol,
|
|
78
|
+
}); // /^[fmpsACGU]{6,}$/
|
|
79
|
+
} else if (DG.Detector.sampleCategories(seqCol,
|
|
80
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|f|m|ps|A|C|G|U){6,}$/.test(s)) ||
|
|
89
81
|
DG.Detector.sampleCategories(seqCol, (s) => /^(?=.*moe)(?=.*5mC)(?=.*ps){6,}/.test(s))) {
|
|
90
82
|
args.args.menu.item('Convert GCRS to raw', () => {
|
|
91
83
|
args.args.context.table.columns.addNewString(seqCol.name + ' to raw').init((i: number) => {
|
|
@@ -96,15 +88,17 @@ export function autostartOligoSdFileSubscription() {
|
|
|
96
88
|
args.args.context.table.columns.addNewString(seqCol.name + ' to MM12').init((i: number) => {
|
|
97
89
|
return gcrsToMermade12(seqCol.get(i));
|
|
98
90
|
});
|
|
99
|
-
});
|
|
100
|
-
} else if (DG.Detector.sampleCategories(seqCol,
|
|
91
|
+
}); // /^[*56789ATGC]{6,}$/
|
|
92
|
+
} else if (DG.Detector.sampleCategories(seqCol,
|
|
93
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|5|6|7|8|9|A|T|G|C){6,}$/.test(s))) {
|
|
101
94
|
args.args.menu.item('Convert Biospring to GCRS', () => {
|
|
102
95
|
const seqCol = args.args.context.table.currentCol;
|
|
103
96
|
args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
|
|
104
97
|
return asoGapmersBioSpringToGcrs(seqCol.get(i));
|
|
105
98
|
});
|
|
106
|
-
});
|
|
107
|
-
} else if (DG.Detector.sampleCategories(seqCol,
|
|
99
|
+
}); // /^[*1-8]{6,}$/
|
|
100
|
+
} else if (DG.Detector.sampleCategories(seqCol,
|
|
101
|
+
(s) => /(\(invabasic\)|\(GalNAc-2-JNJ\)|\*|1|2|3|4|5|6|7|8){6,}$/.test(s))) {
|
|
108
102
|
args.args.menu.item('Convert Biospring to GCRS', () => {
|
|
109
103
|
args.args.context.table.columns.addNewString(seqCol.name + ' to GCRS').init((i: number) => {
|
|
110
104
|
return siRnaAxolabsToGcrs(seqCol.get(i));
|
|
@@ -123,29 +117,46 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
123
117
|
const icdsDf = DG.DataFrame.fromCsv(ICDS);
|
|
124
118
|
const idpsDf = DG.DataFrame.fromCsv(IDPS);
|
|
125
119
|
|
|
126
|
-
function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
120
|
+
async function addColumns(t: DG.DataFrame, saltsDf: DG.DataFrame) {
|
|
127
121
|
if (t.columns.contains(COL_NAMES.COMPOUND_NAME))
|
|
128
122
|
return grok.shell.error('Columns already exist');
|
|
129
123
|
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
124
|
+
const sequenceCol = t.getCol(COL_NAMES.SEQUENCE);
|
|
125
|
+
const saltCol = t.getCol(COL_NAMES.SALT);
|
|
126
|
+
const equivalentsCol = t.getCol(COL_NAMES.EQUIVALENTS);
|
|
127
|
+
|
|
128
|
+
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequenceCol.get(i));
|
|
133
129
|
|
|
134
|
-
t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => sequence.get(i));
|
|
135
130
|
t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => (i > 0 && i % 2 == 0) ?
|
|
136
|
-
|
|
137
|
-
|
|
131
|
+
sequenceCol.get(i) + '; duplex of SS: ' + sequenceCol.get(i - 2) + ' and AS: ' + sequenceCol.get(i - 1) :
|
|
132
|
+
sequenceCol.get(i),
|
|
138
133
|
);
|
|
139
134
|
const molWeightCol = saltsDf.getCol('MOLWEIGHT');
|
|
140
135
|
const saltNamesList = saltsDf.getCol('DISPLAY').toList();
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
const weightsObj: {[code: string]: number} = {};
|
|
137
|
+
for (const synthesizer of Object.keys(map)) {
|
|
138
|
+
for (const technology of Object.keys(map[synthesizer])) {
|
|
139
|
+
for (const code of Object.keys(map[synthesizer][technology]))
|
|
140
|
+
weightsObj[code] = map[synthesizer][technology][code].weight!;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
for (const [key, value] of Object.entries(MODIFICATIONS))
|
|
144
|
+
weightsObj[key] = value.molecularWeight;
|
|
145
|
+
|
|
146
|
+
t.columns.addNewFloat(COL_NAMES.CPD_MW).init((i: number) => {
|
|
147
|
+
return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
|
|
148
|
+
molecularWeight(sequenceCol.get(i), weightsObj) :
|
|
149
|
+
DG.FLOAT_NULL;
|
|
150
|
+
});
|
|
151
|
+
|
|
143
152
|
t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) => {
|
|
144
|
-
const saltRowIndex = saltNamesList.indexOf(
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
|
|
154
|
+
return (saltRowIndex == -1) ?
|
|
155
|
+
DG.FLOAT_NULL :
|
|
156
|
+
molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
|
|
147
157
|
});
|
|
148
|
-
|
|
158
|
+
|
|
159
|
+
await t.columns.addNewCalculated(COL_NAMES.BATCH_MW,
|
|
149
160
|
'${' + COL_NAMES.CPD_MW + '} + ${' + COL_NAMES.SALT_MASS + '}', DG.COLUMN_TYPE.FLOAT, false,
|
|
150
161
|
);
|
|
151
162
|
|
|
@@ -162,11 +173,12 @@ export function oligoSdFile(table: DG.DataFrame) {
|
|
|
162
173
|
if (table.getCol(COL_NAMES.IDP).type != DG.COLUMN_TYPE.STRING)
|
|
163
174
|
table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
|
|
164
175
|
d.append(
|
|
165
|
-
ui.link('Add Columns', () => {
|
|
166
|
-
addColumns(table, saltsDf);
|
|
167
|
-
|
|
176
|
+
ui.link('Add Columns', async () => {
|
|
177
|
+
await addColumns(table, saltsDf);
|
|
178
|
+
view.grid.columns.setOrder(Object.values(COL_NAMES));
|
|
168
179
|
}, 'Add columns: \'' + [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
|
|
169
|
-
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), ''
|
|
180
|
+
COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), '',
|
|
181
|
+
),
|
|
170
182
|
ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
|
|
171
183
|
);
|
|
172
184
|
|
|
@@ -16,9 +16,9 @@ export function gcrsToLcms(sequence: string): string {
|
|
|
16
16
|
}
|
|
17
17
|
const regExp = new RegExp('(' + arr1.join('|') + ')', 'g');
|
|
18
18
|
let r1 = sequence.replace(regExp, function(code) {return obj[code];});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return r1
|
|
19
|
+
while (r1.indexOf('//') != -1)
|
|
20
|
+
r1 = r1.replace('//', '/');
|
|
21
|
+
return r1;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
//name: asoGapmersNucleotidesToBioSpring
|
|
@@ -36,7 +36,7 @@ export function sequenceToMolV3000(sequence: string, inverted: boolean = false,
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
return getNucleotidesMol(smilesCodes
|
|
39
|
+
return getNucleotidesMol(smilesCodes);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export function sequenceToSmiles(sequence: string, inverted: boolean = false, format: string): string {
|
|
@@ -340,6 +340,12 @@ export const map: {[synthesizer: string]:
|
|
|
340
340
|
'normalized': '',
|
|
341
341
|
'SMILES': 'OP(=O)(S)O',
|
|
342
342
|
},
|
|
343
|
+
's': {
|
|
344
|
+
'name': 'ps linkage',
|
|
345
|
+
'weight': 16.07,
|
|
346
|
+
'normalized': '',
|
|
347
|
+
'SMILES': 'OP(=O)(S)O',
|
|
348
|
+
},
|
|
343
349
|
'A': {
|
|
344
350
|
'name': 'Adenine',
|
|
345
351
|
'weight': 313.21,
|
|
@@ -78,7 +78,7 @@ M V30 END COLLECTION
|
|
|
78
78
|
M V30 END CTAB
|
|
79
79
|
M END`;
|
|
80
80
|
|
|
81
|
-
export function getNucleotidesMol(smilesCodes: string[]
|
|
81
|
+
export function getNucleotidesMol(smilesCodes: string[]) {
|
|
82
82
|
const molBlocks: string[] = [];
|
|
83
83
|
|
|
84
84
|
for (let i = 0; i < smilesCodes.length - 1; i++) {
|
|
@@ -88,10 +88,10 @@ export function getNucleotidesMol(smilesCodes: string[], oclRender: boolean = fa
|
|
|
88
88
|
molBlocks.push(rotateNucleotidesV3000(smilesCodes[i]));
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
return linkV3000(molBlocks, false
|
|
91
|
+
return linkV3000(molBlocks, false);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
export function linkV3000(molBlocks: string[], twoChains: boolean = false,
|
|
94
|
+
export function linkV3000(molBlocks: string[], twoChains: boolean = false, useChirality: boolean = true) {
|
|
95
95
|
let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
|
|
96
96
|
macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
|
|
97
97
|
macroMolBlock += 'M V30 BEGIN CTAB\n';
|
|
@@ -213,14 +213,14 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
|
|
|
213
213
|
const entries = 4;
|
|
214
214
|
const collNumber = Math.ceil(collection.length / entries);
|
|
215
215
|
|
|
216
|
-
if (oclRender) {
|
|
217
|
-
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
216
|
+
//if (oclRender) {
|
|
217
|
+
// collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
218
218
|
|
|
219
|
-
for (let j = 0; j < collection.length; j++)
|
|
220
|
-
|
|
219
|
+
// for (let j = 0; j < collection.length; j++)
|
|
220
|
+
// collectionBlock += ' ' + collection[j];
|
|
221
221
|
|
|
222
|
-
collectionBlock += ')\n';
|
|
223
|
-
} else {
|
|
222
|
+
// collectionBlock += ')\n';
|
|
223
|
+
//} else {
|
|
224
224
|
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
|
|
225
225
|
for (let i = 0; i < collNumber; i++) {
|
|
226
226
|
collectionBlock += 'M V30 ';
|
|
@@ -231,7 +231,7 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
|
|
|
231
231
|
collection[entries*i + j] + ' ';
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
|
-
}
|
|
234
|
+
//}
|
|
235
235
|
|
|
236
236
|
//generate file
|
|
237
237
|
twoChains? natom : natom++;
|
|
@@ -242,14 +242,16 @@ export function linkV3000(molBlocks: string[], twoChains: boolean = false, oclRe
|
|
|
242
242
|
macroMolBlock += 'M V30 BEGIN BOND\n';
|
|
243
243
|
macroMolBlock += bondBlock;
|
|
244
244
|
macroMolBlock += 'M V30 END BOND\n';
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
if(useChirality){
|
|
246
|
+
macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
247
|
+
macroMolBlock += collectionBlock;
|
|
248
|
+
macroMolBlock += 'M V30 END COLLECTION\n';
|
|
249
|
+
} else
|
|
250
|
+
macroMolBlock = macroMolBlock.replace(/ CFG=\d/g, ' ');
|
|
251
|
+
|
|
248
252
|
macroMolBlock += 'M V30 END CTAB\n';
|
|
249
253
|
macroMolBlock += 'M END\n';
|
|
250
254
|
|
|
251
|
-
macroMolBlock = macroMolBlock.replaceAll('CFG=1', '').replaceAll('CFG=2', '').replaceAll('CFG=3', '').replaceAll('CFG=4', '');
|
|
252
|
-
|
|
253
255
|
return macroMolBlock;
|
|
254
256
|
}
|
|
255
257
|
|
|
@@ -3,14 +3,14 @@ import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
|
3
3
|
import {linkV3000} from '../structures-works/mol-transformations';
|
|
4
4
|
import {getFormat} from '../structures-works/sequence-codes-tools';
|
|
5
5
|
|
|
6
|
-
export function saveSdf(as: string, ss: string, oneEntity: boolean,
|
|
6
|
+
export function saveSdf(as: string, ss: string, oneEntity: boolean, useChirality: boolean, invertSS: boolean, invertAS: boolean) {
|
|
7
7
|
const formatAs = getFormat(as);
|
|
8
8
|
const formatSs = getFormat(ss);
|
|
9
|
-
const molSS = sequenceToMolV3000(ss,
|
|
10
|
-
const molAS = sequenceToMolV3000(as,
|
|
9
|
+
const molSS = sequenceToMolV3000(ss, invertSS, false, formatSs!);
|
|
10
|
+
const molAS = sequenceToMolV3000(as, invertAS, false, formatAs!);
|
|
11
11
|
let result: string;
|
|
12
12
|
if (oneEntity)
|
|
13
|
-
result = linkV3000([molSS, molAS], true,
|
|
13
|
+
result = linkV3000([molSS, molAS], true, useChirality) + '\n\n$$$$\n';
|
|
14
14
|
else {
|
|
15
15
|
result =
|
|
16
16
|
molSS + '\n' +
|
|
@@ -27,22 +27,35 @@ export function saveSdf(as: string, ss: string, oneEntity: boolean, fit3dx: bool
|
|
|
27
27
|
|
|
28
28
|
export function saveSenseAntiSense() {
|
|
29
29
|
const moleculeSvgDiv = ui.block([]);
|
|
30
|
-
const ssInput = ui.textInput('Sense Strand
|
|
31
|
-
const asInput = ui.textInput('Anti Sense
|
|
30
|
+
const ssInput = ui.textInput('Sense Strand', '');
|
|
31
|
+
const asInput = ui.textInput('Anti Sense', '');
|
|
32
|
+
const straight = '5\' ->3\'';
|
|
33
|
+
const inverse = '3\' ->5\'';
|
|
34
|
+
let ssInverse = false;
|
|
35
|
+
let asInverse = false;
|
|
36
|
+
|
|
37
|
+
const changeSense = ui.choiceInput('SS direction', straight, [straight, inverse]);
|
|
38
|
+
changeSense.onChanged(() => {ssInverse = changeSense.value == inverse;});
|
|
39
|
+
const changeAntiSense = ui.choiceInput('AS direction', straight, [straight, inverse]);
|
|
40
|
+
changeAntiSense.onChanged(() => {asInverse = changeAntiSense.value == inverse;});
|
|
41
|
+
|
|
32
42
|
const saveOption = ui.switchInput('Save as one entity', true);
|
|
33
|
-
const
|
|
43
|
+
const chirality = ui.switchInput('Use chiral', true);
|
|
34
44
|
const saveBtn = ui.button('Save SDF', () =>
|
|
35
|
-
saveSdf(asInput.value, ssInput.value, saveOption.value,
|
|
45
|
+
saveSdf(asInput.value, ssInput.value, saveOption.value, chirality.value, ssInverse, asInverse));
|
|
36
46
|
|
|
37
47
|
const saveSection = ui.panel([
|
|
38
48
|
ui.div([
|
|
39
49
|
ui.div([
|
|
40
50
|
ui.divH([ui.h1('Inputs')]),
|
|
41
51
|
ui.divV([
|
|
42
|
-
|
|
43
|
-
|
|
52
|
+
ssInput,
|
|
53
|
+
asInput,
|
|
54
|
+
ui.div([changeSense], {style: {width: '40'}}),
|
|
55
|
+
changeSense,
|
|
56
|
+
changeAntiSense,
|
|
44
57
|
saveOption,
|
|
45
|
-
|
|
58
|
+
chirality,
|
|
46
59
|
ui.buttonsInput([saveBtn]),
|
|
47
60
|
], 'ui-form'),
|
|
48
61
|
], 'ui-form'),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
import {map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, delimiter} from './map';
|
|
2
|
+
import {map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, delimiter, gcrsCodesWithoutSmiles} from './map';
|
|
3
3
|
import {asoGapmersNucleotidesToBioSpring, asoGapmersNucleotidesToGcrs,
|
|
4
4
|
asoGapmersBioSpringToNucleotides, asoGapmersBioSpringToGcrs, asoGapmersGcrsToNucleotides,
|
|
5
5
|
asoGapmersGcrsToBioSpring, gcrsToMermade12, siRnaNucleotideToBioSpringSenseStrand,
|
|
@@ -88,6 +88,10 @@ export function getFormat(sequence: string): string | null {
|
|
|
88
88
|
return possibleSynthesizers[0];
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function sortByStringLengthInDescendingOrder(array: string[]): string[] {
|
|
92
|
+
return array.sort(function(a: string, b: string) {return b.length - a.length;});
|
|
93
|
+
}
|
|
94
|
+
|
|
91
95
|
export function isValidSequence(sequence: string, format: string | null): {
|
|
92
96
|
indexOfFirstNotValidChar: number,
|
|
93
97
|
synthesizer: string[] | null,
|
|
@@ -118,7 +122,7 @@ export function isValidSequence(sequence: string, format: string | null): {
|
|
|
118
122
|
const nucleotides = ['A', 'U', 'T', 'C', 'G'];
|
|
119
123
|
|
|
120
124
|
possibleSynthesizers.forEach((synthesizer) => {
|
|
121
|
-
const codes = getAllCodesOfSynthesizer(synthesizer);
|
|
125
|
+
const codes = sortByStringLengthInDescendingOrder(getAllCodesOfSynthesizer(synthesizer));
|
|
122
126
|
while (outputIndex < sequence.length) {
|
|
123
127
|
const matchedCode = codes.find((c) => c == sequence.slice(outputIndex, outputIndex + c.length));
|
|
124
128
|
|
|
@@ -212,9 +216,11 @@ export function getAllCodesOfSynthesizer(synthesizer: string): string[] {
|
|
|
212
216
|
}
|
|
213
217
|
|
|
214
218
|
function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): string[] {
|
|
215
|
-
|
|
219
|
+
let synthesizers: string[] = [];
|
|
216
220
|
Object.keys(map).forEach((synthesizer: string) => {
|
|
217
|
-
|
|
221
|
+
let codes = sortByStringLengthInDescendingOrder(getAllCodesOfSynthesizer(synthesizer));
|
|
222
|
+
if (synthesizer == 'Janssen GCRS Codes')
|
|
223
|
+
codes = codes.concat(gcrsCodesWithoutSmiles);
|
|
218
224
|
//TODO: get first non-dropdown code when there are two modifications
|
|
219
225
|
let start = 0;
|
|
220
226
|
for (let i = 0; i < sequence.length; i++) {
|
|
@@ -223,6 +229,8 @@ function getListOfPossibleSynthesizersByFirstMatchedCode(sequence: string): stri
|
|
|
223
229
|
break;
|
|
224
230
|
}
|
|
225
231
|
}
|
|
232
|
+
if (gcrsCodesWithoutSmiles.some((s: string) => s == sequence.slice(start, start + s.length)))
|
|
233
|
+
synthesizers = ['Janssen GCRS Codes'];
|
|
226
234
|
if (codes.some((s: string) => s == sequence.slice(start, start + s.length)))
|
|
227
235
|
synthesizers.push(synthesizer);
|
|
228
236
|
});
|