@datagrok/sequence-translator 1.2.9 → 1.3.1

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/package-test.js +1 -1
  3. package/dist/package-test.js.map +1 -1
  4. package/dist/package.js +1 -1
  5. package/dist/package.js.map +1 -1
  6. package/files/polytool-rules/rules_example.json +34 -0
  7. package/package.json +4 -3
  8. package/src/apps/pattern/model/event-bus.ts +23 -6
  9. package/src/apps/pattern/model/translator.ts +27 -1
  10. package/src/apps/pattern/view/components/bulk-convert/column-input.ts +13 -3
  11. package/src/apps/pattern/view/components/bulk-convert/table-controls.ts +4 -3
  12. package/src/apps/pattern/view/components/load-block-controls.ts +4 -2
  13. package/src/apps/pattern/view/svg-utils/const.ts +15 -1
  14. package/src/apps/pattern/view/svg-utils/legend-block.ts +92 -0
  15. package/src/apps/pattern/view/svg-utils/strands-block.ts +335 -0
  16. package/src/apps/pattern/view/svg-utils/svg-block-base.ts +37 -0
  17. package/src/apps/pattern/view/svg-utils/svg-display-manager.ts +4 -5
  18. package/src/apps/pattern/view/svg-utils/svg-element-factory.ts +16 -4
  19. package/src/apps/pattern/view/svg-utils/svg-renderer.ts +32 -377
  20. package/src/apps/pattern/view/svg-utils/text-dimensions-calculator.ts +29 -0
  21. package/src/apps/pattern/view/svg-utils/title-block.ts +53 -0
  22. package/src/apps/translator/view/ui.ts +1 -1
  23. package/src/package.ts +22 -6
  24. package/src/polytool/const.ts +3 -15
  25. package/src/polytool/pt-conversion.ts +307 -0
  26. package/src/polytool/pt-dialog.ts +115 -0
  27. package/src/polytool/pt-enumeration.ts +127 -0
  28. package/src/polytool/pt-rules.ts +73 -0
  29. package/src/polytool/utils.ts +7 -0
  30. package/src/tests/helm-to-nucleotides.ts +0 -5
  31. package/tsconfig.json +1 -1
  32. package/src/apps/pattern/view/svg-utils/dimensions-calculator.ts +0 -498
  33. package/src/polytool/transformation.ts +0 -326
  34. package/src/polytool/ui.ts +0 -59
