@datagrok/sequence-translator 1.4.4 → 1.4.5

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.
@@ -25,7 +25,7 @@
25
25
  },
26
26
  {
27
27
  "type": "reaction",
28
- "code": "3",
28
+ "code": "4",
29
29
  "monomericSubstitution": {
30
30
  "firstMonomer": "azG",
31
31
  "secondMonomer": "aG",
@@ -1,8 +1,8 @@
1
1
  n,seqs
2
2
  1,R-F-C(1)-T-G-H-F-Y-G-H-F-Y-G-H-F-Y-P-C(1)-meI
3
- 2,C(1)-T-G-H-F-Y-P-C(1)-meI
3
+ 2,C(1)-T-G-Aca-F-Y-P-C(1)-meI
4
4
  3,R-F-C(1)-T-G-H-F-Y-P-C(1)
5
5
  4,C(1)-T-G-H-F-H-P-C(1)
6
6
  5,R-F-D(2)-T-G-H-F-Y-P-NH2(2)
7
- 6,R-F-azG(3)-T-G-H-F-Y-P-aG(3)-meI
8
- 7,R-F-aG(3)-T-G-H-F-Y-P-azG(3)-meI
7
+ 6,R-F-azG(4)-T-G-H-F-Y-P-aG(4)-meI
8
+ 7,R-F-aG(4)-T-G-H-F-Y-P-azG(4)-meI
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.4.4",
4
+ "version": "1.4.5",
5
5
  "author": {
6
6
  "name": "Alexey Chopovsky",
7
7
  "email": "achopovsky@datagrok.ai"
@@ -22,10 +22,10 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "^5.44.2",
25
+ "@datagrok-libraries/bio": "^5.45.2",
26
26
  "@datagrok-libraries/chem-meta": "^1.2.7",
27
- "@datagrok-libraries/tutorials": "^1.4.0",
28
- "@datagrok-libraries/utils": "^4.3.5",
27
+ "@datagrok-libraries/tutorials": "^1.4.3",
28
+ "@datagrok-libraries/utils": "^4.3.6",
29
29
  "@types/react": "^18.0.15",
30
30
  "cash-dom": "^8.1.0",
31
31
  "datagrok-api": "^1.21.1",
@@ -36,32 +36,32 @@
36
36
  "ts-loader": "^9.3.1",
37
37
  "typeahead-standalone": "4.14.1",
38
38
  "typescript": "^5.4.2",
39
- "wu": "latest"
39
+ "wu": "^2.1.0"
40
40
  },
41
41
  "devDependencies": {
42
- "@datagrok-libraries/helm-web-editor": "^1.1.11",
43
- "@datagrok-libraries/js-draw-lite": "^0.0.8",
44
- "@datagrok/bio": "^2.15.6",
45
- "@datagrok/helm": "^2.5.3",
46
- "@datagrok/chem": "^1.12.1",
42
+ "@datagrok-libraries/helm-web-editor": "^1.1.12",
43
+ "@datagrok-libraries/js-draw-lite": "^0.0.9",
44
+ "@datagrok/bio": "^2.16.2",
45
+ "@datagrok/helm": "^2.5.4",
46
+ "@datagrok/chem": "^1.12.3",
47
47
  "@types/jquery": "^3.5.14",
48
48
  "@types/js-yaml": "^4.0.5",
49
49
  "@types/lodash": "^4.14.202",
50
50
  "@types/node-fetch": "^2.6.2",
51
51
  "@types/object-hash": "^3.0.6",
52
52
  "@types/react": "^18.0.15",
53
- "@types/wu": "latest",
53
+ "@types/wu": "^2.1.44",
54
54
  "@typescript-eslint/eslint-plugin": "^7.2.0",
55
55
  "@typescript-eslint/parser": "^7.2.0",
56
56
  "css-loader": "^6.7.3",
57
57
  "eslint": "^8.57.0",
58
- "eslint-config-google": "latest",
58
+ "eslint-config-google": "^0.14.0",
59
59
  "style-loader": "^3.3.1",
60
60
  "ts-loader": "^9.3.1",
61
61
  "typescript": "^4.7.4",
62
62
  "typescript-eslint": "^7.2.0",
63
63
  "webpack": "^5.75.0",
64
- "webpack-cli": "latest"
64
+ "webpack-cli": "^5.1.4"
65
65
  },
66
66
  "scripts": {
67
67
  "link-api": "npm link datagrok-api",
@@ -16,8 +16,16 @@ import {MonomerLibWrapper} from './monomer-lib/lib-wrapper';
16
16
  import {FormatConverter} from '../../translator/model/format-converter';
17
17
  import {FormatDetector} from './parsing-validation/format-detector';
18
18
  import {highlightInvalidSubsequence} from '../view/components/colored-input/input-painters';
19
+ import {ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
19
20
 
20
21
  export class OligoToolkitPackage extends DG.Package implements ITranslationHelper {
22
+ private _seqHelper: ISeqHelper;
23
+ public get seqHelper(): ISeqHelper {
24
+ if (!this._seqHelper)
25
+ throw new Error('Package SequenceTranslator .seqHelper is not initialized');
26
+ return this._seqHelper;
27
+ }
28
+
21
29
  private _monomerLib?: IMonomerLib;
22
30
  get monomerLib(): IMonomerLib {
23
31
  if (!this._monomerLib)
@@ -47,6 +55,10 @@ export class OligoToolkitPackage extends DG.Package implements ITranslationHelpe
47
55
 
48
56
  private initPromise?: Promise<void>;
49
57
 
58
+ completeInit(seqHelper: ISeqHelper): void {
59
+ this._seqHelper = seqHelper;
60
+ }
61
+
50
62
  async initLibData(): Promise<void> {
51
63
  if (!this.initPromise) {
52
64
  this.initPromise = (async () => {
@@ -17,8 +17,8 @@ export class MoleculeImage {
17
17
  this.molblock = molblok;
18
18
  }
19
19
 
20
- private _validMolBlock: string;
21
- get molblock(): string { return this._validMolBlock; }
20
+ private _validMolBlock!: string;
21
+ get molblock(): string { return this._validMolBlock!; }
22
22
 
23
23
  set molblock(value: string) {
24
24
  if (value === '') {
@@ -33,7 +33,7 @@ export class DataManager {
33
33
  instance.currentUserName = await instance.fetchCurrentUserName();
34
34
  instance.currentUserId = await instance.fetchCurrentUserId();
35
35
 
36
- const patternRecords = await instance.fetchPatterns();
36
+ const patternRecords = instance.fetchPatterns();
37
37
  await instance.initializePatternMaps(patternRecords);
38
38
 
39
39
  return instance;
@@ -81,7 +81,7 @@ export class DataManager {
81
81
  if (hash === null || hash === '')
82
82
  return null;
83
83
  try {
84
- const patternConfig = await grok.dapi.userDataStorage.getValue(STORAGE_NAME, hash, false);
84
+ const patternConfig = grok.userSettings.getValue(STORAGE_NAME, hash, false) ?? 'null';
85
85
  const config = JSON.parse(patternConfig) as PatternConfigRecord;
86
86
  return config;
87
87
  } catch {
@@ -181,7 +181,7 @@ export class DataManager {
181
181
  [D.MODIFY]: timestamp,
182
182
  };
183
183
  const record = JSON.stringify(recordObj);
184
- await grok.dapi.userDataStorage.postValue(STORAGE_NAME, hash, record, false);
184
+ grok.userSettings.add(STORAGE_NAME, hash, record, false);
185
185
  this.currentUserPatternNameToHash.set(patternName, hash);
186
186
 
187
187
  eventBus.selectAuthor(this.getCurrentUserAuthorshipCategory());
@@ -212,14 +212,14 @@ export class DataManager {
212
212
  newRecordObj[R.DATE] = {
213
213
  [D.MODIFY]: timestamp,
214
214
  };
215
- const oldPattern = await grok.dapi.userDataStorage.getValue(STORAGE_NAME, oldHash, false);
215
+ const oldPattern = grok.userSettings.getValue(STORAGE_NAME, oldHash, false) ?? 'null';
216
216
  const oldPatternsRecord = JSON.parse(oldPattern) as PatternConfigRecord;
217
217
  if (oldPatternsRecord[R.DATE] !== undefined && oldPatternsRecord[R.DATE][D.CREATE] != undefined)
218
218
  newRecordObj[R.DATE][D.CREATE] = oldPatternsRecord[R.DATE][D.CREATE];
219
219
 
220
220
  const newRecord = JSON.stringify(newRecordObj);
221
- await grok.dapi.userDataStorage.postValue(STORAGE_NAME, newHash, newRecord, false);
222
- await grok.dapi.userDataStorage.remove(STORAGE_NAME, oldHash, false);
221
+ grok.userSettings.add(STORAGE_NAME, newHash, newRecord, false);
222
+ grok.userSettings.delete(STORAGE_NAME, oldHash, false);
223
223
 
224
224
  this.currentUserPatternNameToHash.set(patternName, newHash);
225
225
  eventBus.requestPatternLoad(newHash);
@@ -237,7 +237,7 @@ export class DataManager {
237
237
  }
238
238
  if (hash === undefined)
239
239
  throw new Error(`Pattern with name ${patternName} not found`);
240
- await grok.dapi.userDataStorage.remove(STORAGE_NAME, hash, false);
240
+ grok.userSettings.delete(STORAGE_NAME, hash, false);
241
241
  this.currentUserPatternNameToHash.delete(patternName);
242
242
  eventBus.updatePatternList();
243
243
 
@@ -264,8 +264,8 @@ export class DataManager {
264
264
  return (await grok.dapi.users.current()).id;
265
265
  }
266
266
 
267
- private async fetchPatterns() {
268
- const patternsRecord = await grok.dapi.userDataStorage.get(STORAGE_NAME, false) as RawPatternRecords;
267
+ private fetchPatterns(): RawPatternRecords {
268
+ const patternsRecord = (grok.userSettings.get(STORAGE_NAME, false) ?? {}) as RawPatternRecords;
269
269
  return patternsRecord;
270
270
  }
271
271
 
@@ -3,9 +3,10 @@ import * as DG from 'datagrok-api/dg';
3
3
  import * as grok from 'datagrok-api/grok';
4
4
  import * as ui from 'datagrok-api/ui';
5
5
 
6
+ import $ from 'cash-dom';
6
7
  import {Subject, BehaviorSubject, Observable} from 'rxjs';
7
8
 
8
- import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
9
+ import {ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
9
10
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
10
11
 
11
12
  import {DEFAULT_FORMATS} from '../../common/model/const';
@@ -22,7 +23,6 @@ import {ITranslationHelper} from '../../../types';
22
23
 
23
24
  import {NUCLEOTIDES_FORMAT, SEQUENCE_COPIED_MSG, SEQ_TOOLTIP_MSG} from './const';
24
25
  import './style.css';
25
- import $ from 'cash-dom';
26
26
  import {_package} from '../../../package';
27
27
 
28
28
  const enum REQUIRED_COLUMN_LABEL {
@@ -34,9 +34,10 @@ const REQUIRED_COLUMN_LABELS = [REQUIRED_COLUMN_LABEL.SEQUENCE];
34
34
  class TranslatorAppLayout {
35
35
  private eventBus: EventBus;
36
36
  private inputFormats = Object.keys(_package.jsonData.codesToHelmDict).concat(DEFAULT_FORMATS.HELM);
37
+ private readonly seqHelper: ISeqHelper = _package.seqHelper;
37
38
 
38
39
  constructor(
39
- private readonly th: ITranslationHelper
40
+ private readonly th: ITranslationHelper,
40
41
  ) {
41
42
  this.moleculeImgDiv = ui.div([]);
42
43
  this.moleculeImgDiv.className = 'mol-host';
@@ -171,9 +172,9 @@ class TranslatorAppLayout {
171
172
  translatedColumn.semType = DG.SEMTYPE.MACROMOLECULE;
172
173
  const units = outputFormat == NUCLEOTIDES_FORMAT ? NOTATION.FASTA : NOTATION.HELM;
173
174
  translatedColumn.meta.units = units;
174
- const seqHandler = SeqHandler.forColumn(translatedColumn as DG.Column<string>);
175
- const setUnits = outputFormat == NUCLEOTIDES_FORMAT ? SeqHandler.setUnitsToFastaColumn :
176
- SeqHandler.setUnitsToHelmColumn;
175
+ const seqHandler = this.seqHelper.getSeqHandler(translatedColumn as DG.Column<string>);
176
+ const setUnits = outputFormat == NUCLEOTIDES_FORMAT ? this.seqHelper.setUnitsToFastaColumn :
177
+ this.seqHelper.setUnitsToHelmColumn;
177
178
  setUnits(seqHandler);
178
179
  }
179
180
 
@@ -462,8 +463,7 @@ class ColumnInputsManager {
462
463
  const input = ui.input.choice(`${columnLabel}`, {
463
464
  value: selectedColumnName, items: columnNames,
464
465
  onValueChanged: (value) => this.selectColumnIfTableNotNull(selectedTable, value, columnLabel)
465
- }
466
- );
466
+ });
467
467
 
468
468
  return input;
469
469
  }
@@ -8,10 +8,12 @@ import './tests/formats-to-helm';
8
8
  import './tests/helm-to-nucleotides';
9
9
  import './tests/formats-support';
10
10
  import './tests/files-tests';
11
+ import './tests/polytool-detectors-custom-notation-test';
11
12
  import './tests/polytool-convert-tests';
12
13
  import './tests/polytool-unrule-tests';
13
14
  import './tests/polytool-enumerate-tests';
14
15
  import './tests/polytool-enumerate-breadth-tests';
16
+ import './tests/polytool-chain-parse-notation-tests';
15
17
  import './tests/toAtomicLevel-tests';
16
18
 
17
19
  import {OligoToolkitTestPackage} from './tests/utils';
package/src/package.ts CHANGED
@@ -2,16 +2,15 @@ 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
 
5
- import {MonomerLibWrapper} from './apps/common/model/monomer-lib/lib-wrapper';
5
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
6
+ import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
7
+
6
8
  import {OligoToolkitPackage} from './apps/common/model/oligo-toolkit-package';
7
- import {FormatDetector} from './apps/common/model/parsing-validation/format-detector';
8
- import {SequenceValidator} from './apps/common/model/parsing-validation/sequence-validator';
9
9
  import {APP_NAME} from './apps/common/view/const';
10
10
  import {getSpecifiedAppUI} from './apps/common/view/utils';
11
11
  import {CombinedAppUI} from './apps/common/view/combined-app-ui';
12
12
  import {linkStrandsV3000} from './apps/structure/model/mol-transformations';
13
13
  import {SequenceToMolfileConverter} from './apps/structure/model/sequence-to-molfile';
14
- import {FormatConverter} from './apps/translator/model/format-converter';
15
14
  import {demoOligoPatternUI, demoOligoStructureUI, demoOligoTranslatorUI} from './demo/demo-st-ui';
16
15
  import {getExternalAppViewFactories} from './plugins/mermade';
17
16
  import {defaultErrorHandler} from './utils/err-info';
@@ -26,9 +25,27 @@ import {ITranslationHelper} from './types';
26
25
  import {addContextMenuUI} from './utils/context-menu';
27
26
  import {PolyToolConvertFuncEditor} from './polytool/pt-convert-editor';
28
27
  import {polyToolUnruleUI} from './polytool/pt-unrule';
28
+ import {CyclizedNotationProvider} from './utils/cyclized';
29
+ import {getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
29
30
 
30
31
  export const _package: OligoToolkitPackage = new OligoToolkitPackage({debug: true}/**/);
31
32
 
33
+ let initSequenceTranslatorPromise: Promise<void> | null = null;
34
+
35
+ //tags: init
36
+ export async function init(): Promise<void> {
37
+ if (initSequenceTranslatorPromise === null)
38
+ initSequenceTranslatorPromise = initSequenceTranslatorInt();
39
+ return initSequenceTranslatorPromise;
40
+ }
41
+
42
+ async function initSequenceTranslatorInt(): Promise<void> {
43
+ const [seqHelper] = await Promise.all([
44
+ getSeqHelper(),
45
+ ]);
46
+ _package.completeInit(seqHelper);
47
+ }
48
+
32
49
  //name: Oligo Toolkit
33
50
  //meta.icon: img/icons/toolkit.png
34
51
  //meta.browsePath: Oligo
@@ -277,3 +294,12 @@ export async function ptEnumeratorHelmApp(): Promise<void> {
277
294
  export async function ptEnumeratorChemApp(): Promise<void> {
278
295
  polyToolEnumerateChemUI();
279
296
  }
297
+
298
+ //name: applyNotationProviderForHarmonizedSequence
299
+ //input: column col
300
+ //input: string separator
301
+ export function applyNotationProviderForCyclized(col: DG.Column<string>, separator: string) {
302
+ col.meta.units = NOTATION.CUSTOM;
303
+ col.tags['pt-role'] = 'template';
304
+ col.temp[SeqTemps.notationProvider] = new CyclizedNotationProvider(separator, _package.seqHelper);
305
+ }
@@ -2,36 +2,39 @@ 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
 
5
- import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
6
- import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
5
+ import wu from 'wu';
6
+
7
+ import {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
8
+ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
7
9
  import {IMonomerLib, IMonomerLibBase, Monomer, MonomerLibData, RGroup} from '@datagrok-libraries/bio/src/types';
8
10
  import {RDModule, RDMol, RDReaction, MolList, RDReactionResult} from '@datagrok-libraries/chem-meta/src/rdkit-api';
9
- import {HELM_REQUIRED_FIELD, HELM_RGROUP_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
11
+ import {HELM_REQUIRED_FIELD as REQ, HELM_OPTIONAL_FIELDS as OPT, HELM_RGROUP_FIELDS, HELM_OPTIONAL_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
10
12
  import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
13
+ import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
14
+ import {HelmMol, HelmType, JSDraw2ModuleType, OrgType} from '@datagrok-libraries/bio/src/helm/types';
15
+ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
11
16
 
12
17
  import {Rules, RuleLink, RuleReaction} from './pt-rules';
13
18
  import {InvalidReactionError, MonomerNotFoundError} from './types';
14
- import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
19
+
15
20
  import {_package} from '../package';
16
21
 
17
- export const RULES_DIMER = '(#2)';
18
- export const RULES_HETERODIMER = '($2)';
22
+ declare const JSDraw2: JSDraw2ModuleType;
23
+ declare const org: OrgType;
19
24
 
20
- // function addCommonTags(col: DG.Column): void {
21
- // col.semType = DG.SEMTYPE.MACROMOLECULE;
22
- // col.setTag('aligned', ALIGNMENT.SEQ);
23
- // col.setTag('alphabet', ALPHABET.PT);
24
- // }
25
25
 
26
26
  export class Chain {
27
27
  linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[];
28
28
  monomers: string[][];
29
+ mol: HelmMol | null;
29
30
 
30
31
  constructor(
31
32
  monomers: string[][],
32
- linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[]) {
33
+ linkages: { fChain: number, sChain: number, fMonomer: number, sMonomer: number, fR: number, sR: number }[],
34
+ mol: HelmMol | null) {
33
35
  this.linkages = linkages;
34
36
  this.monomers = monomers;
37
+ this.mol = mol;
35
38
  }
36
39
 
37
40
  static fromHelm(helm: string) {
@@ -78,7 +81,7 @@ export class Chain {
78
81
  }
79
82
  }
80
83
 
81
- return new Chain(monomers, linkages);
84
+ return new Chain(monomers, linkages, null);
82
85
  }
83
86
 
84
87
  static fromNotation(sequence: string, rules: Rules): Chain {
@@ -223,7 +226,97 @@ export class Chain {
223
226
  }
224
227
  }
225
228
 
226
- const chain = new Chain(monomersAll, linkages);
229
+ const chain = new Chain(monomersAll, linkages, null);
230
+ return chain;
231
+ }
232
+
233
+ static async parseNotation(sequence: string): Promise<Chain> {
234
+ const mainFragments: string[][] = [];
235
+
236
+ const linkages: {
237
+ fChain: number,
238
+ sChain: number,
239
+ fMonomer: number,
240
+ sMonomer: number,
241
+ fR: number,
242
+ sR: number
243
+ }[] = [];
244
+
245
+
246
+ const hh = await getHelmHelper();
247
+ // const sampleHwe = hh.createHelmWebEditor();
248
+ // sampleHwe.editor.setHelm('PEPTIDE1{R.P.D.[meI]}$$$$');
249
+
250
+ const resHwe = hh.createHelmWebEditor();
251
+ const resMol = resHwe.editor.m;
252
+
253
+ const rxp = /(\(.\d+\))?\{[^\}]*\}/g;
254
+ const seqs: string [] = [];
255
+ seqs.push(sequence.replaceAll(rxp, ''));
256
+
257
+ //const l = (rxpRes?.length) ?? -1;
258
+
259
+ const matches = sequence.matchAll(rxp);
260
+ //const rxpRes = rxp.exec(sequence);
261
+ for (const m of matches) {
262
+ const str = m![0];
263
+ if (str)
264
+ seqs.push(str);
265
+ }
266
+
267
+ let counter = 0;
268
+ for (let i = 0; i < seqs.length; i++) {
269
+ const splMonomers = seqs[i].split('-');
270
+ const monomers: string [] = new Array<string>(splMonomers.length);
271
+ for (let j = 0; j < splMonomers.length; j++) {
272
+ const monomer = splMonomers[j].replace('{', '').replace('}', '');
273
+ if (monomer !== '') {
274
+ monomers[j] = monomer;
275
+ counter++;
276
+ } else {
277
+ linkages.push({fChain: i, sChain: i + 1, fMonomer: counter, sMonomer: counter + 1, fR: 1, sR: 1});
278
+ }
279
+ }
280
+
281
+ mainFragments.push(monomers);
282
+ }
283
+
284
+ counter = 0;
285
+ const p = new JSDraw2.Point(0, 0);
286
+ for (let i = 0; i < mainFragments.length; i++) {
287
+ for (let j = 0; j < mainFragments[i].length; j++) {
288
+ if (!!mainFragments[i][j]) {
289
+ const elem = mainFragments[i][j];
290
+ const bio = {type: HelmTypes.AA, i: i, j: j};
291
+ const atom = new JSDraw2.Atom<HelmType>(p, elem, bio);
292
+ resMol.addAtom(atom);
293
+
294
+ if (j !== 0) {
295
+ const atom1 = resMol.atoms[counter - 1];
296
+ const atom2 = resMol.atoms[counter];
297
+ const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
298
+ bond.r1 = 2;
299
+ bond.r2 = 1;
300
+ resMol.addBond(bond);
301
+ }
302
+
303
+ counter++;
304
+ p.x += JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
305
+ }
306
+ p.y += 4 * JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
307
+ }
308
+ }
309
+
310
+ for (let i = 0; i < linkages.length; i++) {
311
+ const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
312
+ const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
313
+ const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
314
+ bond.r1 = linkages[i].fR;
315
+ bond.r2 = linkages[i].sR;
316
+ resMol.addBond(bond);
317
+ }
318
+
319
+ const chain = new Chain(mainFragments, linkages, resMol);
227
320
  return chain;
228
321
  }
229
322
 
@@ -233,17 +326,17 @@ export class Chain {
233
326
  let idx1 = 0;
234
327
  let idx2 = 0;
235
328
  loop1:
236
- for (let i = 0; i < this.monomers.length; i++) {
237
- loop2:
238
- for (let j = 0; j < this.monomers[i].length; j++) {
239
- if (counter == changeNumber) {
240
- idx1 = i;
241
- idx2 = j;
242
- break loop1;
243
- }
244
- counter++;
245
- }
329
+ for (let i = 0; i < this.monomers.length; i++) {
330
+ loop2:
331
+ for (let j = 0; j < this.monomers[i].length; j++) {
332
+ if (counter == changeNumber) {
333
+ idx1 = i;
334
+ idx2 = j;
335
+ break loop1;
336
+ }
337
+ counter++;
246
338
  }
339
+ }
247
340
 
248
341
  const previous = this.monomers[idx1][idx2];
249
342
 
@@ -254,6 +347,10 @@ export class Chain {
254
347
  return res;
255
348
  }
256
349
 
350
+ getNotationHelm(): string {
351
+ return this.getHelm();
352
+ }
353
+
257
354
  getHelm(): string {
258
355
  let helm = '';
259
356
  for (let i = 0; i < this.monomers.length; i++) {
@@ -285,8 +382,66 @@ export class Chain {
285
382
  return helm;
286
383
  }
287
384
 
288
- getNotation(rules: Rules): string {
289
- return 'not implemented';
385
+ getNotation(): string {
386
+ const atoms = this.mol!.atoms;
387
+ const bonds = this.mol!.bonds;
388
+ const chains: number[] = [];
389
+ const specialBonds: number[] = [];
390
+ for (let i = 0; i < bonds.length!; i++) {
391
+ //@ts-ignore
392
+ if (bonds[i].a1.bio.i !== bonds[i].a2.bio.i)
393
+ specialBonds.push(i);
394
+ }
395
+
396
+ for (let i = 0; i < atoms.length!; i++) {
397
+ //@ts-ignore
398
+ const atomChain = atoms[i].bio?.i;
399
+ if (atomChain + 1 > chains.length)
400
+ chains.push(1);
401
+ else
402
+ chains[atomChain]++;
403
+ }
404
+
405
+ const simpleChains: string[][] = new Array(chains.length);
406
+ let counter = 0;
407
+ for (let i = 0; i < chains.length!; i++) {
408
+ const simpleChain: string[] = new Array(chains[i]);
409
+ for (let j = 0; j < chains[i]; j++) {
410
+ simpleChain[j] = atoms[counter].elem;
411
+ counter++;
412
+ }
413
+
414
+ simpleChains[i] = simpleChain;
415
+ }
416
+
417
+ let res = '';
418
+ for (let i = 0; i < simpleChains.length; i++) {
419
+ let chainAdd = '';
420
+
421
+ for (let j = 0; j < simpleChains[i].length; j++)
422
+ chainAdd += `${j == 0 ? '' : '-'}${simpleChains[i][j]}`;
423
+
424
+ if (i !== 0) {
425
+ const rxp = /(\(.\d+\))/;
426
+ const match = chainAdd.match(rxp);
427
+ chainAdd = chainAdd.replace(match?.[0]!, '');
428
+ const group = match ? match?.[0]! : '';
429
+ chainAdd = `${group}{${chainAdd}}`;
430
+ } else {
431
+ if (simpleChains.length > 1) {
432
+ //@ts-ignore
433
+ const firstAtomLinks = bonds[specialBonds[0]].a1.bio.i == 0 && bonds[specialBonds[0]].a1.bio.j == 0;
434
+ //@ts-ignore
435
+ const secondAtomLinks = bonds[specialBonds[0]].a2.bio.i == 1 && bonds[specialBonds[0]].a1.bio.j == 0;
436
+ if (firstAtomLinks && secondAtomLinks)
437
+ chainAdd += '-';
438
+ }
439
+ }
440
+
441
+ res += chainAdd;
442
+ }
443
+
444
+ return res;
290
445
  }
291
446
 
292
447
  protected static getLinkedPositions(monomers: string[], rules: RuleLink[] | RuleReaction []):
@@ -517,18 +672,24 @@ export function getNewMonomer(rdkit: RDModule, mLib: IMonomerLib, rule: RuleReac
517
672
  const groups: RGroup[] = getNewGroups(monomer1!, monomer2!);
518
673
 
519
674
  const resMonomer: Monomer = {
520
- [HELM_REQUIRED_FIELD.SYMBOL]: monomerName,
521
- [HELM_REQUIRED_FIELD.NAME]: monomerName,
522
- [HELM_REQUIRED_FIELD.MOLFILE]: molBlock,
523
- [HELM_REQUIRED_FIELD.AUTHOR]: '',
524
- [HELM_REQUIRED_FIELD.ID]: 0,
525
- [HELM_REQUIRED_FIELD.RGROUPS]: groups,
526
- [HELM_REQUIRED_FIELD.SMILES]: '',
527
- [HELM_REQUIRED_FIELD.POLYMER_TYPE]: 'PEPTIDE',
528
- [HELM_REQUIRED_FIELD.MONOMER_TYPE]: 'Backbone',
529
- [HELM_REQUIRED_FIELD.CREATE_DATE]: null,
675
+ [REQ.SYMBOL]: monomerName,
676
+ [REQ.NAME]: monomerName,
677
+ [REQ.MOLFILE]: molBlock,
678
+ [REQ.AUTHOR]: '',
679
+ [REQ.ID]: 0,
680
+ [REQ.RGROUPS]: groups,
681
+ [REQ.SMILES]: '',
682
+ [REQ.POLYMER_TYPE]: 'PEPTIDE',
683
+ [REQ.MONOMER_TYPE]: 'Backbone',
684
+ [REQ.CREATE_DATE]: null,
685
+
686
+ // // @ts-ignore
687
+ // lib: {source: 'Reaction'},
530
688
  };
531
689
 
690
+ resMonomer[OPT.META] = Object.assign(resMonomer[OPT.META] ?? {},
691
+ {'colors': {'default': {line: '#2083D5', text: '#2083D5', background: '#F2F2F5'}}});
692
+
532
693
  return [monomerName, resMonomer];
533
694
  }
534
695
 
@@ -545,6 +706,7 @@ export async function getOverriddenLibrary(rules: Rules): Promise<IMonomerLibBas
545
706
  }
546
707
 
547
708
  const overrideMonomerLibData: MonomerLibData = {[PolymerTypes.PEPTIDE]: argLib};
548
- const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData);
709
+ const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData,
710
+ 'ST-PT-reactions.' + wu.repeat(1).map(() => Math.floor((Math.random() * 36)).toString(36)).take(4).toArray().join(''));
549
711
  return overriddenMonomerLib;
550
712
  }
@@ -9,7 +9,10 @@ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
9
9
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
10
10
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
11
11
  import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
12
- import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
12
+ import {MmcrTemps} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
13
+ import {buildMonomerHoverLink} from '@datagrok-libraries/bio/src/monomer-works/monomer-hover';
14
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
15
+ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
13
16
 
14
17
  import {getRules, RuleInputs, Rules, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
15
18
  import {doPolyToolConvert, getOverriddenLibrary} from './pt-conversion';
@@ -74,7 +77,7 @@ export async function getPolyToolConvertDialog(srcCol?: DG.Column): Promise<DG.D
74
77
  table: srcColVal.dataFrame, value: srcColVal,
75
78
  filter: (col: DG.Column) => {
76
79
  if (col.semType !== DG.SEMTYPE.MACROMOLECULE) return false;
77
- const sh = SeqHandler.forColumn(col);
80
+ const sh = _package.seqHelper.getSeqHandler(col);
78
81
  return sh.notation === NOTATION.CUSTOM;
79
82
  }
80
83
  });
@@ -256,7 +259,11 @@ export async function polyToolConvert(
256
259
  if (generateHelm && table) table.columns.add(resHelmCol, true);
257
260
 
258
261
  const seqHelper: ISeqHelper = await getSeqHelper();
262
+ const rdKitModule: RDModule = await getRdKitModule();
259
263
  const lib = await getOverriddenLibrary(rules);
264
+ const resHelmColTemp = resHelmCol.temp;
265
+ resHelmColTemp[MmcrTemps.overriddenLibrary] = lib;
266
+ resHelmCol.temp = resHelmColTemp;
260
267
  const toAtomicLevelRes =
261
268
  await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, /* highlight */ generateHelm, lib);
262
269
  const resMolCol = toAtomicLevelRes.molCol!;
@@ -267,6 +274,9 @@ export async function polyToolConvert(
267
274
  table.columns.add(resMolCol, true);
268
275
  await grok.data.detectSemanticTypes(table);
269
276
  }
277
+
278
+ buildMonomerHoverLink(resHelmCol, resMolCol, lib, seqHelper, rdKitModule);
279
+
270
280
  return [resHelmCol, resMolCol];
271
281
  } finally {
272
282
  pi.close();