@datagrok/sequence-translator 1.4.5 → 1.4.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.
@@ -38,17 +38,18 @@ type PolyToolEnumerateChemSerialized = {
38
38
  screenLibrary: string | null;
39
39
  }
40
40
 
41
- export function polyToolEnumerateChemUI(cell?: DG.Cell): void {
42
- getPolyToolEnumerationChemDialog(cell)
43
- .then((dialog) => {
44
- dialog.show({resizable: true});
45
- })
46
- .catch((_err: any) => {
47
- grok.shell.warning('To run PolyTool Enumeration, sketch the molecule and specify the R group to vary');
48
- });
41
+ export async function polyToolEnumerateChemUI(cell?: DG.Cell): Promise<void> {
42
+ await _package.initPromise;
43
+ try {
44
+ const dialog = await getPolyToolEnumerationChemDialog(cell);
45
+ dialog.show({resizable: true});
46
+ } catch (_err: any) {
47
+ grok.shell.warning('To run PolyTool Enumeration, sketch the molecule and specify the R group to vary');
48
+ }
49
49
  }
50
50
 
51
51
  export async function polyToolConvertUI(): Promise<void> {
52
+ await _package.initPromise;
52
53
  let dialog: DG.Dialog;
53
54
  try {
54
55
  dialog = await getPolyToolConvertDialog();
@@ -234,6 +235,11 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
234
235
  }
235
236
  }
236
237
 
238
+ function dealGroups(col: DG.Column<string>): void {
239
+ for (let i = 0; i < col.length; i++)
240
+ col.set(i, col.get(i)!.replaceAll('undefined', 'H'));
241
+ }
242
+
237
243
  /** Returns Helm and molfile columns. */
238
244
  export async function polyToolConvert(
239
245
  seqCol: DG.Column<string>, generateHelm: boolean, chiralityEngine: boolean, ruleFiles: string[]
@@ -244,11 +250,11 @@ export async function polyToolConvert(
244
250
  if (!df) return colName;
245
251
  return df.columns.getUnusedName(colName);
246
252
  };
247
- await getHelmHelper(); // initializes JSDraw and org
253
+ const helmHelper = await getHelmHelper(); // initializes JSDraw and org
248
254
 
249
255
  const table = seqCol.dataFrame;
250
256
  const rules = await getRules(ruleFiles);
251
- const resList = doPolyToolConvert(seqCol.toList(), rules);
257
+ const resList = doPolyToolConvert(seqCol.toList(), rules, helmHelper);
252
258
 
253
259
  const resHelmColName = getUnusedName(table, `transformed(${seqCol.name})`);
254
260
  const resHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, resHelmColName, resList.length)
@@ -267,7 +273,7 @@ export async function polyToolConvert(
267
273
  const toAtomicLevelRes =
268
274
  await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm, lib);
269
275
  const resMolCol = toAtomicLevelRes.molCol!;
270
-
276
+ dealGroups(resMolCol);
271
277
  resMolCol.name = getUnusedName(table, `molfile(${seqCol.name})`);
272
278
  resMolCol.semType = DG.SEMTYPE.MOLECULE;
273
279
  if (table) {
@@ -5,10 +5,8 @@ import * as DG from 'datagrok-api/dg';
5
5
  import $ from 'cash-dom';
6
6
  import wu from 'wu';
7
7
  import {fromEvent, Unsubscribable} from 'rxjs';
8
-
9
- import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
10
- import {HelmAtom, HelmMol} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
11
- import {getHelmHelper, HelmInputBase} from '@datagrok-libraries/bio/src/helm/helm-helper';
8
+ import {HelmAtom} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
9
+ import {getHelmHelper, HelmInputBase, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
12
10
  import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
13
11
  import {HelmType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
14
12
  import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
@@ -17,17 +15,17 @@ import '@datagrok-libraries/bio/src/types/input';
17
15
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
18
16
  import {InputColumnBase} from '@datagrok-libraries/bio/src/types/input';
19
17
 
20
- import {
21
- PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes
22
- } from './types';
18
+ import {PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes} from './types';
23
19
  import {getLibrariesList} from './utils';
24
20
  import {doPolyToolEnumerateHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
25
21
  import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
26
22
  import {defaultErrorHandler} from '../utils/err-info';
27
23
  import {PolyToolPlaceholdersBreadthInput} from './pt-placeholders-breadth-input';
28
24
  import {PT_UI_DIALOG_ENUMERATION} from './const';
25
+ import {PolyToolDataRole, PolyToolTags} from '../consts';
26
+ import {Chain} from './pt-conversion';
29
27
 
30
- import {_package} from '../package';
28
+ import {_package, applyNotationProviderForCyclized} from '../package';
31
29
 
32
30
  type PolyToolEnumerateInputs = {
33
31
  macromolecule: HelmInputBase;
@@ -52,6 +50,8 @@ type PolyToolEnumerateHelmSerialized = {
52
50
  };
53
51
 
54
52
  export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
53
+ await _package.initPromise;
54
+
55
55
  const maxWidth = window.innerWidth;
56
56
  const maxHeight = window.innerHeight;
57
57
 
@@ -118,7 +118,6 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
118
118
  }
119
119
  }
120
120
 
121
-
122
121
  async function getPolyToolEnumerateDialog(
123
122
  cell?: DG.Cell, resizeInputs?: () => void
124
123
  ): Promise<DG.Dialog> {
@@ -312,11 +311,12 @@ async function getPolyToolEnumerateDialog(
312
311
  inputs.macromolecule.root.style.setProperty('min-width', '250px', 'important');
313
312
  // inputs.macromolecule.root.style.setProperty('max-height', '300px', 'important');
314
313
 
314
+ const phPosSet = new Set<number>(inputs.placeholders.placeholdersValue.map((ph) => ph.position));
315
315
  const updateMolView = () => {
316
316
  const mol = inputs.macromolecule.molValue;
317
317
  for (let aI = 0; aI < mol.atoms.length; aI++) {
318
318
  const a = mol.atoms[aI];
319
- a.highlighted = aI in inputs.placeholders.placeholdersValue;
319
+ a.highlighted = phPosSet.has(aI);
320
320
  }
321
321
  inputs.macromolecule.redraw();
322
322
  };
@@ -363,23 +363,33 @@ async function getPolyToolEnumerateDialog(
363
363
  if (resizeInputs) resizeInputs();
364
364
  };
365
365
 
366
- const fillForCurrentCell = async (cell?: DG.Cell): Promise<void> => {
366
+ const fillForCurrentCell = async (cell?: DG.Cell): Promise<PolyToolDataRole> => {
367
+ let resDataRole;
367
368
  let helmValue: string;
368
369
  let table: DG.DataFrame | undefined = undefined;
369
370
  if (cell && cell.rowIndex >= 0 && cell?.column.semType == DG.SEMTYPE.MACROMOLECULE) {
370
371
  const sh = _package.seqHelper.getSeqHandler(cell.column);
371
- const helmSemValue = await sh.getHelm(cell.rowIndex);
372
- helmValue = helmSemValue.value;
372
+ const mValue = await sh.getValue(cell.rowIndex);
373
+ helmValue = mValue.value;
373
374
  table = cell.dataFrame;
375
+ resDataRole = (mValue.tags[PolyToolTags.dataRole] as PolyToolDataRole.template) ?? PolyToolDataRole.macromolecule;
374
376
  } else {
375
377
  helmValue = PT_HELM_EXAMPLE;
378
+ resDataRole = PolyToolDataRole.macromolecule;
376
379
  }
377
-
378
380
  inputs.macromolecule.stringValue = helmValue;
381
+
382
+ if (resDataRole === PolyToolDataRole.template) {
383
+ inputs.toAtomicLevel.root.style.display = 'none';
384
+ } else {
385
+ inputs.toAtomicLevel.root.style.removeProperty('display');
386
+ }
387
+
379
388
  fillTrivialNameList(table);
389
+ return resDataRole;
380
390
  };
381
391
 
382
- await fillForCurrentCell(cell);
392
+ let dataRole: PolyToolDataRole = await fillForCurrentCell(cell);
383
393
 
384
394
  const exec = async (): Promise<void> => {
385
395
  try {
@@ -402,10 +412,12 @@ async function getPolyToolEnumerateDialog(
402
412
  const params: PolyToolEnumeratorParams = {
403
413
  placeholders: inputs.placeholders.placeholdersValue,
404
414
  type: inputs.enumeratorType.value!,
405
- placeholdersBreadth: inputs.placeholdersBreadth.placeholdersBreadthValue,
415
+ breadthPlaceholders: inputs.placeholdersBreadth.placeholdersBreadthValue,
406
416
  keepOriginal: inputs.keepOriginal.value,
407
417
  };
408
- const enumeratorResDf = await polyToolEnumerateHelm(srcHelm, srcId, params, inputs.toAtomicLevel.value, seqHelper);
418
+ const toAtomicLevelV = inputs.toAtomicLevel.value && dataRole == PolyToolDataRole.macromolecule;
419
+ const enumeratorResDf = await polyToolEnumerateHelm(srcHelm, dataRole, srcId, params,
420
+ toAtomicLevelV, seqHelper, helmHelper);
409
421
  grok.shell.addTableView(enumeratorResDf);
410
422
  }
411
423
  } catch (err: any) {
@@ -460,23 +472,49 @@ async function getPolyToolEnumerateDialog(
460
472
  }
461
473
  }
462
474
 
475
+ /**
476
+ * @param {DG.SemanticValue} srcValue Source value to enumerate, either of data role
477
+ * {@link PolyToolDataRole.template} or {@link PolyToolDataRole.macromolecule}
478
+ * */
463
479
  async function polyToolEnumerateHelm(
464
- srcHelm: string, srcId: { value: string, colName: string } | null, params: PolyToolEnumeratorParams,
465
- toAtomicLevel: boolean, seqHelper: ISeqHelper,
480
+ srcHelm: string, dataRole: PolyToolDataRole, srcId: { value: string, colName: string } | null,
481
+ params: PolyToolEnumeratorParams, toAtomicLevel: boolean, seqHelper: ISeqHelper, helmHelper: IHelmHelper
466
482
  ): Promise<DG.DataFrame> {
467
483
  const pi = DG.TaskBarProgressIndicator.create('PolyTool enumerating...');
468
484
  try {
469
485
  await getHelmHelper(); // initializes JSDraw and org
470
486
 
471
487
  const resList = doPolyToolEnumerateHelm(srcHelm, srcId?.value ?? '', params);
472
- const enumHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'Enumerated', resList.length)
473
- .init((rowIdx: number) => resList[rowIdx][0]);
474
- const enumeratorResDf = DG.DataFrame.fromColumns([enumHelmCol]);
488
+ let enumCol: DG.Column<string>;
489
+ switch (dataRole) {
490
+ case PolyToolDataRole.macromolecule: {
491
+ enumCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'Enumerated', resList.length)
492
+ .init((rowIdx: number) => resList[rowIdx][0]);
493
+ break;
494
+ }
495
+ case PolyToolDataRole.template: {
496
+ const templateList: string[] = new Array<string>(resList.length);
497
+ for (let rowIdx = 0; rowIdx < resList.length; rowIdx++) {
498
+ const pseudoHelm = resList[rowIdx][0];
499
+ const chain = Chain.parseHelm(pseudoHelm, helmHelper);
500
+ templateList[rowIdx] = chain.getNotation();
501
+ }
502
+ enumCol = DG.Column.fromList(DG.COLUMN_TYPE.STRING, 'Enumerated', templateList);
503
+ // enumCol.semType = DG.SEMTYPE.MACROMOLECULE;
504
+ // enumCol.setTag(PolyToolTags.dataRole, PolyToolDataRole.template);
505
+ // applyNotationProviderForCyclized(enumCol, '-');
506
+ break;
507
+ }
508
+ }
509
+ const enumeratorResDf = DG.DataFrame.fromColumns([enumCol]);
510
+ await grok.data.detectSemanticTypes(enumeratorResDf);
511
+ if (dataRole == PolyToolDataRole.template) {
512
+ applyNotationProviderForCyclized(enumCol, '-');
513
+ }
475
514
 
476
- if (toAtomicLevel) {
515
+ if (toAtomicLevel && dataRole != PolyToolDataRole.template) {
477
516
  const seqHelper: ISeqHelper = await getSeqHelper();
478
- const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(enumHelmCol, true, true);
479
- toAtomicLevelRes.molCol!.semType = DG.SEMTYPE.MOLECULE;
517
+ const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(enumCol, true, true);
480
518
  enumeratorResDf.columns.add(toAtomicLevelRes.molCol!, false);
481
519
  }
482
520
 
@@ -11,7 +11,7 @@ import {
11
11
 
12
12
  import {Chain} from './pt-conversion';
13
13
  import {getAvailableMonomers} from './utils';
14
- import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes, PolyToolPlaceholders, PolyToolPlaceholdersBreadth} from './types';
14
+ import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes, PolyToolPlaceholder, PolyToolBreadthPlaceholder} from './types';
15
15
 
16
16
  // For example keep monomers presented in HELMCoreLibrary.json only (not [NH2])
17
17
  export const PT_HELM_EXAMPLE = 'PEPTIDE1{R.[Aca].T.G.H.F.G.A.A.Y.P.E.[meI]}$$$$';
@@ -44,14 +44,14 @@ function polyToolEnumeratorCore(m: HelmMol, start: number, end: number, monomerL
44
44
  * @param placeholders Placeholders by zero-based position key
45
45
  * @returns {string[]} List of enumerated molecules in Helm format
46
46
  */
47
- function getPtEnumeratorSingle(m: HelmMol, placeholders: PolyToolPlaceholders): HelmMol[] {
47
+ function getPtEnumeratorSingle(m: HelmMol, placeholders: PolyToolPlaceholder[]): HelmMol[] {
48
48
  const coreResList: HelmMol[][] = placeholders
49
49
  .map((ph) => polyToolEnumeratorCore(m, ph.position, ph.position, ph.monomers));
50
50
  const resMolList = coreResList.reduce((acc, posList) => acc.concat(posList), []);
51
51
  return resMolList;
52
52
  }
53
53
 
54
- function getPtEnumeratorMatrix(m: HelmMol, placeholders: PolyToolPlaceholders): HelmMol[] {
54
+ function getPtEnumeratorMatrix(m: HelmMol, placeholders: PolyToolPlaceholder[]): HelmMol[] {
55
55
  let resMolList = [m];
56
56
  for (const ph of placeholders) {
57
57
  const phResMolList: HelmMol[][] = resMolList.map((m: HelmMol) => polyToolEnumeratorCore(m, ph.position, ph.position, ph.monomers));
@@ -60,7 +60,10 @@ function getPtEnumeratorMatrix(m: HelmMol, placeholders: PolyToolPlaceholders):
60
60
  return resMolList;
61
61
  }
62
62
 
63
- function getPtEnumeratorBreadth(m: HelmMol, placeholdersBreadth: PolyToolPlaceholdersBreadth): HelmMol[] {
63
+ function getPtEnumeratorBreadth(m: HelmMol, placeholdersBreadth: PolyToolBreadthPlaceholder[]): HelmMol[] {
64
+ if (placeholdersBreadth.length == 0)
65
+ return [];
66
+
64
67
  let resMolList = [m];
65
68
  for (const phb of placeholdersBreadth) {
66
69
  const phResMolList: HelmMol[][] = resMolList.map((m: HelmMol) => polyToolEnumeratorCore(m, phb.start, phb.end, phb.monomers));
@@ -94,8 +97,8 @@ export function doPolyToolEnumerateHelm(
94
97
  }
95
98
 
96
99
  let resBreadthMolList: HelmMol[] = [];
97
- if (params.placeholdersBreadth) {
98
- resBreadthMolList = getPtEnumeratorBreadth(molHandler.m, params.placeholdersBreadth);
100
+ if (params.breadthPlaceholders) {
101
+ resBreadthMolList = getPtEnumeratorBreadth(molHandler.m, params.breadthPlaceholders);
99
102
  }
100
103
  resMolList = resMolList.concat(resBreadthMolList);
101
104
 
@@ -3,7 +3,7 @@ import * as grok from 'datagrok-api/grok';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import {Unsubscribable} from 'rxjs';
6
- import {PolyToolPlaceholders, PolyToolPlaceholdersBreadth} from './types';
6
+ import {PolyToolBreadthPlaceholder} from './types';
7
7
  import {parseMonomerSymbolList} from './pt-placeholders-input';
8
8
 
9
9
  export class PolyToolPlaceholdersBreadthInput extends DG.JsInputBase<DG.DataFrame> {
@@ -21,7 +21,7 @@ export class PolyToolPlaceholdersBreadthInput extends DG.JsInputBase<DG.DataFram
21
21
 
22
22
  setStringValue(str: string): void { this.grid.dataFrame = DG.DataFrame.fromCsv(str); }
23
23
 
24
- get placeholdersBreadthValue(): PolyToolPlaceholdersBreadth {
24
+ get placeholdersBreadthValue(): PolyToolBreadthPlaceholder[] {
25
25
  return dfToPlaceholdersBreadth(this.grid.dataFrame);
26
26
  }
27
27
 
@@ -97,8 +97,8 @@ export class PolyToolPlaceholdersBreadthInput extends DG.JsInputBase<DG.DataFram
97
97
  }
98
98
  }
99
99
 
100
- export function dfToPlaceholdersBreadth(df: DG.DataFrame): PolyToolPlaceholdersBreadth {
101
- const res: PolyToolPlaceholdersBreadth = [];
100
+ export function dfToPlaceholdersBreadth(df: DG.DataFrame): PolyToolBreadthPlaceholder[] {
101
+ const res: PolyToolBreadthPlaceholder[] = [];
102
102
  for (let rowI = 0; rowI < df.rowCount; rowI++) {
103
103
  const startPos = parseInt(df.get('Start', rowI)) - 1;
104
104
  const endPos = parseInt(df.get('End', rowI)) - 1;
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import {Unsubscribable} from 'rxjs';
6
6
 
7
- import {PolyToolPlaceholders} from './types';
7
+ import {PolyToolPlaceholder} from './types';
8
8
 
9
9
  export class PolyToolPlaceholdersInput extends DG.JsInputBase<DG.DataFrame> {
10
10
  get inputType(): string { return 'Positions'; }
@@ -21,7 +21,7 @@ export class PolyToolPlaceholdersInput extends DG.JsInputBase<DG.DataFrame> {
21
21
 
22
22
  setStringValue(str: string): void { this.grid.dataFrame = DG.DataFrame.fromCsv(str); }
23
23
 
24
- get placeholdersValue(): PolyToolPlaceholders {
24
+ get placeholdersValue(): PolyToolPlaceholder[] {
25
25
  return dfToPlaceholders(this.grid.dataFrame);
26
26
  }
27
27
 
@@ -95,8 +95,8 @@ export class PolyToolPlaceholdersInput extends DG.JsInputBase<DG.DataFrame> {
95
95
  }
96
96
  }
97
97
 
98
- export function getPlaceholdersFromText(src: string): PolyToolPlaceholders {
99
- const res: PolyToolPlaceholders = [];
98
+ export function getPlaceholdersFromText(src: string): PolyToolPlaceholder[] {
99
+ const res: PolyToolPlaceholder[] = [];
100
100
  for (const line of src.split('\n')) {
101
101
  const lineM = /^\s*(?<pos>\d+)\s*:\s*(?<monomers>.+)$/.exec(line);
102
102
  if (lineM) {
@@ -108,8 +108,8 @@ export function getPlaceholdersFromText(src: string): PolyToolPlaceholders {
108
108
  return res;
109
109
  }
110
110
 
111
- export function dfToPlaceholders(df: DG.DataFrame): PolyToolPlaceholders {
112
- const res: PolyToolPlaceholders = [];
111
+ export function dfToPlaceholders(df: DG.DataFrame): PolyToolPlaceholder[] {
112
+ const res: PolyToolPlaceholder[] = [];
113
113
  for (let rowI = 0; rowI < df.rowCount; rowI++) {
114
114
  const pos = parseInt(df.get('Position', rowI)) - 1;
115
115
  if (!isNaN(pos)) {
@@ -6,11 +6,13 @@ import {Unsubscribable} from 'rxjs';
6
6
 
7
7
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
8
8
  import {getUnusedColName} from '@datagrok-libraries/bio/src/monomer-works/utils';
9
+ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
9
10
 
10
11
  import {defaultErrorHandler} from '../utils/err-info';
11
12
  import {doPolyToolUnrule} from './pt-unrule';
12
13
  import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
13
14
  import {PT_ERROR_DATAFRAME, PT_UI_DIALOG_UNRULE, PT_UI_RULES_USED} from './const';
15
+
14
16
  import {_package} from '../package';
15
17
 
16
18
  type PolyToolUnruleSerialized = {
@@ -87,9 +89,11 @@ export async function polyToolUnrule(
87
89
  ): Promise<DG.Column> {
88
90
  const pi = DG.TaskBarProgressIndicator.create('PolyTool unrule...');
89
91
  try {
92
+ const helmHelper = await getHelmHelper();
93
+
90
94
  const table = srcCol.dataFrame;
91
95
  const rules = await getRules(ruleFiles);
92
- const resHelmList = doPolyToolUnrule(srcCol.toList(), rules);
96
+ const resHelmList = doPolyToolUnrule(srcCol.toList(), rules, helmHelper);
93
97
  const resHelmColName = `harmonized(srcCol.name)`;
94
98
  const resHelmCol = DG.Column.fromList(DG.COLUMN_TYPE.STRING, resHelmColName, resHelmList,);
95
99
  resHelmCol.semType = DG.SEMTYPE.MACROMOLECULE;
@@ -9,6 +9,7 @@ import {getPolyToolUnruleDialog} from './pt-unrule-dialog';
9
9
  import {Rules} from './pt-rules';
10
10
 
11
11
  import {_package} from '../package';
12
+ import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
12
13
 
13
14
  export async function polyToolUnruleUI(): Promise<void> {
14
15
  let dialog: DG.Dialog;
@@ -23,13 +24,13 @@ export async function polyToolUnruleUI(): Promise<void> {
23
24
  }
24
25
 
25
26
  /** Returns list of harmonized sequences. Covered with tests. */
26
- export function doPolyToolUnrule(helms: string[], rules: Rules): string[] {
27
+ export function doPolyToolUnrule(helms: string[], rules: Rules, helmHelper: IHelmHelper): string[] {
27
28
  const resHrzSeqList = new Array<string>(helms.length);
28
29
  for (let i = 0; i < helms.length; ++i) {
29
30
  if (!helms[i])
30
31
  resHrzSeqList[i] = '';
31
32
  else {
32
- const chain = Chain.fromHelm(helms[i]);
33
+ const chain = Chain.parseHelm(helms[i], helmHelper);
33
34
  resHrzSeqList[i] = chain.getNotation();
34
35
  }
35
36
  }
@@ -11,15 +11,15 @@ export enum PolyToolEnumeratorTypes {
11
11
 
12
12
  export type PolyToolEnumeratorType = typeof PolyToolEnumeratorTypes[keyof typeof PolyToolEnumeratorTypes];
13
13
 
14
- export type PolyToolPlaceholders = { position: number, monomers: string[] } [];
14
+ export type PolyToolPlaceholder = { position: number, monomers: string[] };
15
15
 
16
- export type PolyToolPlaceholdersBreadth = { start: number, end: number, monomers: string[] }[];
16
+ export type PolyToolBreadthPlaceholder = { start: number, end: number, monomers: string[] };
17
17
 
18
18
  export type PolyToolEnumeratorParams = {
19
19
  type: PolyToolEnumeratorType;
20
20
  /** position key is zero-based */
21
- placeholders?: PolyToolPlaceholders;
22
- placeholdersBreadth?: PolyToolPlaceholdersBreadth;
21
+ placeholders?: PolyToolPlaceholder[];
22
+ breadthPlaceholders?: PolyToolBreadthPlaceholder[];
23
23
  keepOriginal?: boolean;
24
24
  trivialName?: boolean;
25
25
  }
@@ -5,41 +5,131 @@ import * as DG from 'datagrok-api/dg';
5
5
  import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
6
  import {Chain} from '../polytool/pt-conversion';
7
7
  import {getRules} from '../polytool/pt-rules';
8
+ import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
9
+
10
+ category('PolyTool: Chain', () => {
11
+ let helmHelper: IHelmHelper;
12
+
13
+ before(async () => {
14
+ helmHelper = await getHelmHelper();
15
+ });
8
16
 
9
- category('PolyTool: Chain: fromNotation', () => {
10
17
  const tests = {
11
18
  'cyclized': {
12
- src: {seq: 'R-F-C(1)-T-G-H-F-Y-P-C(1)-meI'},
19
+ data: {
20
+ templateSeq: 'R-F-C(1)-T-G-H-F-Y-P-C(1)-meI',
21
+ templateHelm: 'PEPTIDE1{R.F.[C(1)].T.G.H.F.Y.P.[C(1)].[meI]}$$$$V2.0',
22
+ mmHelm: 'PEPTIDE1{R.F.C.T.G.H.F.Y.P.C.[meI]}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$V2.0',
23
+ },
13
24
  tgt: {
14
- monomerCount: [11], linkageCount: 1,
15
- helm: 'PEPTIDE1{R.F.C.T.G.H.F.Y.P.C.[meI]}$PEPTIDE1,PEPTIDE1,3:R3-10:R3$$$',
25
+ templateChain: {monomerCount: [11], linkageCount: 0},
26
+ mmChain: {monomerCount: [11], linkageCount: 1,}
16
27
  },
17
28
  },
18
29
  'reaction1': {
19
- src: {seq: 'R-F-azG(3)-T-G-H-F-Y-P-aG(3)-meI'},
30
+ data: {
31
+ templateSeq: 'R-F-azG(4)-T-G-H-F-Y-P-aG(4)-meI',
32
+ templateHelm: 'PEPTIDE1{R.F.[azG(4)].T.G.H.F.Y.P.[aG(4)].[meI]}$$$$V2.0',
33
+ mmHelm: 'PEPTIDE1{R.F.[GGaz].T.G.H.F.Y.P}|PEPTIDE2{[meI]}$PEPTIDE1,PEPTIDE1,3:R3-9:R2|PEPTIDE1,PEPTIDE2,3:R4-1:R1$$$V2.0',
34
+ },
20
35
  tgt: {
21
- monomerCount: [9, 1], linkageCount: 2,
22
- helm: 'PEPTIDE1{R.F.[GGaz].T.G.H.F.Y.P}|PEPTIDE2{[meI]}$PEPTIDE1,PEPTIDE1,3:R3-9:R2|PEPTIDE1,PEPTIDE2,3:R4-1:R1$$$',
36
+ templateChain: {monomerCount: [11], linkageCount: 0,},
37
+ mmChain: {monomerCount: [9, 1], linkageCount: 2,}
23
38
  }
24
39
  },
25
40
  'reaction2': {
26
- src: {seq: 'R-F-aG(3)-T-G-H-F-Y-P-azG(3)-meI'},
41
+ data: {
42
+ templateSeq: 'R-F-aG(4)-T-G-H-F-Y-P-azG(4)-meI',
43
+ templateHelm: 'PEPTIDE1{R.F.[aG(4)].T.G.H.F.Y.P.[azG(4)].[meI]}$$$$V2.0',
44
+ mmHelm: 'PEPTIDE1{R.F}|PEPTIDE2{T.G.H.F.Y.P.[GGaz].[meI]}$PEPTIDE1,PEPTIDE2,2:R2-7:R3|PEPTIDE2,PEPTIDE2,1:R1-7:R4,$$$V2.0',
45
+ },
46
+ tgt: {
47
+ templateChain: {monomerCount: [11], linkageCount: 0,},
48
+ mmChain: {monomerCount: [2, 8], linkageCount: 2,}
49
+ }
50
+ },
51
+ 'dimerized1': {
52
+ data: {
53
+ templateSeq: '(#3)Succ-{A(CHOL)-F-C(1)-T-G-H-Y-P-C(1)-NH2}',
54
+ templateHelm: 'PEPTIDE1{[(#3)Succ]}' + '|' +
55
+ 'PEPTIDE2{[A(CHOL)].F.[C(1)].T.G.H.Y.P.[C(1)].[NH2]}' + '$' +
56
+ 'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '$$$' + 'V2.0',
57
+ mmHelm: 'PEPTIDE1{[Succ].[A(CHOL)].F.C.T.G.H.Y.P.C.[NH2]}' + '|' +
58
+ 'PEPTIDE2{[A(CHOL)].F.C.T.G.H.Y.P.C.[NH2]}' + '$' +
59
+ 'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '|' +
60
+ 'PEPTIDE1,PEPTIDE1,4:R3-10:R3' + '|' +
61
+ 'PEPTIDE2,PEPTIDE2,3:R3-9:R3' + '$$$V2.0',
62
+ },
63
+ tgt: {
64
+ templateChain: {monomerCount: [1, 10], linkageCount: 1},
65
+ mmChain: {monomerCount: [11, 10], linkageCount: 3,}
66
+ }
67
+ },
68
+ 'dimerized2': {
69
+ data: {
70
+ templateSeq: '($3)Succ-{R-F-C(1)-T-G-H-F-P-C(1)-NH2}($3){A(CHOL)-F-C(1)-Y-H-G-D-N-C(1)-meI}',
71
+ templateHelm: 'PEPTIDE1{[($3)Succ]}' + '|' +
72
+ 'PEPTIDE2{R.F.[C(1)].T.G.H.F.P.[C(1)].[NH2]}' + '|' +
73
+ 'PEPTIDE3{[($3)A(CHOL)].F.[C(1)].Y.H.G.D.N.[C(1)].[meI]}' + '$' +
74
+ 'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '$$$' + 'V2.0',
75
+ mmHelm: 'PEPTIDE1{[Succ].R.F.C.T.G.H.F.P.C.[NH2]}' + '|' +
76
+ 'PEPTIDE2{[A(CHOL)].F.C.Y.H.G.D.N.C.[meI]}' + '$' +
77
+ 'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '|' +
78
+ 'PEPTIDE1,PEPTIDE1,4:R3-10:R3' + '|' +
79
+ 'PEPTIDE2,PEPTIDE2,3:R3-9:R3' + '$$$V2.0',
80
+ },
27
81
  tgt: {
28
- // TODO: Target test data requires clarification
29
- monomerCount: [2, 8], linkageCount: 0,
30
- helm: 'PEPTIDE1{R.F}|PEPTIDE2{T.G.H.F.Y.P.[GGaz].[meI]}$PEPTIDE1,PEPTIDE2,2:R2-7:R3|PEPTIDE2,PEPTIDE2,1:R1-7:R4,$$$',
82
+ templateChain: {monomerCount: [1, 10, 10], linkageCount: 1,},
83
+ mmChain: {monomerCount: [11, 10], linkageCount: 3,}
31
84
  }
32
85
  }
33
-
34
86
  };
35
87
 
36
- for (const [testName, testData] of Object.entries(tests)) {
37
- test(`${testName}`, async () => {
88
+ for (const [testName, {data, tgt}] of Object.entries(tests)) {
89
+ test(`fromNotation-${testName}`, async () => {
38
90
  const rules = await getRules(['rules_example.json']);
39
- const resChain = Chain.fromNotation(testData.src.seq, rules);
40
- expectArray(resChain.monomers.map((mL) => mL.length), testData.tgt.monomerCount);
41
- expect(resChain.linkages.length, testData.tgt.linkageCount);
42
- expect(resChain.getHelm(), testData.tgt.helm);
91
+ const resMmChain = Chain.fromNotation(data.templateSeq, rules, helmHelper);
92
+ resMmChain.check(true);
93
+ expectArray(resMmChain.monomers.map((mL) => mL.length), tgt.mmChain.monomerCount);
94
+ expect(resMmChain.linkages.length, tgt.mmChain.linkageCount);
95
+ expect(resMmChain.getHelm(), data.mmHelm);
43
96
  }, testName == 'reaction2' ? {skipReason: 'reverse reaction'} : undefined);
44
97
  }
98
+
99
+ for (const [testName, {data, tgt}] of Object.entries(tests)) {
100
+ test(`parseNotation-${testName}`, async () => {
101
+ const rules = await getRules(['rules_example.json']);
102
+ const resTemplateChain = Chain.parseNotation(data.templateSeq, helmHelper);
103
+ resTemplateChain.check(true);
104
+ expectArray(resTemplateChain.monomers.map((mL) => mL.length), tgt.templateChain.monomerCount);
105
+ expect(resTemplateChain.linkages.length, tgt.templateChain.linkageCount);
106
+ expect(resTemplateChain.getHelm(), data.templateHelm);
107
+ expect(resTemplateChain.getNotation(), data.templateSeq);
108
+ });
109
+ }
110
+
111
+ for (const [testName, {data, tgt}] of Object.entries(tests)) {
112
+ test(`parseHelm-${testName}`, async () => {
113
+ const rules = await getRules(['rules_example.json']);
114
+ const resTemplateChain = Chain.parseHelm(data.templateHelm, helmHelper);
115
+ resTemplateChain.check(true);
116
+ expectArray(resTemplateChain.monomers.map((mL) => mL.length), tgt.templateChain.monomerCount);
117
+ expect(resTemplateChain.linkages.length, tgt.templateChain.linkageCount);
118
+ expect(resTemplateChain.getHelm(), data.templateHelm);
119
+ expect(resTemplateChain.getNotation(), data.templateSeq);
120
+ });
121
+ }
122
+
123
+ for (const [testName, {data, tgt}] of Object.entries(tests)) {
124
+ test(`applyRules-${testName}`, async () => {
125
+ const rules = await getRules(['rules_example.json']);
126
+ const resTemplateChain = Chain.parseNotation(data.templateSeq, helmHelper);
127
+ const resMmChain = resTemplateChain.applyRules(rules);
128
+ resMmChain.check(true);
129
+ expectArray(resMmChain.monomers.map((mL) => mL.length), tgt.mmChain.monomerCount);
130
+ expect(resMmChain.linkages.length, tgt.mmChain.linkageCount);
131
+ expect(resMmChain.getHelm(), data.mmHelm);
132
+ }, {skipReason: 'applyRules is not implemented'});
133
+ }
134
+
45
135
  });