@@ -0,0 +1,307 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as DG from 'datagrok-api/dg';
3
+
4
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
5
+ import {ALIGNMENT, ALPHABET} from '@datagrok-libraries/bio/src/utils/macromolecule';
6
+
7
+ import {Rules, RuleLink, getRules} from './pt-rules';
8
+
9
+ export const RULES_DIMER = '(#2)';
10
+ export const RULES_HETERODIMER = '($2)';
11
+
12
+ function addCommonTags(col: DG.Column): void {
13
+ col.setTag('quality', DG.SEMTYPE.MACROMOLECULE);
14
+ col.setTag('aligned', ALIGNMENT.SEQ);
15
+ col.setTag('alphabet', ALPHABET.PT);
16
+ }
17
+
18
+ export class Chain {
19
+ linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[];
20
+ monomers: string[][];
21
+
22
+ constructor(
23
+ monomers: string[][],
24
+ linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[]) {
25
+ this.linkages = linkages;
26
+ this.monomers = monomers;
27
+ }
28
+
29
+ static fromHelm(helm: string) {
30
+ const fragmentation = helm.split('$');
31
+ const rawFragments = fragmentation[0].split('|');
32
+ const rawLinkages = fragmentation[1].split('|');
33
+
34
+ const monomers = new Array<Array<string>>(rawFragments.length);
35
+ const linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[] = [];
36
+
37
+ //HELM parsing
38
+ for (let i = 0; i < rawFragments.length; i++) {
39
+ const idxStart = rawFragments[i].indexOf('{');
40
+ const idxEnd = rawFragments[i].indexOf('}');
41
+
42
+ monomers[i] = rawFragments[i].slice(idxStart + 1, idxEnd).split('.');
43
+ }
44
+
45
+ //HELM parsing
46
+ for (let i = 0; i < rawLinkages.length; i++) {
47
+ if (rawLinkages[i] !== '' && rawLinkages[i] !== 'V2.0') {
48
+ const rawData = rawLinkages[i].split(',');
49
+ const seq1 = (rawData[0].replace('PEPTIDE', '') as unknown as number) - 1;
50
+ const seq2 = (rawData[1].replace('PEPTIDE', '') as unknown as number) - 1;
51
+ const rawDataConnctions = rawData[2].split('-');
52
+ const rawDataConnction1 = rawDataConnctions[0].split(':');
53
+ const rawDataConnction2 = rawDataConnctions[1].split(':');
54
+
55
+ linkages.push({
56
+ fChain: seq1,
57
+ sChain: seq2,
58
+ fMonomer: rawDataConnction1[0] as unknown as number,
59
+ sMonomer: rawDataConnction2[0] as unknown as number,
60
+ fR: rawDataConnction1[1].replace('R', '') as unknown as number,
61
+ sR: rawDataConnction2[1].replace('R', '') as unknown as number,
62
+ });
63
+ }
64
+ }
65
+
66
+ return new Chain(monomers, linkages);
67
+ }
68
+
69
+ static fromNotation(sequence: string, rules: Rules) {
70
+ const heterodimerCode = rules.heterodimerCode;
71
+ const homodimerCode = rules.homodimerCode;
72
+ const mainFragments: string[] = [];
73
+
74
+ const linkages: {fChain: number, sChain: number, fMonomer:number, sMonomer:number, fR:number, sR:number}[] = [];
75
+
76
+ //NOTICE: this works only with simple single heterodimers
77
+ const heterodimeric = heterodimerCode !== null? sequence.split(`(${rules.heterodimerCode!})`) : '';
78
+ if (heterodimerCode !== null && heterodimeric.length > 1) {
79
+ linkages.push({fChain: 0, sChain: 1, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
80
+ mainFragments.push(heterodimeric[1].replaceAll('{', '').replaceAll('}', ''));
81
+ mainFragments.push(heterodimeric[2].replaceAll('{', '').replaceAll('}', ''));
82
+ } else {
83
+ mainFragments.push(sequence);
84
+ }
85
+
86
+ //NOTICE: this works only with simple single dimers
87
+ for (let i = 0; i < mainFragments.length; i++) {
88
+ if (homodimerCode !== null && mainFragments[i].includes(`(${homodimerCode!})`)) {
89
+ const idxSequence = mainFragments.length;
90
+
91
+ linkages.push({fChain: i, sChain: idxSequence, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
92
+ const rawDimer = mainFragments[i].replace(`(${homodimerCode!})`, '');
93
+ const idx = rawDimer.indexOf('{');
94
+ const linker = rawDimer.slice(0, idx);
95
+ const body = rawDimer.replace(linker, '').replaceAll('{', '').replaceAll('}', '');
96
+
97
+ mainFragments[i] = linker + body;
98
+ mainFragments.push(body);
99
+ }
100
+ }
101
+
102
+ const monomers = new Array<Array<string>>(mainFragments.length);
103
+
104
+ for (let i = 0; i < mainFragments.length; i++) {
105
+ const rawMonomers = mainFragments[i].split('-');
106
+ const linkedPositions = this.getLinkedPositions(rawMonomers, rules.linkRules);
107
+ const [monomersCycled, allPos1, allPos2, allAttaches1, allAttaches2] =
108
+ this.getAllCycles(rules.linkRules, rawMonomers, linkedPositions);
109
+
110
+ const monomersReady = new Array<string>(monomersCycled.length);
111
+ for (let j = 0; j < monomersCycled.length; j++)
112
+ monomersReady[j] = `[${monomersCycled[j]}]`;
113
+
114
+ for (let j = 0; j < allPos1.length; j++) {
115
+ linkages.push({
116
+ fChain: i,
117
+ sChain: i,
118
+ fMonomer: allPos1[j],
119
+ sMonomer: allPos2[j],
120
+ fR: allAttaches1[j],
121
+ sR: allAttaches2[j],
122
+ });
123
+ }
124
+
125
+ monomers[i] = monomersReady;
126
+ }
127
+
128
+ return new Chain(monomers, linkages);
129
+ }
130
+
131
+ getHelmChanged(changeNumber: number, monomer: string): string {
132
+ //TODO: make more efficient
133
+ let counter = 0;
134
+ let idx1 = 0;
135
+ let idx2 = 0;
136
+ loop1:
137
+ for (let i = 0; i < this.monomers.length; i++) {
138
+ loop2:
139
+ for (let j = 0; j < this.monomers[i].length; j++) {
140
+ if (counter == changeNumber) {
141
+ idx1 = i;
142
+ idx2 = j;
143
+ break loop1;
144
+ }
145
+ counter++;
146
+ }
147
+ }
148
+
149
+ const previous = this.monomers[idx1][idx2];
150
+
151
+ this.monomers[idx1][idx2] = `[${monomer}]`;
152
+ const res = this.getHelm();
153
+ this.monomers[idx1][idx2] = previous;
154
+
155
+ return res;
156
+ }
157
+
158
+ getHelm(): string {
159
+ let helm = '';
160
+ for (let i = 0; i < this.monomers.length; i++) {
161
+ if (i > 0)
162
+ helm += '|';
163
+
164
+ helm += `PEPTIDE${i + 1}{`;
165
+
166
+ for (let j = 0; j < this.monomers[i].length; j++) {
167
+ if (j > 0)
168
+ helm += '.';
169
+ helm += this.monomers[i][j];
170
+ }
171
+ helm += `}`;
172
+ }
173
+
174
+ helm += '$';
175
+
176
+ for (let i = 0; i < this.linkages.length; i++) {
177
+ if (i > 0)
178
+ helm += '|';
179
+ helm += `PEPTIDE${this.linkages[i].fChain + 1},PEPTIDE${this.linkages[i].sChain + 1},`;
180
+ helm += `${this.linkages[i].fMonomer}:R${this.linkages[i].fR}-`;
181
+ helm += `${this.linkages[i].sMonomer}:R${this.linkages[i].sR}`;
182
+ }
183
+
184
+ helm += '$$$';
185
+ return helm;
186
+ }
187
+
188
+ protected static getLinkedPositions(monomers: string[], rules: RuleLink[]): [number, number][] {
189
+ const result: [number, number][] = new Array<[number, number]>(rules.length);
190
+
191
+ for (let i = 0; i < rules.length; i++) {
192
+ let firstFound = false;
193
+ let secondFound = false;
194
+ let firstIsFirst = false;
195
+ let firstEntryIndex = -1;
196
+ let secondEntryIndex = -1;
197
+ const add = `(${rules[i].code})`;
198
+ for (let j = 0; j < monomers.length; j++) {
199
+ if (monomers[j].includes(add)) {
200
+ if (firstFound) {
201
+ if (firstIsFirst && monomers[j] == rules[i].secondMonomer + add) {
202
+ secondFound = true;
203
+ secondEntryIndex = j;
204
+ break;
205
+ } else if (!firstIsFirst && monomers[j] == rules[i].firstMonomer + add) {
206
+ secondFound = true;
207
+ secondEntryIndex = j;
208
+ break;
209
+ } else {
210
+ continue;
211
+ }
212
+ } else {
213
+ if (monomers[j] == rules[i].firstMonomer + add) {
214
+ firstFound = true;
215
+ firstIsFirst = true;
216
+ firstEntryIndex = j;
217
+ } else if (monomers[j] == rules[i].secondMonomer + add) {
218
+ firstFound = true;
219
+ firstIsFirst = false;
220
+ firstEntryIndex = j;
221
+ } else {
222
+ continue;
223
+ }
224
+ }
225
+ }
226
+ }
227
+
228
+ if (!(firstFound && secondFound))
229
+ result[i] = [-1, -1];
230
+ else if (firstIsFirst)
231
+ result[i] = [firstEntryIndex, secondEntryIndex];
232
+ else
233
+ result[i] = [secondEntryIndex, firstEntryIndex];
234
+ }
235
+
236
+
237
+ return result;
238
+ }
239
+
240
+ protected static getAllCycles(rules: RuleLink[], monomers: string [], positions: [number, number][]) :
241
+ [string [], number [], number [], number [], number []] {
242
+ const allPos1: number [] = [];
243
+ const allPos2: number [] = [];
244
+ const allAttaches1: number [] = [];
245
+ const allAttaches2: number [] = [];
246
+ const ruleCount = rules.length;
247
+
248
+ for (let i = 0; i < ruleCount; i++) {
249
+ if (positions[i][0] == -1)
250
+ continue;
251
+
252
+ const firstMonomer = monomers[positions[i][0]];
253
+ const secondMonomer = monomers[positions[i][1]];
254
+
255
+ monomers[positions[i][0]] = monomers[positions[i][0]].replace(firstMonomer, rules[i].firstSubstitution);
256
+ monomers[positions[i][1]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondSubstitution);
257
+
258
+ allPos1.push(positions[i][0] + 1);
259
+ allPos2.push(positions[i][1] + 1);
260
+ allAttaches1.push(rules[i].firstLinkingGroup);
261
+ allAttaches2.push(rules[i].secondLinkingGroup);
262
+ }
263
+
264
+ return [monomers, allPos1, allPos2, allAttaches1, allAttaches2];
265
+ }
266
+ }
267
+
268
+ function getHelms(sequences: string[], rules: Rules): string[] {
269
+ const helms = new Array<string>(sequences.length);
270
+ for (let i = 0; i < sequences.length; i++) {
271
+ const chain = Chain.fromNotation(sequences[i], rules);
272
+ helms[i] = chain.getHelm();
273
+ }
274
+
275
+ return helms;
276
+ }
277
+
278
+ export async function addTransformedColumn(
279
+ sequencesCol: DG.Column<string>, addHelm: boolean, ruleFiles: string[], chiralityEngine?: boolean
280
+ ): Promise<void> {
281
+ const df = sequencesCol.dataFrame;
282
+
283
+ const rules = await getRules(ruleFiles);
284
+ const targetList = getHelms(sequencesCol.toList(), rules);
285
+ const helmColName = df.columns.getUnusedName('transformed(' + sequencesCol.name + ')');
286
+ const targetHelmCol = DG.Column.fromList('string', helmColName, targetList);
287
+
288
+ addCommonTags(targetHelmCol);
289
+ targetHelmCol.setTag('units', NOTATION.HELM);
290
+
291
+ const molCol = await grok.functions.call('Bio:getMolFromHelm', {
292
+ 'df': df,
293
+ 'helmCol': targetHelmCol,
294
+ 'chiralityEngine': chiralityEngine
295
+ });
296
+
297
+
298
+ molCol.name = df.columns.getUnusedName('molfile(' + sequencesCol.name + ')');
299
+ molCol.semType = DG.SEMTYPE.MOLECULE;
300
+
301
+ if (addHelm) {
302
+ targetHelmCol.setTag('cell.renderer', 'helm');
303
+ df.columns.add(targetHelmCol);
304
+ }
305
+ df.columns.add(molCol, true);
306
+ await grok.data.detectSemanticTypes(df);
307
+ }
@@ -0,0 +1,115 @@
1
+ /* Do not change these import lines to match external modules in webpack configuration */
2
+ import * as grok from 'datagrok-api/grok';
3
+ import * as ui from 'datagrok-api/ui';
4
+ import * as DG from 'datagrok-api/dg';
5
+
6
+ import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
7
+ import {addTransformedColumn} from './pt-conversion';
8
+
9
+ import {handleError} from './utils';
10
+ import {getLibrariesList, HelmInput, getEnumeration} from './pt-enumeration';
11
+
12
+ const PT_ERROR_DATAFRAME = 'No dataframe with macromolecule columns open';
13
+ const PT_WARNING_COLUMN = 'No marcomolecule column chosen!';
14
+
15
+ const PT_UI_GET_HELM = 'Get HELM';
16
+ const PT_UI_ADD_HELM = 'Add HELM column';
17
+ const PT_UI_USE_CHIRALITY = 'Chirality engine';
18
+ const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
19
+ const PT_UI_DIALOG_ENUMERATION = 'Poly Tool Enumeration';
20
+ const PT_UI_RULES_USED = 'Rules used';
21
+
22
+ export async function getPolyToolConversionDialog(): Promise<DG.Dialog> {
23
+ const targetColumns = grok.shell.t.columns.bySemTypeAll(DG.SEMTYPE.MACROMOLECULE);
24
+ if (!targetColumns)
25
+ throw new Error(PT_ERROR_DATAFRAME);
26
+
27
+ const targetColumnInput = ui.columnInput(
28
+ 'Column', grok.shell.t, targetColumns[0], null,
29
+ {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE}
30
+ );
31
+
32
+ const generateHelmChoiceInput = ui.boolInput(PT_UI_GET_HELM, true);
33
+ ui.tooltip.bind(generateHelmChoiceInput.root, PT_UI_ADD_HELM);
34
+
35
+ const chiralityEngineInput = ui.boolInput(PT_UI_USE_CHIRALITY, false);
36
+ const ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json');
37
+ const rulesHeader = ui.inlineText([PT_UI_RULES_USED]);
38
+ ui.tooltip.bind(rulesHeader, 'Add or specify rules to use');
39
+ const rulesForm = await ruleInputs.getForm();
40
+
41
+ const div = ui.div([
42
+ targetColumnInput,
43
+ generateHelmChoiceInput,
44
+ chiralityEngineInput,
45
+ rulesHeader,
46
+ rulesForm
47
+ ]);
48
+
49
+ const dialog = ui.dialog(PT_UI_DIALOG_CONVERSION)
50
+ .add(div)
51
+ .onOK(async () => {
52
+ const pi = DG.TaskBarProgressIndicator.create('PolyTool converting');
53
+ try {
54
+ const sequencesCol = targetColumnInput.value;
55
+ if (!sequencesCol) {
56
+ grok.shell.warning(PT_WARNING_COLUMN);
57
+ return;
58
+ }
59
+
60
+ const files = await ruleInputs.getActive();
61
+
62
+ addTransformedColumn(sequencesCol!,
63
+ generateHelmChoiceInput.value!,
64
+ files,
65
+ chiralityEngineInput.value!);
66
+ } catch (err: any) {
67
+ handleError(err);
68
+ } finally {
69
+ pi.close();
70
+ }
71
+ });
72
+
73
+ return dialog;
74
+ }
75
+
76
+ export async function getPolyToolEnumerationDialog(): Promise<DG.Dialog> {
77
+ const helmInput = await HelmInput.init();
78
+
79
+ const libList = await getLibrariesList();
80
+ const screenLibrary = ui.choiceInput('Library to use', null, libList);
81
+
82
+ screenLibrary.input.setAttribute('style', `min-width:250px!important;`);
83
+
84
+ const div = ui.div([
85
+ helmInput.getDiv(),
86
+ screenLibrary.root
87
+ ]);
88
+
89
+ const dialog = ui.dialog(PT_UI_DIALOG_ENUMERATION)
90
+ .add(div)
91
+ .onOK(async () => {
92
+ try {
93
+ const helmString = helmInput.getHelmString();
94
+ const helmSelections = helmInput.getHelmSelections();
95
+ if (helmString === undefined || helmString === '') {
96
+ grok.shell.warning('PolyTool: no molecule was provided');
97
+ } else if (helmSelections === undefined || helmSelections.length < 1) {
98
+ grok.shell.warning('PolyTool: no selection was provided');
99
+ } else {
100
+ const molecules = await getEnumeration(helmString, helmSelections, screenLibrary.value!);
101
+ const molCol = DG.Column.fromStrings('Enumerated', molecules);
102
+ const df = DG.DataFrame.fromColumns([molCol]);
103
+ grok.shell.addTableView(df);
104
+ }
105
+ } catch (err: any) {
106
+
107
+ } finally {
108
+
109
+ }
110
+ }).onCancel(() => {
111
+
112
+ });
113
+
114
+ return dialog;
115
+ }
@@ -0,0 +1,127 @@
1
+ import * as ui from 'datagrok-api/ui';
2
+ import * as grok from 'datagrok-api/grok';
3
+
4
+ import {IHelmHelper, getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
5
+ import {IHelmWebEditor} from '@datagrok-libraries/bio/src/helm/types';
6
+ import '@datagrok-libraries/bio/src/types/helm';
7
+ import '@datagrok-libraries/bio/src/types/jsdraw2';
8
+ import * as org from 'org';
9
+ import $ from 'cash-dom';
10
+ import {Unsubscribable, fromEvent} from 'rxjs';
11
+ import {IMonomerLibFileManager, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
12
+
13
+ import {Chain} from './pt-conversion';
14
+
15
+ const LIB_PATH = 'System:AppData/Bio/monomer-libraries/';
16
+ const PT_HELM_EXAMPLE = 'PEPTIDE1{[R].[F].[T].[G].[H].[F].[G].[A].[A].[Y].[P].[E].[NH2]}$$$$';
17
+
18
+ export async function getLibrariesList(): Promise<string[]> {
19
+ const monomerLibHelper: IMonomerLibHelper = await grok.functions.call('Bio:getMonomerLibHelper', {});
20
+ const monomerFileManager: IMonomerLibFileManager = await monomerLibHelper.getFileManager();
21
+ return monomerFileManager.getValidLibraryPaths();
22
+ }
23
+
24
+ export async function getEnumeration(helmString: string, helmSelections: number[], screenLibrary: string):
25
+ Promise<string[]> {
26
+ const variableMonomers = await getAvaialableMonomers(screenLibrary);
27
+ const chain: Chain = Chain.fromHelm(helmString);
28
+ const size = helmSelections.length*variableMonomers.length;
29
+ const enumerations = new Array<string>(size);
30
+
31
+ for (let i = 0; i < helmSelections.length; i++) {
32
+ for (let j = 0; j < variableMonomers.length; j++)
33
+ enumerations[i*variableMonomers.length + j] = chain.getHelmChanged(helmSelections[i], variableMonomers[j]);
34
+ }
35
+
36
+ return enumerations;
37
+ }
38
+
39
+ export class HelmInput {
40
+ webEditorHost: HTMLDivElement | null;
41
+ webEditorApp: org.helm.IWebEditorApp | null;
42
+ helmHelper: IHelmHelper;
43
+ editor: IHelmWebEditor;
44
+ subs: Unsubscribable[];
45
+
46
+ helmString: string = PT_HELM_EXAMPLE;
47
+ helmSelection: number[];
48
+
49
+ constructor(
50
+ helmHelper: IHelmHelper, editor: IHelmWebEditor) {
51
+ this.helmHelper = helmHelper;
52
+ this.editor = editor;
53
+
54
+ this.webEditorHost = null;
55
+ this.webEditorApp = null;
56
+ const subs: Unsubscribable[] = [];
57
+
58
+ subs.push(fromEvent<MouseEvent>(editor.host, 'click').subscribe(() => {
59
+ this.webEditorHost = ui.div();
60
+ //TODO: use not hh, but anything from editor.getHelm(true)
61
+ this.webEditorApp = helmHelper.createWebEditorApp(this.webEditorHost, this.getHelmString());
62
+ const dlg = ui.dialog({showHeader: false, showFooter: true})
63
+ .add(this.webEditorHost!)
64
+ .onOK(() => {
65
+ try {
66
+ const webEditorValue = this.webEditorApp!.canvas.getHelm(true)
67
+ .replace(/<\/span>/g, '').replace(/<span style='background:#bbf;'>/g, '');
68
+ editor.editor.setHelm(webEditorValue);
69
+ this.helmString = webEditorValue;
70
+ this.helmSelection = [];
71
+
72
+ //@ts-ignore
73
+ const selection = this.webEditorApp?.canvas.helm.jsd.m.atoms;
74
+ for (let i = 0; i < selection.length; i++) {
75
+ if (selection[i].selected)
76
+ this.helmSelection.push(i);
77
+ }
78
+ } catch (err: any) {
79
+ //this.logger.error(err);
80
+ } finally {
81
+ $(this.webEditorHost).empty();
82
+ this.webEditorHost = null;
83
+ this.webEditorApp = null;
84
+ }
85
+ })
86
+ .onCancel(() => {
87
+ $(this.webEditorHost).empty();
88
+ this.webEditorHost = null;
89
+ this.webEditorApp = null;
90
+ })
91
+ .show({modal: true, fullScreen: true});
92
+ }));
93
+ }
94
+
95
+ static async init() {
96
+ const helmHelper = await getHelmHelper();
97
+
98
+ const editor = helmHelper.createHelmWebEditor();
99
+ editor.host.style.width = '200px';
100
+ editor.host.style.height = '100px';
101
+ editor.host.style.paddingLeft = '40px';
102
+ editor.editor.setHelm(PT_HELM_EXAMPLE);
103
+
104
+ return new HelmInput(helmHelper, editor);
105
+ }
106
+
107
+ getHelmString(): string {
108
+ return this.helmString;
109
+ }
110
+
111
+ getHelmSelections() {
112
+ return this.helmSelection;
113
+ }
114
+
115
+ getDiv(): HTMLDivElement {
116
+ const title = ui.divText('Macromolecule', {style: {paddingTop: '43px', color: 'var(--grey-4)'}});
117
+
118
+ return ui.divH([title, this.editor.host], {style: {paddingLeft: '48px'}});
119
+ }
120
+ }
121
+
122
+ async function getAvaialableMonomers(screenLibrary: string): Promise<string[]> {
123
+ const monomerLibHelper: IMonomerLibHelper = await grok.functions.call('Bio:getMonomerLibHelper', {});
124
+ const monomerLib = await monomerLibHelper.readLibrary(LIB_PATH, screenLibrary);
125
+ //NOTICE: works with Peptides only
126
+ return monomerLib.getMonomerSymbolsByType('PEPTIDE');
127
+ }
@@ -0,0 +1,73 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import * as grok from 'datagrok-api/grok';
3
+ import {ActiveFiles} from '@datagrok-libraries/utils/src/settings/active-files-base';
4
+
5
+ export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
6
+ export const RULES_STORAGE_NAME = 'Polytool';
7
+ export const RULES_TYPE_LINK = 'link';
8
+ export const RULES_TYPE_HOMODIMER = 'fragmentDuplication';
9
+ export const RULES_TYPE_HETERODIMER = 'differentFragments';
10
+
11
+ export class RuleInputs extends ActiveFiles {
12
+ constructor(path: string, userStorageName: string, ext: string ) {
13
+ super(path, userStorageName, ext);
14
+ }
15
+ }
16
+
17
+ export type Rules = {
18
+ homodimerCode: string | null,
19
+ heterodimerCode: string | null,
20
+ linkRules: RuleLink[]
21
+ }
22
+
23
+ export type RuleLink = {
24
+ code: number,
25
+ firstMonomer: string,
26
+ secondMonomer: string,
27
+ firstSubstitution: string,
28
+ secondSubstitution: string,
29
+ firstLinkingGroup: number,
30
+ secondLinkingGroup: number
31
+ }
32
+
33
+ export async function getRules(ruleFiles: string[]): Promise<Rules> {
34
+ const fileSource = new DG.FileSource(RULES_PATH);
35
+ const linkRules: RuleLink[] = [];
36
+ const rules: Rules = {homodimerCode: null, heterodimerCode: null, linkRules: linkRules};
37
+
38
+ for (let i = 0; i < ruleFiles.length; i++) {
39
+ const rulesRaw = await fileSource.readAsText(ruleFiles[i].replace(RULES_PATH, ''));
40
+ const ruleSingle = JSON.parse(rulesRaw);
41
+ for (let j = 0; j < ruleSingle.length; j++) {
42
+ if (ruleSingle[j].type !== undefined && ruleSingle[j].code !== undefined) {
43
+ switch (ruleSingle[j].type) {
44
+ case RULES_TYPE_LINK: {
45
+ const rule = ruleSingle[j].monomericSubstitution;
46
+ rule['code'] = ruleSingle[j].code;
47
+ linkRules.push(rule);
48
+ break;
49
+ }
50
+ case RULES_TYPE_HOMODIMER: {
51
+ if (rules.homodimerCode)
52
+ grok.shell.warning(`PolyTool: homodimer code is duplicated in rules.`);
53
+ rules.homodimerCode = ruleSingle[j].code;
54
+ break;
55
+ }
56
+ case RULES_TYPE_HETERODIMER: {
57
+ if (rules.heterodimerCode)
58
+ grok.shell.warning(`PolyTool: heterodimer code is duplicated in rules.`);
59
+ rules.heterodimerCode = ruleSingle[j].code;
60
+ break;
61
+ }
62
+ default:
63
+ grok.shell.warning(`PolyTool: Unexpected type - '${ruleSingle[j]}'.`);
64
+ break;
65
+ }
66
+ } else {
67
+ grok.shell.warning('Polytool: rules contain invalid rule');
68
+ }
69
+ }
70
+ }
71
+
72
+ return rules;
73
+ }
@@ -2,6 +2,7 @@
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
+ import {_package} from '../package';
5
6
 
6
7
  import {ALPHABET, ALIGNMENT, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
8
 
@@ -18,3 +19,9 @@ function addCommonTags(col: DG.Column<any>) {
18
19
  col.setTag('alphabet', ALPHABET.PT);
19
20
  }
20
21
 
22
+ export function handleError(err: any): void {
23
+ const errMsg: string = err instanceof Error ? err.message : err.toString();
24
+ const stack: string | undefined = err instanceof Error ? err.stack : undefined;
25
+ grok.shell.error(errMsg);
26
+ _package.logger.error(err.message, undefined, stack);
27
+ }
@@ -1,8 +1,3 @@
1
- /* Do not change these import lines to match external modules in webpack configuration */
2
- import * as grok from 'datagrok-api/grok';
3
- import * as ui from 'datagrok-api/ui';
4
- import * as DG from 'datagrok-api/dg';
5
-
6
1
  import {before, category, expect, test} from '@datagrok-libraries/utils/src/test';
7
2
  import {getNucleotidesSequence} from '../apps/translator/model/conversion-utils';
8
3
  import {loadJsonData} from '../apps/common/model/data-loader/json-loader';
package/tsconfig.json CHANGED
@@ -65,7 +65,7 @@
65
65
  // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
66
66
 
67
67
  /* Advanced Options */
68
- "skipLibCheck": false, /* Skip type checking of declaration files. */
68
+ "skipLibCheck": true, /* Skip type checking of declaration files. */
69
69
  "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
70
70
  }
71
71
  }