@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.
@@ -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, MODIFICATIONS} from '../structures-works/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
- function updateTableAndMolecule(sequence: string, inputFormat: string): void {
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
- ui.divH([
42
- ui.divText(sequence.slice(0, indexOfFirstNotValidChar), {style: {color: 'grey'}}),
43
- ui.tooltip.bind(
44
- ui.divText(sequence.slice(indexOfFirstNotValidChar), {style: {color: 'red'}}),
45
- 'Expected format: ' + JSON.parse(outputSequenceObj.indexOfFirstNotValidChar!).synthesizer +
46
- '. See tables with valid codes on the right',
47
- ),
48
- ]) : //@ts-ignore
49
- ui.link(outputSequenceObj[key], () => navigator.clipboard.writeText(outputSequenceObj[key])
50
- .then(() => grok.shell.info(sequenceWasCopied)), tooltipSequence, ''),
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(inputSequenceField.value.replace(/\s/g, ''), false, true,
80
- output.synthesizer![0]);
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
- output.synthesizer![0]);
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 asoDf = DG.DataFrame.fromObjects([
112
- {'Name': '2\'MOE-5Me-rU', 'BioSpring': '5', 'Janssen GCRS': 'moeT'},
113
- {'Name': '2\'MOE-rA', 'BioSpring': '6', 'Janssen GCRS': 'moeA'},
114
- {'Name': '2\'MOE-5Me-rC', 'BioSpring': '7', 'Janssen GCRS': 'moe5mC'},
115
- {'Name': '2\'MOE-rG', 'BioSpring': '8', 'Janssen GCRS': 'moeG'},
116
- {'Name': '5-Methyl-dC', 'BioSpring': '9', 'Janssen GCRS': '5mC'},
117
- {'Name': 'ps linkage', 'BioSpring': '*', 'Janssen GCRS': 'ps'},
118
- {'Name': 'dA', 'BioSpring': 'A', 'Janssen GCRS': 'A, dA'},
119
- {'Name': 'dC', 'BioSpring': 'C', 'Janssen GCRS': 'C, dC'},
120
- {'Name': 'dG', 'BioSpring': 'G', 'Janssen GCRS': 'G, dG'},
121
- {'Name': 'dT', 'BioSpring': 'T', 'Janssen GCRS': 'T, dT'},
122
- {'Name': 'rA', 'BioSpring': '', 'Janssen GCRS': 'rA'},
123
- {'Name': 'rC', 'BioSpring': '', 'Janssen GCRS': 'rC'},
124
- {'Name': 'rG', 'BioSpring': '', 'Janssen GCRS': 'rG'},
125
- {'Name': 'rU', 'BioSpring': '', 'Janssen GCRS': 'rU'},
126
- ])!;
127
- const asoGapmersGrid = DG.Viewer.grid(asoDf, {showRowHeader: false, showCellTooltip: false});
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
- DG.DataFrame.fromObjects([
135
- {'Name': '2\'-fluoro-U', 'BioSpring': '1', 'Axolabs': 'Uf', 'Janssen GCRS': 'fU'},
136
- {'Name': '2\'-fluoro-A', 'BioSpring': '2', 'Axolabs': 'Af', 'Janssen GCRS': 'fA'},
137
- {'Name': '2\'-fluoro-C', 'BioSpring': '3', 'Axolabs': 'Cf', 'Janssen GCRS': 'fC'},
138
- {'Name': '2\'-fluoro-G', 'BioSpring': '4', 'Axolabs': 'Gf', 'Janssen GCRS': 'fG'},
139
- {'Name': '2\'OMe-rU', 'BioSpring': '5', 'Axolabs': 'u', 'Janssen GCRS': 'mU'},
140
- {'Name': '2\'OMe-rA', 'BioSpring': '6', 'Axolabs': 'a', 'Janssen GCRS': 'mA'},
141
- {'Name': '2\'OMe-rC', 'BioSpring': '7', 'Axolabs': 'c', 'Janssen GCRS': 'mC'},
142
- {'Name': '2\'OMe-rG', 'BioSpring': '8', 'Axolabs': 'g', 'Janssen GCRS': 'mG'},
143
- {'Name': 'ps linkage', 'BioSpring': '*', 'Axolabs': 's', 'Janssen GCRS': 'ps'},
144
- ])!, {showRowHeader: false, showCellTooltip: false},
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
- ui.iconFA('download', () => {
180
- const result = sequenceToMolV3000(inputSequenceField.value.replace(/\s/g, ''), false, false,
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 {delimiter} from './map';
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[delimiter] = delimiter;
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(delimiter).sort(function(a, b) {return b.length - a.length;});
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, stadardPhosphateLinkSmiles, SYNTHESIZERS, TECHNOLOGIES, MODIFICATIONS, delimiter} from './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
- export function sequenceToMolV3000(sequence: string, inverted: boolean = false, oclRender: boolean = false,
6
- format: string): string {
7
- const obj = getObjectWithCodesAndSmiles(sequence, format);
8
- let codes = sortByStringLengthInDescendingOrder(Object.keys(obj));
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(delimiter);
27
+ codes = codes.concat(dropdowns).concat(DELIMITER);
16
28
  while (i < sequence.length) {
17
- const code = codes.find((s: string) => s == sequence.slice(i, i + s.length))!;
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 (dropdowns.includes(codesList[i])) {
23
- smilesCodes.push((i >= codesList.length / 2) ?
24
- MODIFICATIONS[codesList[i]].right : MODIFICATIONS[codesList[i]].left);
25
- if (!(i < codesList.length - 1 && links.includes(codesList[i + 1])))
26
- smilesCodes.push(stadardPhosphateLinkSmiles);
27
- } else {
28
- if (links.includes(codesList[i]) ||
29
- includesStandardLinkAlready.includes(codesList[i]) ||
30
- (i < codesList.length - 1 && links.includes(codesList[i + 1]))
31
- )
32
- smilesCodes.push(obj[codesList[i]]);
33
- else {
34
- smilesCodes.push(obj[codesList[i]]);
35
- smilesCodes.push(stadardPhosphateLinkSmiles);
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 getNucleotidesMol(smilesCodes);
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(delimiter);
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 + stadardPhosphateLinkSmiles:
62
- MODIFICATIONS[codesList[i]].left + stadardPhosphateLinkSmiles;
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]] + stadardPhosphateLinkSmiles;
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 - stadardPhosphateLinkSmiles.length + 1);
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[delimiter] = '';
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 sortByStringLengthInDescendingOrder(array: string[]): string[] {
113
- return array.sort(function(a: string, b: string) {return b.length - a.length;});
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
  }