@datagrok/sequence-translator 1.0.12 → 1.0.14
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/package-test.js +70739 -1417
- package/dist/package.js +70546 -4914
- package/package.json +6 -4
- package/scripts/build-monomer-lib.py +140 -0
- package/setup-unlink-clean.cmd +14 -0
- package/setup.cmd +14 -11
- package/setup.sh +37 -0
- package/src/__jest__/remote.test.ts +11 -3
- package/src/{ICDs.ts → autostart/ICDs.ts} +0 -0
- package/src/{IDPs.ts → autostart/IDPs.ts} +0 -0
- package/src/autostart/calculations.ts +37 -0
- package/src/autostart/constants.ts +49 -0
- package/src/autostart/registration.ts +101 -122
- package/src/{salts.ts → autostart/salts.ts} +0 -0
- package/src/{sources.ts → autostart/sources.ts} +0 -0
- package/src/{users.ts → autostart/users.ts} +0 -0
- package/src/axolabs/constants.ts +10 -10
- package/src/axolabs/define-pattern.ts +13 -12
- package/src/axolabs/draw-svg.ts +140 -201
- package/src/axolabs/helpers.ts +94 -0
- package/src/helpers.ts +28 -0
- package/src/main/main-view.ts +85 -87
- package/src/package.ts +25 -8
- package/src/structures-works/const.ts +18 -0
- package/src/structures-works/converters.ts +3 -3
- package/src/structures-works/from-monomers.ts +185 -32
- package/src/structures-works/map.ts +20 -35
- package/src/structures-works/mol-transformations.ts +295 -582
- package/src/structures-works/save-sense-antisense.ts +35 -11
- package/src/structures-works/sequence-codes-tools.ts +9 -13
- package/{test-SequenceTranslator-49ff04f38f57-128d0678.html → test-SequenceTranslator-e8c06047b7e7-eb4db608.html} +10 -7
package/src/main/main-view.ts
CHANGED
|
@@ -2,20 +2,35 @@ import * as grok from 'datagrok-api/grok';
|
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
import {convertSequence, undefinedInputSequence, isValidSequence} from '../structures-works/sequence-codes-tools';
|
|
5
|
-
import {map
|
|
5
|
+
import {map} from '../structures-works/map';
|
|
6
|
+
import {MODIFICATIONS} from '../structures-works/const';
|
|
6
7
|
import {sequenceToSmiles, sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
7
8
|
import $ from 'cash-dom';
|
|
9
|
+
import {download} from '../helpers';
|
|
8
10
|
|
|
9
|
-
const defaultInput = 'fAmCmGmAmCpsmU';
|
|
10
|
-
const sequenceWasCopied = 'Copied';
|
|
11
|
+
const defaultInput = 'fAmCmGmAmCpsmU'; // todo: capitalize constants
|
|
12
|
+
const sequenceWasCopied = 'Copied'; // todo: wrap hardcoded literals into constants
|
|
11
13
|
const tooltipSequence = 'Copy sequence';
|
|
12
14
|
|
|
13
|
-
export function mainView() {
|
|
14
|
-
|
|
15
|
+
export async function mainView(): Promise<HTMLDivElement> {
|
|
16
|
+
const monomersLibAddress = 'System:AppData/SequenceTranslator/helmLib.json';
|
|
17
|
+
async function updateTableAndMolecule(sequence: string, inputFormat: string): Promise<void> {
|
|
15
18
|
moleculeSvgDiv.innerHTML = '';
|
|
16
19
|
outputTableDiv.innerHTML = '';
|
|
17
20
|
const pi = DG.TaskBarProgressIndicator.create('Rendering table and molecule...');
|
|
18
21
|
let errorsExist = false;
|
|
22
|
+
|
|
23
|
+
// external helm-like monomers library
|
|
24
|
+
const fileExists = await grok.dapi.files.exists(monomersLibAddress);
|
|
25
|
+
if (!fileExists) {
|
|
26
|
+
// todo: improve behaviour in this case
|
|
27
|
+
grok.shell.warning('Please, provide the file with monomers library as System:AppData/SequenceTranslator/helmLib.json');
|
|
28
|
+
pi.close();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const monomersLib = await grok.dapi.files.readAsText(monomersLibAddress);
|
|
33
|
+
|
|
19
34
|
try {
|
|
20
35
|
sequence = sequence.replace(/\s/g, '');
|
|
21
36
|
const output = isValidSequence(sequence, null);
|
|
@@ -27,42 +42,21 @@ export function mainView() {
|
|
|
27
42
|
const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
28
43
|
JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
|
|
29
44
|
-1;
|
|
30
|
-
if ('indexOfFirstNotValidChar' in outputSequenceObj) {
|
|
31
|
-
const indexOfFirstNotValidChar = ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
32
|
-
JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).indexOfFirstNotValidChar :
|
|
33
|
-
-1;
|
|
34
|
-
if (indexOfFirstNotValidChar != -1)
|
|
35
|
-
errorsExist = true;
|
|
36
|
-
}
|
|
37
45
|
|
|
38
46
|
tableRows.push({
|
|
39
47
|
'key': key,
|
|
40
48
|
'value': ('indexOfFirstNotValidChar' in outputSequenceObj) ?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (errorsExist) {
|
|
55
|
-
const synthesizer = JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer.slice(0, -6);
|
|
56
|
-
asoGapmersGrid.onCellPrepare(function(gc) {
|
|
57
|
-
gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
58
|
-
});
|
|
59
|
-
omeAndFluoroGrid.onCellPrepare(function(gc) {
|
|
60
|
-
gc.style.backColor = (gc.gridColumn.name == synthesizer) ? 0xFFF00000 : 0xFFFFFFFF;
|
|
49
|
+
ui.divH([
|
|
50
|
+
ui.divText(sequence.slice(0, indexOfFirstNotValidChar), {style: {color: 'grey'}}),
|
|
51
|
+
ui.tooltip.bind(
|
|
52
|
+
ui.divText(sequence.slice(indexOfFirstNotValidChar), {style: {color: 'red'}}),
|
|
53
|
+
'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer +
|
|
54
|
+
'. See tables with valid codes on the right',
|
|
55
|
+
),
|
|
56
|
+
]) : //@ts-ignore
|
|
57
|
+
ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
|
|
58
|
+
.then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, ''),
|
|
61
59
|
});
|
|
62
|
-
switchInput.enabled = true;
|
|
63
|
-
} else {
|
|
64
|
-
asoGapmersGrid.onCellPrepare(function(gc) {gc.style.backColor = 0xFFFFFFFF;});
|
|
65
|
-
omeAndFluoroGrid.onCellPrepare(function(gc) {gc.style.backColor = 0xFFFFFFFF;});
|
|
66
60
|
}
|
|
67
61
|
|
|
68
62
|
outputTableDiv.append(
|
|
@@ -76,8 +70,11 @@ export function mainView() {
|
|
|
76
70
|
const canvas = ui.canvas(300, 170);
|
|
77
71
|
canvas.addEventListener('click', () => {
|
|
78
72
|
const canv = ui.canvas($(window).width(), $(window).height());
|
|
79
|
-
const mol = sequenceToMolV3000(
|
|
80
|
-
|
|
73
|
+
const mol = sequenceToMolV3000(
|
|
74
|
+
inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
75
|
+
output.synthesizer![0],
|
|
76
|
+
);
|
|
77
|
+
console.log(mol);
|
|
81
78
|
// @ts-ignore
|
|
82
79
|
OCL.StructureView.drawMolecule(canv, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
83
80
|
ui.dialog('Molecule: ' + inputSequenceField.value)
|
|
@@ -87,7 +84,7 @@ export function mainView() {
|
|
|
87
84
|
$(canvas).on('mouseover', () => $(canvas).css('cursor', 'zoom-in'));
|
|
88
85
|
$(canvas).on('mouseout', () => $(canvas).css('cursor', 'default'));
|
|
89
86
|
const mol = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, true,
|
|
90
|
-
|
|
87
|
+
output.synthesizer![0]);
|
|
91
88
|
// @ts-ignore
|
|
92
89
|
OCL.StructureView.drawMolecule(canvas, OCL.Molecule.fromMolfile(mol), {suppressChiralText: true});
|
|
93
90
|
moleculeSvgDiv.append(canvas);
|
|
@@ -108,46 +105,43 @@ export function mainView() {
|
|
|
108
105
|
updateTableAndMolecule(sequence, inputFormatChoiceInput.value!);
|
|
109
106
|
});
|
|
110
107
|
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
asoDf.onCurrentCellChanged.subscribe((_) => {
|
|
130
|
-
navigator.clipboard.writeText(asoDf.currentCell.value).then(() => grok.shell.info('Copied'));
|
|
131
|
-
});
|
|
108
|
+
const asoGapmersGrid = DG.Viewer.grid(
|
|
109
|
+
DG.DataFrame.fromObjects([
|
|
110
|
+
{'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
|
|
111
|
+
{'Name': '2\'MOE-rA', 'BioSpring': '6', 'Janssen GCRS': 'moeA'},
|
|
112
|
+
{'Name': '2\'MOE-5Me-rC', 'BioSpring': '7', 'Janssen GCRS': 'moe5mC'},
|
|
113
|
+
{'Name': '2\'MOE-rG', 'BioSpring': '8', 'Janssen GCRS': 'moeG'},
|
|
114
|
+
{'Name': '5-Methyl-dC', 'BioSpring': '9', 'Janssen GCRS': '5mC'},
|
|
115
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Janssen GCRS': 'ps'},
|
|
116
|
+
{'Name': 'dA', 'BioSpring': 'A', 'Janssen GCRS': 'A, dA'},
|
|
117
|
+
{'Name': 'dC', 'BioSpring': 'C', 'Janssen GCRS': 'C, dC'},
|
|
118
|
+
{'Name': 'dG', 'BioSpring': 'G', 'Janssen GCRS': 'G, dG'},
|
|
119
|
+
{'Name': 'dT', 'BioSpring': 'T', 'Janssen GCRS': 'T, dT'},
|
|
120
|
+
{'Name': 'rA', 'BioSpring': '', 'Janssen GCRS': 'rA'},
|
|
121
|
+
{'Name': 'rC', 'BioSpring': '', 'Janssen GCRS': 'rC'},
|
|
122
|
+
{'Name': 'rG', 'BioSpring': '', 'Janssen GCRS': 'rG'},
|
|
123
|
+
{'Name': 'rU', 'BioSpring': '', 'Janssen GCRS': 'rU'},
|
|
124
|
+
])!, {showRowHeader: false, showCellTooltip: false, allowEdit: false},
|
|
125
|
+
);
|
|
132
126
|
|
|
133
127
|
const omeAndFluoroGrid = DG.Viewer.grid(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
128
|
+
DG.DataFrame.fromObjects([
|
|
129
|
+
{'Name': '2\'-fluoro-U', 'BioSpring': '1', 'Axolabs': 'Uf', 'Janssen GCRS': 'fU'},
|
|
130
|
+
{'Name': '2\'-fluoro-A', 'BioSpring': '2', 'Axolabs': 'Af', 'Janssen GCRS': 'fA'},
|
|
131
|
+
{'Name': '2\'-fluoro-C', 'BioSpring': '3', 'Axolabs': 'Cf', 'Janssen GCRS': 'fC'},
|
|
132
|
+
{'Name': '2\'-fluoro-G', 'BioSpring': '4', 'Axolabs': 'Gf', 'Janssen GCRS': 'fG'},
|
|
133
|
+
{'Name': '2\'OMe-rU', 'BioSpring': '5', 'Axolabs': 'u', 'Janssen GCRS': 'mU'},
|
|
134
|
+
{'Name': '2\'OMe-rA', 'BioSpring': '6', 'Axolabs': 'a', 'Janssen GCRS': 'mA'},
|
|
135
|
+
{'Name': '2\'OMe-rC', 'BioSpring': '7', 'Axolabs': 'c', 'Janssen GCRS': 'mC'},
|
|
136
|
+
{'Name': '2\'OMe-rG', 'BioSpring': '8', 'Axolabs': 'g', 'Janssen GCRS': 'mG'},
|
|
137
|
+
{'Name': 'ps linkage', 'BioSpring': '*', 'Axolabs': 's', 'Janssen GCRS': 'ps'},
|
|
138
|
+
])!, {showRowHeader: false, showCellTooltip: false, allowEdit: false},
|
|
145
139
|
);
|
|
146
140
|
|
|
147
141
|
const overhangModificationsGrid = DG.Viewer.grid(
|
|
148
142
|
DG.DataFrame.fromColumns([
|
|
149
143
|
DG.Column.fromStrings('Name', Object.keys(MODIFICATIONS)),
|
|
150
|
-
])!, {showRowHeader: false, showCellTooltip: false},
|
|
144
|
+
])!, {showRowHeader: false, showCellTooltip: false, allowEdit: false},
|
|
151
145
|
);
|
|
152
146
|
updateTableAndMolecule(defaultInput, inputFormatChoiceInput.value!);
|
|
153
147
|
|
|
@@ -175,27 +169,31 @@ export function mainView() {
|
|
|
175
169
|
$(codesTablesDiv).hide(),
|
|
176
170
|
);
|
|
177
171
|
|
|
172
|
+
const downloadMolFileIcon = ui.iconFA('download', async () => {
|
|
173
|
+
const clearSequence = inputSequenceField.value.replace(/\s/g, '');
|
|
174
|
+
const monomersLib = await grok.dapi.files.readAsText(monomersLibAddress);
|
|
175
|
+
const result = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, false,
|
|
176
|
+
inputFormatChoiceInput.value!);
|
|
177
|
+
download(clearSequence + '.mol', encodeURIComponent(result));
|
|
178
|
+
}, 'Save .mol file');
|
|
179
|
+
|
|
180
|
+
const copySmilesIcon = ui.iconFA('copy', () => {
|
|
181
|
+
navigator.clipboard.writeText(
|
|
182
|
+
sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''), false, inputFormatChoiceInput.value!),
|
|
183
|
+
).then(() => grok.shell.info(sequenceWasCopied));
|
|
184
|
+
}, 'Copy SMILES');
|
|
185
|
+
|
|
178
186
|
const topPanel = [
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
inputFormatChoiceInput.value!);
|
|
182
|
-
const element = document.createElement('a');
|
|
183
|
-
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
184
|
-
element.setAttribute('download', inputSequenceField.value.replace(/\s/g, '') + '.mol');
|
|
185
|
-
element.click();
|
|
186
|
-
}, 'Save .mol file'),
|
|
187
|
-
ui.iconFA('copy', () => {
|
|
188
|
-
navigator.clipboard.writeText(
|
|
189
|
-
sequenceToSmiles(inputSequenceField.value.replace(/\s/g, ''), false, inputFormatChoiceInput.value!))
|
|
190
|
-
.then(() => grok.shell.info(sequenceWasCopied));
|
|
191
|
-
}, 'Copy SMILES'),
|
|
187
|
+
downloadMolFileIcon,
|
|
188
|
+
copySmilesIcon,
|
|
192
189
|
switchInput.root,
|
|
193
190
|
];
|
|
194
191
|
|
|
195
192
|
const v = grok.shell.v;
|
|
196
193
|
const tabControl = grok.shell.sidebar;
|
|
197
|
-
tabControl.onTabChanged.subscribe((_) =>
|
|
198
|
-
v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []])
|
|
194
|
+
tabControl.onTabChanged.subscribe((_) => {
|
|
195
|
+
v.setRibbonPanels([(tabControl.currentPane.name == 'MAIN') ? topPanel : []]);
|
|
196
|
+
});
|
|
199
197
|
v.setRibbonPanels([topPanel]);
|
|
200
198
|
|
|
201
199
|
return ui.box(
|
package/src/package.ts
CHANGED
|
@@ -5,26 +5,43 @@ import {autostartOligoSdFileSubscription} from './autostart/registration';
|
|
|
5
5
|
import {defineAxolabsPattern} from './axolabs/define-pattern';
|
|
6
6
|
import {saveSenseAntiSense} from './structures-works/save-sense-antisense';
|
|
7
7
|
import {mainView} from './main/main-view';
|
|
8
|
+
import {IMonomerLib, MonomerWorks, readLibrary} from '@datagrok-libraries/bio';
|
|
8
9
|
|
|
9
10
|
export const _package = new DG.Package();
|
|
10
11
|
|
|
12
|
+
const LIB_PATH = 'System:AppData/SequenceTranslator';
|
|
13
|
+
|
|
14
|
+
let monomerLib: IMonomerLib | null = null;
|
|
15
|
+
export let monomerWorks: MonomerWorks | null = null;
|
|
16
|
+
|
|
17
|
+
export function getMonomerWorks() {
|
|
18
|
+
return monomerWorks;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function getMonomerLib() {
|
|
22
|
+
return monomerLib;
|
|
23
|
+
};
|
|
11
24
|
|
|
12
25
|
//name: Sequence Translator
|
|
13
26
|
//tags: app
|
|
14
|
-
export function sequenceTranslator(): void {
|
|
27
|
+
export async function sequenceTranslator(): Promise<void> {
|
|
28
|
+
monomerLib = await readLibrary(LIB_PATH, 'helmLib.json');
|
|
29
|
+
|
|
30
|
+
if (monomerWorks == null)
|
|
31
|
+
monomerWorks = new MonomerWorks(monomerLib);
|
|
32
|
+
|
|
15
33
|
const windows = grok.shell.windows;
|
|
16
34
|
windows.showProperties = false;
|
|
17
35
|
windows.showToolbox = false;
|
|
18
36
|
windows.showHelp = false;
|
|
19
37
|
|
|
20
|
-
const v = grok.shell.newView('Sequence Translator', [
|
|
21
|
-
ui.tabControl({
|
|
22
|
-
'MAIN': mainView(),
|
|
23
|
-
'AXOLABS': defineAxolabsPattern(),
|
|
24
|
-
'SDF': saveSenseAntiSense(),
|
|
25
|
-
}),
|
|
26
|
-
]);
|
|
38
|
+
const v = grok.shell.newView('Sequence Translator', []);
|
|
27
39
|
v.box = true;
|
|
40
|
+
v.append(ui.tabControl({
|
|
41
|
+
'MAIN': await mainView(),
|
|
42
|
+
'AXOLABS': defineAxolabsPattern(),
|
|
43
|
+
'SDF': saveSenseAntiSense(),
|
|
44
|
+
}));
|
|
28
45
|
}
|
|
29
46
|
|
|
30
47
|
//tags: autostart
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const MODIFICATIONS: {[index: string]: {molecularWeight: number, left: string, right: string}} = {
|
|
2
|
+
'(invabasic)': {
|
|
3
|
+
molecularWeight: 118.13,
|
|
4
|
+
left: 'O[C@@H]1C[C@@H]O[C@H]1CO',
|
|
5
|
+
right: 'O[C@@H]1C[C@@H]O[C@H]1CO',
|
|
6
|
+
},
|
|
7
|
+
'(GalNAc-2-JNJ)': {
|
|
8
|
+
molecularWeight: 1273.3,
|
|
9
|
+
left: 'C(COCCC(=O)NCCCNC(=O)CCCCOC2OC(CO)C(O)C(O)C2NC(=O)C)' +
|
|
10
|
+
'(COCCC(=O)NCCCNC(=O)CCCCOC2OC(CO)C(O)C(O)C2NC(=O)C)' +
|
|
11
|
+
'(COCCC(=O)NCCCNC(=O)CCCCOC2OC(CO)C(O)C(O)C2NC(=O)C)NC(=O)CCCC(=O)NCC(O)CO',
|
|
12
|
+
right: 'OCC(O)CNC(=O)CCCC(=O)NC(COCCC(=O)NCCCNC(=O)CCCCOC2OC(CO)C(O)C(O)C2NC(=O)C)' +
|
|
13
|
+
'(COCCC(=O)NCCCNC(=O)CCCCOC2OC(CO)C(O)C(O)C2NC(=O)C)'+
|
|
14
|
+
'(COCCC(=O)NCCCNC(=O)CCCCOC2OC(CO)C(O)C(O)C2NC(=O)C)',
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const standardPhosphateLinkSmiles = 'OP(=O)(O)O';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {lcmsToGcrs} from './map';
|
|
2
2
|
import * as DG from 'datagrok-api/dg';
|
|
3
|
-
import {
|
|
3
|
+
import {DELIMITER} from './map';
|
|
4
4
|
//name: gcrsToLcms
|
|
5
5
|
//input: string nucleotides {semType: GCRS}
|
|
6
6
|
//output: string result {semType: LCMS}
|
|
@@ -10,14 +10,14 @@ export function gcrsToLcms(sequence: string): string {
|
|
|
10
10
|
const arr2 = df.getCol('LCMS').toList();
|
|
11
11
|
const obj: {[i: string]: string} = {};
|
|
12
12
|
arr1.forEach((element, index) => obj[element] = arr2[index]);
|
|
13
|
-
obj[
|
|
13
|
+
obj[DELIMITER] = DELIMITER;
|
|
14
14
|
// for (let i = 0; i < arr1.length; i++) {
|
|
15
15
|
// arr1[i] = arr1[i].replace('(', '\\(');
|
|
16
16
|
// arr1[i] = arr1[i].replace(')', '\\)');
|
|
17
17
|
// }
|
|
18
18
|
// const regExp = new RegExp('(' + arr1.join('|') + ')', 'g');
|
|
19
19
|
// let r1 = sequence.replace(regExp, function(code) {return obj[code];});
|
|
20
|
-
const codes = arr1.concat(
|
|
20
|
+
const codes = arr1.concat(DELIMITER).sort(function(a, b) {return b.length - a.length;});
|
|
21
21
|
let i = 0;
|
|
22
22
|
let r1 = '';
|
|
23
23
|
while (i < sequence.length) {
|
|
@@ -1,43 +1,104 @@
|
|
|
1
|
-
import {map,
|
|
1
|
+
// import {map, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, DELIMITER} from './map';
|
|
2
|
+
import {map, SYNTHESIZERS, TECHNOLOGIES, DELIMITER} from './map';
|
|
2
3
|
import {isValidSequence} from './sequence-codes-tools';
|
|
4
|
+
import {sortByStringLengthInDescendingOrder} from '../helpers';
|
|
5
|
+
import {getMonomerWorks} from '../package';
|
|
3
6
|
import {getNucleotidesMol} from './mol-transformations';
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
import {standardPhosphateLinkSmiles, MODIFICATIONS} from './const';
|
|
9
|
+
import {getMonomerLib} from '../package';
|
|
10
|
+
// todo: remove
|
|
11
|
+
// const NAME = 'name';
|
|
12
|
+
const CODES = 'codes';
|
|
13
|
+
// const SMILES = 'smiles';
|
|
14
|
+
const MOL = 'molfile';
|
|
15
|
+
|
|
16
|
+
export function sequenceToMolV3000(
|
|
17
|
+
sequence: string, inverted: boolean = false, oclRender: boolean = false,
|
|
18
|
+
format: string,
|
|
19
|
+
): string {
|
|
20
|
+
const monomerNameFromCode = getCodeToNameMap(sequence, format);
|
|
21
|
+
let codes = sortByStringLengthInDescendingOrder(Object.keys(monomerNameFromCode));
|
|
9
22
|
let i = 0;
|
|
10
|
-
const smilesCodes:string[] = [];
|
|
11
23
|
const codesList = [];
|
|
12
24
|
const links = ['s', 'ps', '*'];
|
|
13
25
|
const includesStandardLinkAlready = ['e', 'h', /*'g',*/ 'f', 'i', 'l', 'k', 'j'];
|
|
14
26
|
const dropdowns = Object.keys(MODIFICATIONS);
|
|
15
|
-
codes = codes.concat(dropdowns).concat(
|
|
27
|
+
codes = codes.concat(dropdowns).concat(DELIMITER);
|
|
16
28
|
while (i < sequence.length) {
|
|
17
|
-
const code = codes.find((s: string) => s
|
|
29
|
+
const code = codes.find((s: string) => s === sequence.slice(i, i + s.length))!;
|
|
18
30
|
i += code.length;
|
|
19
31
|
inverted ? codesList.unshift(code) : codesList.push(code);
|
|
20
32
|
}
|
|
33
|
+
|
|
34
|
+
const monomers: string[] = [];
|
|
35
|
+
|
|
21
36
|
for (let i = 0; i < codesList.length; i++) {
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
if (links.includes(codesList[i]) ||
|
|
38
|
+
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
39
|
+
(i < codesList.length - 1 && links.includes(codesList[i + 1]))
|
|
40
|
+
) {
|
|
41
|
+
let aa = monomerNameFromCode[codesList[i]];
|
|
42
|
+
if(aa !== undefined)
|
|
43
|
+
monomers.push(aa);
|
|
44
|
+
else
|
|
45
|
+
monomers.push(codesList[i]);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
let aa = monomerNameFromCode[codesList[i]];
|
|
49
|
+
if(aa !== undefined)
|
|
50
|
+
monomers.push(aa);
|
|
51
|
+
else
|
|
52
|
+
monomers.push(codesList[i]);
|
|
53
|
+
monomers.push('p linkage');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const lib = getMonomerLib();
|
|
58
|
+
const mols: string [] = [];
|
|
59
|
+
for(let i = 0; i < monomers.length; i++) {
|
|
60
|
+
const mnmr = lib?.getMonomer('RNA', monomers[i]);
|
|
61
|
+
mols.push(mnmr?.molfile!);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
return getNucleotidesMol(mols);
|
|
66
|
+
//return getMonomerWorks()?.getAtomicLevel(monomers, 'RNA')!;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function sequenceToMolV3000_new(
|
|
70
|
+
sequence: string, inverted: boolean = false, oclRender: boolean = false,
|
|
71
|
+
format: string,
|
|
72
|
+
): string {
|
|
73
|
+
const monomerNameFromCode = getCodeToNameMap(sequence, format);
|
|
74
|
+
let codes = sortByStringLengthInDescendingOrder(Object.keys(monomerNameFromCode));
|
|
75
|
+
let i = 0;
|
|
76
|
+
const codesList = [];
|
|
77
|
+
const links = ['s', 'ps', '*'];
|
|
78
|
+
const includesStandardLinkAlready = ['e', 'h', /*'g',*/ 'f', 'i', 'l', 'k', 'j'];
|
|
79
|
+
const dropdowns = Object.keys(MODIFICATIONS);
|
|
80
|
+
codes = codes.concat(dropdowns).concat(DELIMITER);
|
|
81
|
+
while (i < sequence.length) {
|
|
82
|
+
const code = codes.find((s: string) => s === sequence.slice(i, i + s.length))!;
|
|
83
|
+
i += code.length;
|
|
84
|
+
inverted ? codesList.unshift(code) : codesList.push(code);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const monomers: string[] = [];
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < codesList.length; i++) {
|
|
90
|
+
if (links.includes(codesList[i]) ||
|
|
91
|
+
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
92
|
+
(i < codesList.length - 1 && links.includes(codesList[i + 1]))
|
|
93
|
+
)
|
|
94
|
+
monomers.push(monomerNameFromCode[codesList[i]]);
|
|
95
|
+
else {
|
|
96
|
+
monomers.push(monomerNameFromCode[codesList[i]]);
|
|
97
|
+
monomers.push('p linkage');
|
|
37
98
|
}
|
|
38
99
|
}
|
|
39
100
|
|
|
40
|
-
return
|
|
101
|
+
return getMonomerWorks()?.getAtomicLevel(monomers, 'RNA')!;
|
|
41
102
|
}
|
|
42
103
|
|
|
43
104
|
export function sequenceToSmiles(sequence: string, inverted: boolean = false, format: string): string {
|
|
@@ -49,7 +110,7 @@ export function sequenceToSmiles(sequence: string, inverted: boolean = false, fo
|
|
|
49
110
|
const links = ['s', 'ps', '*'];
|
|
50
111
|
const includesStandardLinkAlready = ['e', 'h', /*'g',*/ 'f', 'i', 'l', 'k', 'j'];
|
|
51
112
|
const dropdowns = Object.keys(MODIFICATIONS);
|
|
52
|
-
codes = codes.concat(dropdowns).concat(
|
|
113
|
+
codes = codes.concat(dropdowns).concat(DELIMITER);
|
|
53
114
|
while (i < sequence.length) {
|
|
54
115
|
const code = codes.find((s: string) => s == sequence.slice(i, i + s.length))!;
|
|
55
116
|
i += code.length;
|
|
@@ -58,8 +119,8 @@ export function sequenceToSmiles(sequence: string, inverted: boolean = false, fo
|
|
|
58
119
|
for (let i = 0; i < codesList.length; i++) {
|
|
59
120
|
if (dropdowns.includes(codesList[i])) {
|
|
60
121
|
smiles += (i >= codesList.length / 2) ?
|
|
61
|
-
MODIFICATIONS[codesList[i]].right +
|
|
62
|
-
MODIFICATIONS[codesList[i]].left +
|
|
122
|
+
MODIFICATIONS[codesList[i]].right + standardPhosphateLinkSmiles :
|
|
123
|
+
MODIFICATIONS[codesList[i]].left + standardPhosphateLinkSmiles;
|
|
63
124
|
} else {
|
|
64
125
|
if (links.includes(codesList[i]) ||
|
|
65
126
|
includesStandardLinkAlready.includes(codesList[i]) ||
|
|
@@ -67,7 +128,7 @@ export function sequenceToSmiles(sequence: string, inverted: boolean = false, fo
|
|
|
67
128
|
)
|
|
68
129
|
smiles += obj[codesList[i]];
|
|
69
130
|
else
|
|
70
|
-
smiles += obj[codesList[i]] +
|
|
131
|
+
smiles += obj[codesList[i]] + standardPhosphateLinkSmiles;
|
|
71
132
|
}
|
|
72
133
|
}
|
|
73
134
|
smiles = smiles.replace(/OO/g, 'O');
|
|
@@ -81,7 +142,34 @@ export function sequenceToSmiles(sequence: string, inverted: boolean = false, fo
|
|
|
81
142
|
includesStandardLinkAlready.includes(codesList[codesList.length - 1])
|
|
82
143
|
) ?
|
|
83
144
|
smiles :
|
|
84
|
-
smiles.slice(0, smiles.length -
|
|
145
|
+
smiles.slice(0, smiles.length - standardPhosphateLinkSmiles.length + 1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function getCodeToNameMap(sequence: string, format: string) {
|
|
149
|
+
const obj: { [code: string]: string } = {};
|
|
150
|
+
const NAME = 'name';
|
|
151
|
+
if (format == null) {
|
|
152
|
+
for (const synthesizer of Object.keys(map)) {
|
|
153
|
+
for (const technology of Object.keys(map[synthesizer])) {
|
|
154
|
+
for (const code of Object.keys(map[synthesizer][technology]))
|
|
155
|
+
obj[code] = map[synthesizer][technology][code][NAME]!;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
for (const technology of Object.keys(map[format])) {
|
|
160
|
+
for (const code of Object.keys(map[format][technology]))
|
|
161
|
+
obj[code] = map[format][technology][code][NAME]!;
|
|
162
|
+
// obj[code] = map[format][technology][code].SMILES;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
obj[DELIMITER] = '';
|
|
166
|
+
// TODO: create object based from synthesizer type to avoid key(codes) duplicates
|
|
167
|
+
const output = isValidSequence(sequence, format);
|
|
168
|
+
if (output.synthesizer!.includes(SYNTHESIZERS.MERMADE_12))
|
|
169
|
+
obj['g'] = map[SYNTHESIZERS.MERMADE_12][TECHNOLOGIES.SI_RNA]['g'][NAME]!;
|
|
170
|
+
else if (output.synthesizer!.includes(SYNTHESIZERS.AXOLABS))
|
|
171
|
+
obj['g'] = map[SYNTHESIZERS.AXOLABS][TECHNOLOGIES.SI_RNA]['g'][NAME]!;
|
|
172
|
+
return obj;
|
|
85
173
|
}
|
|
86
174
|
|
|
87
175
|
function getObjectWithCodesAndSmiles(sequence: string, format: string) {
|
|
@@ -99,7 +187,7 @@ function getObjectWithCodesAndSmiles(sequence: string, format: string) {
|
|
|
99
187
|
obj[code] = map[format][technology][code].SMILES;
|
|
100
188
|
}
|
|
101
189
|
}
|
|
102
|
-
obj[
|
|
190
|
+
obj[DELIMITER] = '';
|
|
103
191
|
// TODO: create object based from synthesizer type to avoid key(codes) duplicates
|
|
104
192
|
const output = isValidSequence(sequence, format);
|
|
105
193
|
if (output.synthesizer!.includes(SYNTHESIZERS.MERMADE_12))
|
|
@@ -109,6 +197,71 @@ function getObjectWithCodesAndSmiles(sequence: string, format: string) {
|
|
|
109
197
|
return obj;
|
|
110
198
|
}
|
|
111
199
|
|
|
112
|
-
function
|
|
113
|
-
|
|
200
|
+
function getObjectWithCodesAndMolsFromFile(sequence: string, format: string, libFileContent: string) {
|
|
201
|
+
const obj: { [code: string]: string } = {};
|
|
202
|
+
// todo: type
|
|
203
|
+
const lib: any[] = JSON.parse(libFileContent); //consider using library
|
|
204
|
+
|
|
205
|
+
for (const item of lib) {
|
|
206
|
+
for (const synthesizer of Object.keys(item[CODES])) {
|
|
207
|
+
if (synthesizer === format) {
|
|
208
|
+
for (const technology of Object.keys(item[CODES][synthesizer])) {
|
|
209
|
+
const codes = item[CODES][synthesizer][technology];
|
|
210
|
+
let mol: string = item[MOL];
|
|
211
|
+
// todo: find another solution
|
|
212
|
+
mol = mol.replace(/ R /g, ' O ');
|
|
213
|
+
|
|
214
|
+
for (const code of codes)
|
|
215
|
+
obj[code] = mol;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
obj[DELIMITER] = '';
|
|
222
|
+
// TODO: create object based on synthesizer type to avoid key(codes) duplicates
|
|
223
|
+
const output = isValidSequence(sequence, format);
|
|
224
|
+
if (output.synthesizer!.includes(SYNTHESIZERS.MERMADE_12)) {
|
|
225
|
+
// todo: remove as quickfix, optimize access to 'g'
|
|
226
|
+
for (const item of lib) {
|
|
227
|
+
for (const synthesizer of Object.keys(item[CODES])) {
|
|
228
|
+
for (const technology of Object.keys(item[CODES][synthesizer])) {
|
|
229
|
+
const codes = item[CODES][synthesizer][technology];
|
|
230
|
+
for (const code of codes) {
|
|
231
|
+
const condition =
|
|
232
|
+
(code === 'g') &&
|
|
233
|
+
(synthesizer === SYNTHESIZERS.MERMADE_12) &&
|
|
234
|
+
(technology === TECHNOLOGIES.SI_RNA);
|
|
235
|
+
if (condition) {
|
|
236
|
+
let mol: string = item[MOL];
|
|
237
|
+
// todo: find another solution
|
|
238
|
+
mol = mol.replace(/ R /g, ' O ');
|
|
239
|
+
obj[code] = mol;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
} else if (output.synthesizer!.includes(SYNTHESIZERS.AXOLABS)) {
|
|
246
|
+
for (const item of lib) {
|
|
247
|
+
for (const synthesizer of Object.keys(item[CODES])) {
|
|
248
|
+
for (const technology of Object.keys(item[CODES][synthesizer])) {
|
|
249
|
+
const codes = item[CODES][synthesizer][technology];
|
|
250
|
+
for (const code of codes) {
|
|
251
|
+
const condition =
|
|
252
|
+
(code === 'g') &&
|
|
253
|
+
(synthesizer === SYNTHESIZERS.AXOLABS) &&
|
|
254
|
+
(technology === TECHNOLOGIES.SI_RNA);
|
|
255
|
+
if (condition) {
|
|
256
|
+
let mol: string = item[MOL];
|
|
257
|
+
// todo: find another solution
|
|
258
|
+
mol = mol.replace(/ R /g, ' O ');
|
|
259
|
+
obj[code] = mol;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return obj;
|
|
114
267
|
}
|