@datagrok/sequence-translator 1.3.1 → 1.3.2

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 (53) hide show
  1. package/.eslintrc.json +1 -1
  2. package/CHANGELOG.md +12 -0
  3. package/dist/package-test.js +1 -2
  4. package/dist/package-test.js.map +1 -1
  5. package/dist/package.js +1 -1
  6. package/dist/package.js.map +1 -1
  7. package/files/monomers-sample/README.md +12 -0
  8. package/files/samples/bulk-translation-axolabs.csv +6 -0
  9. package/files/tests/README.md +2 -0
  10. package/files/tests/axolabs1.csv +2 -0
  11. package/package.json +23 -13
  12. package/src/apps/common/model/data-loader/const.ts +1 -2
  13. package/src/apps/common/model/data-loader/json-loader.ts +22 -31
  14. package/src/apps/common/model/monomer-lib/lib-wrapper.ts +13 -19
  15. package/src/apps/common/model/oligo-toolkit-package.ts +80 -13
  16. package/src/apps/common/model/parsing-validation/format-detector.ts +9 -6
  17. package/src/apps/common/model/parsing-validation/format-handler.ts +16 -13
  18. package/src/apps/common/model/parsing-validation/sequence-validator.ts +8 -3
  19. package/src/apps/common/view/combined-app-ui.ts +12 -10
  20. package/src/apps/common/view/components/colored-input/input-painters.ts +4 -3
  21. package/src/apps/common/view/monomer-lib-viewer.ts +2 -1
  22. package/src/apps/common/view/utils.ts +5 -4
  23. package/src/apps/pattern/model/data-manager.ts +9 -6
  24. package/src/apps/pattern/model/translator.ts +8 -10
  25. package/src/apps/pattern/model/utils.ts +0 -1
  26. package/src/apps/pattern/view/components/strand-editor/strand-controls.ts +0 -1
  27. package/src/apps/pattern/view/components/translation-examples-block.ts +2 -1
  28. package/src/apps/pattern/view/svg-utils/utils.ts +6 -4
  29. package/src/apps/pattern/view/ui.ts +4 -1
  30. package/src/apps/structure/model/monomer-code-parser.ts +15 -5
  31. package/src/apps/structure/model/oligo-structure.ts +17 -16
  32. package/src/apps/structure/model/sequence-to-molfile.ts +2 -1
  33. package/src/apps/structure/view/ui.ts +19 -11
  34. package/src/apps/translator/model/conversion-utils.ts +16 -11
  35. package/src/apps/translator/model/format-converter.ts +15 -5
  36. package/src/apps/translator/view/ui.ts +32 -20
  37. package/src/demo/demo-st-ui.ts +2 -2
  38. package/src/package-test.ts +9 -2
  39. package/src/package.ts +18 -17
  40. package/src/plugins/mermade.ts +11 -8
  41. package/src/tests/const.ts +7 -5
  42. package/src/tests/files-tests.ts +75 -0
  43. package/src/tests/formats-support.ts +12 -11
  44. package/src/tests/formats-to-helm.ts +12 -19
  45. package/src/tests/helm-to-nucleotides.ts +12 -6
  46. package/src/tests/utils.ts +20 -0
  47. package/src/types.ts +18 -0
  48. package/dist/package-test.js.LICENSE.txt +0 -8
  49. /package/files/{codes-to-symbols.json → monomers-sample/codes-to-symbols.json} +0 -0
  50. /package/files/{formats-to-helm.json → monomers-sample/formats-to-helm.json} +0 -0
  51. /package/files/{linkers.json → monomers-sample/linkers.json} +0 -0
  52. /package/files/{monomer-lib.json → monomers-sample/monomer-lib.json} +0 -0
  53. /package/files/{pattern-app-data.json → monomers-sample/pattern-app-data.json} +0 -0
@@ -11,8 +11,8 @@ import {
11
11
 
12
12
  import objectHash from 'object-hash';
13
13
  import {EventBus} from './event-bus';
14
- import {PATTERN_APP_DATA} from '../../common/model/data-loader/json-loader';
15
-
14
+ import {ITranslationHelper} from '../../../types';
15
+ import {_package} from '../../../package';
16
16
 
17
17
  export class DataManager {
18
18
  private currentUserName: string;
@@ -21,10 +21,13 @@ export class DataManager {
21
21
  private currentUserPatternNameToHash = new Map<string, string>();
22
22
 
23
23
  // WARNING: init logic encapsulated
24
- private constructor( ) { }
24
+ private constructor(
25
+ private readonly th: ITranslationHelper
26
+ ) { }
25
27
 
26
28
  static async getInstance(): Promise<DataManager> {
27
- const instance = new DataManager();
29
+ const th = await _package.getTranslationHelper();
30
+ const instance = new DataManager(th);
28
31
 
29
32
  instance.currentUserName = await instance.fetchCurrentUserName();
30
33
  instance.currentUserId = await instance.fetchCurrentUserId();
@@ -222,8 +225,8 @@ export class DataManager {
222
225
  }
223
226
 
224
227
  fetchAvailableNucleotideBases(): string[] {
225
- const format = Object.keys(PATTERN_APP_DATA)[0];
226
- const nucleotideBases: string[] = Object.keys(PATTERN_APP_DATA[format]);
228
+ const format = Object.keys(this.th.jsonData.patternAppData)[0];
229
+ const nucleotideBases: string[] = Object.keys(this.th.jsonData.patternAppData[format]);
227
230
  return nucleotideBases;
228
231
  }
229
232
 
@@ -1,7 +1,9 @@
1
1
  import * as grok from 'datagrok-api/grok';
2
2
  import {STRAND, STRANDS, TERMINI, TERMINUS} from './const';
3
- import {PATTERN_APP_DATA} from '../../common/model/data-loader/json-loader';
4
3
  import {EventBus} from './event-bus';
4
+ import {ITranslationHelper} from '../../../types';
5
+ import {_package} from '../../../package';
6
+ import {JsonData} from '../../common/model/data-loader/json-loader';
5
7
 
6
8
  export function bulkTranslate(eventBus: EventBus): void {
7
9
  const df = eventBus.getTableSelection();
@@ -31,16 +33,12 @@ export function applyPatternToRawSequence(
31
33
  rawNucleotideSequence: string,
32
34
  modifications: string[],
33
35
  ptoFlags: boolean[],
34
- terminalModifications: Record<TERMINUS, string>
36
+ terminalModifications: Record<TERMINUS, string>,
35
37
  ): string {
36
38
  const rawNucleotides = rawNucleotideSequence.split('');
37
39
 
38
40
  const modifiedNucleotides = rawNucleotides.map((nucleotide, i) => {
39
- const modifiedNucleotide = getModifiedNucleotide(
40
- nucleotide,
41
- modifications[i]
42
-
43
- );
41
+ const modifiedNucleotide = getModifiedNucleotide(nucleotide, modifications[i], _package.jsonData);
44
42
  return modifiedNucleotide;
45
43
  });
46
44
 
@@ -51,9 +49,9 @@ export function applyPatternToRawSequence(
51
49
  return modificationsWithPTOLinkages.join('');
52
50
  }
53
51
 
54
- function getModifiedNucleotide(nucleotide: string, modification: string): string {
55
- const format = Object.keys(PATTERN_APP_DATA)[0];
56
- const substitution = PATTERN_APP_DATA[format][modification].substitution;
52
+ function getModifiedNucleotide(nucleotide: string, modification: string, jsonData: JsonData): string {
53
+ const format = Object.keys(jsonData.patternAppData)[0];
54
+ const substitution = jsonData.patternAppData[format][modification].substitution;
57
55
  return nucleotide.replace(/([AGCTU])/, substitution);
58
56
  }
59
57
 
@@ -1,7 +1,6 @@
1
1
  import * as grok from 'datagrok-api/grok';
2
2
  import * as DG from 'datagrok-api/dg';
3
3
 
4
- import {PATTERN_APP_DATA} from '../../common/model/data-loader/json-loader';
5
4
  import {NucleotideSequences} from './types';
6
5
 
7
6
 
@@ -2,7 +2,6 @@ import * as ui from 'datagrok-api/ui';
2
2
 
3
3
  import $ from 'cash-dom';
4
4
 
5
- import {PATTERN_APP_DATA} from '../../../../common/model/data-loader/json-loader';
6
5
  import {STRAND, STRANDS, STRAND_LABEL} from '../../../model/const';
7
6
  import {EventBus} from '../../../model/event-bus';
8
7
  import {StrandType} from '../../../model/types';
@@ -15,6 +15,7 @@ import {SubscriptionManager} from '../../model/subscription-manager';
15
15
 
16
16
  export class TranslationExamplesBlock {
17
17
  private subscriptions = new SubscriptionManager();
18
+
18
19
  constructor(
19
20
  private eventBus: EventBus,
20
21
  private dataManager: DataManager
@@ -55,7 +56,7 @@ class StrandExample {
55
56
  constructor(
56
57
  private strand: STRAND,
57
58
  private eventBus: EventBus,
58
- private subscriptions: SubscriptionManager
59
+ private subscriptions: SubscriptionManager,
59
60
  ) { }
60
61
 
61
62
  create(): HTMLDivElement {
@@ -1,8 +1,10 @@
1
+ import {PATTERN_APP_DATA_FILENAME} from '../../../common/model/data-loader/const';
1
2
  import {NUCLEOTIDES} from '../../../common/model/const';
2
- import {PATTERN_APP_DATA} from '../../../common/model/data-loader/json-loader';
3
3
  import {LUMINANCE_COEFFICIENTS, TEXT_COLOR, SVG_CIRCLE_SIZES} from './const';
4
4
  import {isOverhangNucleotide} from '../../model/utils';
5
5
 
6
+ import {_package} from '../../../../package';
7
+
6
8
  export function computeLegendCircleYPosition(isAntisenseStrandActive: boolean): number {
7
9
  return (isAntisenseStrandActive ? 9.5 : 6) * SVG_CIRCLE_SIZES.NUCLEOBASE_RADIUS;
8
10
  }
@@ -28,10 +30,10 @@ export function computeTextColorForNucleobaseLabel(nucleobase: string): string {
28
30
 
29
31
  export function getNucleobaseColorFromStyleMap(nucleobase: string): string {
30
32
  // todo: optimize
31
- const format = Object.keys(PATTERN_APP_DATA)[0];
33
+ const format = Object.keys(_package.jsonData.patternAppData)[0];
32
34
  if (!format)
33
- throw new Error('No format found in PATTERN_APP_DATA');
35
+ throw new Error(`No format found in '${PATTERN_APP_DATA_FILENAME}'`);
34
36
 
35
- const styleMap = PATTERN_APP_DATA[format];
37
+ const styleMap = _package.jsonData.patternAppData[format];
36
38
  return styleMap[nucleobase].color || '';
37
39
  }
@@ -8,10 +8,13 @@ import {URLRouter} from '../model/router';
8
8
  import {PatternAppLeftSection} from './components/left-section';
9
9
  import {PatternAppRightSection} from './components/right-section';
10
10
  import {PatternConfigRecord} from '../model/types';
11
+ import {ITranslationHelper} from '../../../types';
11
12
 
12
13
 
13
14
  export class OligoPatternUI extends IsolatedAppUIBase {
14
- constructor() {
15
+ constructor(
16
+ private readonly th: ITranslationHelper
17
+ ) {
15
18
  super(APP_NAME.PATTERN);
16
19
  }
17
20
 
@@ -5,8 +5,14 @@ import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {PHOSPHATE_SYMBOL} from './const';
7
7
  import {sortByReverseLength} from '../../common/model/helpers';
8
- import {MonomerLibWrapper} from '../../common/model/monomer-lib/lib-wrapper';
9
- import {MONOMERS_WITH_PHOSPHATE} from '../../common/model/data-loader/json-loader';
8
+
9
+ import {_package} from '../../../package';
10
+
11
+ export class MonomerNotFoundError extends Error {
12
+ constructor(message?: string, options?: ErrorOptions) {
13
+ super(message, options);
14
+ }
15
+ }
10
16
 
11
17
  /** Wrapper for parsing a strand and getting a sequence of monomer IDs (with
12
18
  * omitted linkers, if needed) */
@@ -61,6 +67,10 @@ export class MonomerSequenceParser {
61
67
  const code = allCodesOfFormat.find(
62
68
  (s: string) => s === this.sequence.substring(i, i + s.length)
63
69
  )!;
70
+ if (code === undefined) {
71
+ throw new MonomerNotFoundError(
72
+ `Unable to match a monomer for the rest of the sequence '${this.sequence.slice(i)}'.`);
73
+ }
64
74
  parsedCodes.push(code);
65
75
  i += code.length;
66
76
  }
@@ -76,13 +86,13 @@ export class MonomerSequenceParser {
76
86
 
77
87
  // todo: to be eliminated after full helm support
78
88
  function monomerHasLeftPhosphateLinker(monomerSymbol: string): boolean {
79
- return MONOMERS_WITH_PHOSPHATE['left'].includes(monomerSymbol);
89
+ return _package.jsonData.monomersWithPhosphate['left'].includes(monomerSymbol);
80
90
  }
81
91
 
82
92
  function monomerHasRightPhosphateLinker(monomerSymbol: string): boolean {
83
- return MONOMERS_WITH_PHOSPHATE['right'].includes(monomerSymbol);
93
+ return _package.jsonData.monomersWithPhosphate['right'].includes(monomerSymbol);
84
94
  }
85
95
 
86
96
  function monomerIsPhosphateLinker(monomerSymbol: string): boolean {
87
- return MONOMERS_WITH_PHOSPHATE['phosphate'].includes(monomerSymbol);
97
+ return _package.jsonData.monomersWithPhosphate['phosphate'].includes(monomerSymbol);
88
98
  }
@@ -7,8 +7,7 @@ import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
7
7
  import {download} from '../../common/model/helpers';
8
8
  import {SequenceToMolfileConverter} from './sequence-to-molfile';
9
9
  import {linkStrandsV3000} from './mol-transformations';
10
- import {DEFAULT_FORMATS} from '../../common/model/const';
11
- import {FormatDetector} from '../../common/model/parsing-validation/format-detector';
10
+ import {ITranslationHelper} from '../../../types';
12
11
 
13
12
  export type StrandData = {
14
13
  strand: string,
@@ -16,10 +15,10 @@ export type StrandData = {
16
15
  }
17
16
 
18
17
  /** Get a molfile for a single strand */
19
- export function getMolfileForStrand(strand: string, invert: boolean): string {
18
+ export function getMolfileForStrand(strand: string, invert: boolean, th: ITranslationHelper): string {
20
19
  if (strand === '')
21
20
  return '';
22
- const format = (new FormatDetector(strand)).getFormat();
21
+ const format = th.createFormatDetector(strand).getFormat();
23
22
  if (!format)
24
23
  return '';
25
24
  let molfile = '';
@@ -34,15 +33,15 @@ export function getMolfileForStrand(strand: string, invert: boolean): string {
34
33
 
35
34
  /** Get molfile for single strand or linked strands */
36
35
  export function getLinkedMolfile(
37
- ss: StrandData, as: StrandData, as2: StrandData, useChiral: boolean
36
+ ss: StrandData, as: StrandData, as2: StrandData, useChiral: boolean, th: ITranslationHelper
38
37
  ): string {
39
38
  const nonEmptyStrands = [ss, as, as2].filter((item) => item.strand !== '');
40
39
  if (nonEmptyStrands.length === 1) {
41
- return getMolfileForStrand(nonEmptyStrands[0].strand, nonEmptyStrands[0].invert);
40
+ return getMolfileForStrand(nonEmptyStrands[0].strand, nonEmptyStrands[0].invert, th);
42
41
  } else {
43
- const ssMol = getMolfileForStrand(ss.strand, ss.invert);
44
- const asMol = getMolfileForStrand(as.strand, as.invert);
45
- const as2Mol = getMolfileForStrand(as2.strand, as2.invert);
42
+ const ssMol = getMolfileForStrand(ss.strand, ss.invert, th);
43
+ const asMol = getMolfileForStrand(as.strand, as.invert, th);
44
+ const as2Mol = getMolfileForStrand(as2.strand, as2.invert, th);
46
45
 
47
46
  // select only the non-empty anti-strands
48
47
  const antiStrands = [asMol, as2Mol].filter((item) => item !== '');
@@ -54,8 +53,8 @@ export function getLinkedMolfile(
54
53
 
55
54
  /** Save sdf in case ss and as (and optionally as2) strands entered */
56
55
  export function saveSdf(
57
- ss: StrandData, as: StrandData, as2: StrandData, useChiral: boolean,
58
- oneEntity: boolean
56
+ ss: StrandData, as: StrandData, as2: StrandData, useChiral: boolean, oneEntity: boolean,
57
+ th: ITranslationHelper
59
58
  ): void {
60
59
  const nonEmptyStrands = [ss.strand, as.strand, as2.strand].filter((item) => item !== '');
61
60
  if (
@@ -66,16 +65,16 @@ export function saveSdf(
66
65
  } else {
67
66
  let result: string;
68
67
  if (oneEntity) {
69
- result = getLinkedMolfile(ss, as, as2, useChiral) + '\n$$$$\n';
68
+ result = getLinkedMolfile(ss, as, as2, useChiral, th) + '\n$$$$\n';
70
69
  } else {
71
- const ssMol = getMolfileForStrand(ss.strand, ss.invert);
72
- const asMol = getMolfileForStrand(as.strand, as.invert);
73
- const as2Mol = getMolfileForStrand(as2.strand, as2.invert);
70
+ const ssMol = getMolfileForStrand(ss.strand, ss.invert, th);
71
+ const asMol = getMolfileForStrand(as.strand, as.invert, th);
72
+ const as2Mol = getMolfileForStrand(as2.strand, as2.invert, th);
74
73
  result = ssMol + '\n' +
75
74
  `> <Sequence>\nSense Strand\n$$$$\n`;
76
75
  if (asMol) {
77
76
  result += asMol + '\n' +
78
- `> <Sequence>\nAnti Sense\n$$$$\n`;
77
+ `> <Sequence>\nAnti Sense\n$$$$\n`;
79
78
  }
80
79
  if (as2Mol) {
81
80
  result += as2Mol + '\n' +
@@ -85,9 +84,11 @@ export function saveSdf(
85
84
 
86
85
  // construct date-time in the form yyyy-mm-dd_hh-mm-ss
87
86
  const date = new Date();
87
+
88
88
  function pad(x: number): string {
89
89
  return (x >= 10) ? x.toString() : '0' + x.toString();
90
90
  }
91
+
91
92
  const dateString: string = date.getFullYear() + '-' + pad(date.getMonth() + 1) +
92
93
  '-' + pad(date.getDate()) + '_' + pad(date.getHours()) + '-' +
93
94
  pad(date.getMinutes()) + '-' + pad(date.getSeconds());
@@ -5,12 +5,13 @@ import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {MonomerSequenceParser} from './monomer-code-parser';
7
7
  import {MonomerLibWrapper} from '../../common/model/monomer-lib/lib-wrapper';
8
+ import {_package} from '../../../package';
8
9
 
9
10
  export class SequenceToMolfileConverter {
10
11
  constructor(
11
12
  sequence: string, private invert: boolean = false, format: string
12
13
  ) {
13
- this.lib = MonomerLibWrapper.getInstance();
14
+ this.lib = _package.monomerLibWrapper;
14
15
  const codeToSymbolMap = this.lib.getCodeToSymbolMap(format);
15
16
  this.parser = new MonomerSequenceParser(sequence, codeToSymbolMap);
16
17
  }
@@ -10,11 +10,13 @@ import './style.css';
10
10
  import {errorToConsole} from '@datagrok-libraries/utils/src/to-console';
11
11
 
12
12
  import {ColoredTextInput} from '../../common/view/components/colored-input/colored-text-input';
13
- import {highlightInvalidSubsequence} from '../../common/view/components/colored-input/input-painters';
14
13
  import {MoleculeImage} from '../../common/view/components/molecule-img';
15
14
  import {APP_NAME} from '../../common/view/const';
16
15
  import {IsolatedAppUIBase} from '../../common/view/isolated-app-ui';
17
16
  import {getLinkedMolfile, saveSdf, StrandData} from '../model/oligo-structure';
17
+ import {ITranslationHelper} from '../../../types';
18
+
19
+ import {_package} from '../../../package';
18
20
 
19
21
  const enum DIRECTION {
20
22
  STRAIGHT = '5′ → 3′',
@@ -23,7 +25,10 @@ const enum DIRECTION {
23
25
  const STRANDS = ['ss', 'as', 'as2'] as const;
24
26
 
25
27
  class StructureAppLayout {
28
+ private readonly th: ITranslationHelper;
29
+
26
30
  constructor() {
31
+ this.th = _package;
27
32
  this.onInput = new rxjs.Subject<string>();
28
33
  this.onInvalidInput = new rxjs.Subject<string>();
29
34
  this.inputBase = Object.fromEntries(
@@ -53,12 +58,12 @@ class StructureAppLayout {
53
58
  private onInvalidInput: rxjs.Subject<string>;
54
59
  private useChiralInput: DG.InputBase<boolean | null>;
55
60
  private saveAllStrandsInput: DG.InputBase<boolean | null>;
56
- private inputBase: {[key: string]: DG.InputBase<string>};
57
- private directionInversion: {[key: string]: boolean};
61
+ private inputBase: { [key: string]: DG.InputBase<string> };
62
+ private directionInversion: { [key: string]: boolean };
58
63
  private moleculeImgDiv: HTMLDivElement;
59
64
 
60
- async getHtmlDivElement(): Promise<HTMLDivElement> {
61
- const tableLayout = this.getTableInput();
65
+ async getHtmlDivElement(th: ITranslationHelper): Promise<HTMLDivElement> {
66
+ const tableLayout = this.getTableInput(th);
62
67
  const boolInputsAndButton = this.getBoolInputsAndButton();
63
68
  await this.updateMoleculeImg();
64
69
  const bottomDiv = ui.divH([boolInputsAndButton, this.moleculeImgDiv]);
@@ -75,7 +80,7 @@ class StructureAppLayout {
75
80
  ui.bigButton('Save SDF', () => {
76
81
  const strandData = this.getStrandData();
77
82
  saveSdf(strandData.ss, strandData.as, strandData.as2,
78
- this.useChiralInput.value!, this.saveAllStrandsInput.value!);
83
+ this.useChiralInput.value!, this.saveAllStrandsInput.value!, this.th);
79
84
  })
80
85
  ]);
81
86
 
@@ -86,10 +91,10 @@ class StructureAppLayout {
86
91
  return boolInputsAndButton;
87
92
  }
88
93
 
89
- private getTableInput(): HTMLTableElement {
94
+ private getTableInput(th: ITranslationHelper): HTMLTableElement {
90
95
  const coloredInput = Object.fromEntries(
91
96
  STRANDS.map(
92
- (key) => [key, new ColoredTextInput(this.inputBase[key], highlightInvalidSubsequence)]
97
+ (key) => [key, new ColoredTextInput(this.inputBase[key], th.highlightInvalidSubsequence)]
93
98
  )
94
99
  );
95
100
 
@@ -181,7 +186,7 @@ class StructureAppLayout {
181
186
  // return '';
182
187
  // }
183
188
 
184
- return getLinkedMolfile(ss, as, as2, this.useChiralInput.value!);
189
+ return getLinkedMolfile(ss, as, as2, this.useChiralInput.value!, this.th);
185
190
  }
186
191
 
187
192
  private async updateMoleculeImg(): Promise<void> {
@@ -205,13 +210,16 @@ class StructureAppLayout {
205
210
  }
206
211
 
207
212
  export class OligoStructureUI extends IsolatedAppUIBase {
208
- constructor() {
213
+ constructor(
214
+ private readonly th: ITranslationHelper
215
+ ) {
209
216
  super(APP_NAME.STRUCTURE);
210
217
  this.layout = new StructureAppLayout();
211
218
  }
219
+
212
220
  private readonly layout: StructureAppLayout;
213
221
 
214
222
  protected getContent(): Promise<HTMLDivElement> {
215
- return this.layout.getHtmlDivElement();
223
+ return this.layout.getHtmlDivElement(this.th);
216
224
  }
217
225
  }
@@ -1,12 +1,14 @@
1
1
  import {DEFAULT_FORMATS, NUCLEOTIDES} from '../../common/model/const';
2
2
  import {NUCLEOTIDES_FORMAT} from '../view/const';
3
3
  import {UNKNOWN_SYMBOL} from './const';
4
- import {FormatConverter} from './format-converter';
5
- import {CODES_TO_HELM_DICT} from '../../common/model/data-loader/json-loader';
6
4
  import {MonomerLibWrapper} from '../../common/model/monomer-lib/lib-wrapper';
7
5
 
8
- export function getTranslatedSequences(sequence: string, indexOfFirstInvalidChar: number, sourceFormat: string): {[key: string]: string} {
9
- const supportedFormats = Object.keys(CODES_TO_HELM_DICT).concat([DEFAULT_FORMATS.HELM]) as string[];
6
+ import {ITranslationHelper} from '../../../types';
7
+
8
+ export function getTranslatedSequences(
9
+ sequence: string, indexOfFirstInvalidChar: number, sourceFormat: string, th: ITranslationHelper
10
+ ): { [key: string]: string } {
11
+ const supportedFormats = Object.keys(th.jsonData.codesToHelmDict).concat([DEFAULT_FORMATS.HELM]) as string[];
10
12
 
11
13
  if (!sequence || (indexOfFirstInvalidChar !== -1 && sourceFormat !== DEFAULT_FORMATS.HELM))
12
14
  return {};
@@ -16,7 +18,7 @@ export function getTranslatedSequences(sequence: string, indexOfFirstInvalidChar
16
18
 
17
19
  const outputFormats = supportedFormats.filter((el) => el != sourceFormat)
18
20
  .sort((a, b) => a.localeCompare(b));
19
- const converter = new FormatConverter(sequence, sourceFormat);
21
+ const converter = th.createFormatConverter(sequence, sourceFormat);
20
22
  const result = Object.fromEntries(
21
23
  outputFormats.map((format) => {
22
24
  let translation;
@@ -29,7 +31,7 @@ export function getTranslatedSequences(sequence: string, indexOfFirstInvalidChar
29
31
  }).filter(([_, translation]) => translation)
30
32
  );
31
33
  const helm = (sourceFormat === DEFAULT_FORMATS.HELM) ? sequence : result[DEFAULT_FORMATS.HELM];
32
- const nucleotides = getNucleotidesSequence(helm, MonomerLibWrapper.getInstance());
34
+ const nucleotides = getNucleotidesSequence(helm, th.monomerLibWrapper);
33
35
  if (nucleotides)
34
36
  result['Nucleotides'] = nucleotides;
35
37
  return result;
@@ -50,18 +52,21 @@ export function getNucleotidesSequence(helmString: string, monomerLib: MonomerLi
50
52
  }
51
53
 
52
54
  // todo: remove after refactoring as a workaround
53
- export function convert(sequence: string, sourceFormat: string, targetFormat: string): string | null {
54
- const converter = new FormatConverter(sequence, sourceFormat);
55
+ export function convert(
56
+ sequence: string, sourceFormat: string, targetFormat: string, th: ITranslationHelper
57
+ ): string | null {
58
+ const converter = th.createFormatConverter(sequence, sourceFormat);
55
59
  if (targetFormat === NUCLEOTIDES_FORMAT) {
56
60
  const helm = converter.convertTo(DEFAULT_FORMATS.HELM);
57
- const nucleotides = getNucleotidesSequence(helm, MonomerLibWrapper.getInstance());
61
+ const nucleotides = getNucleotidesSequence(helm, th.monomerLibWrapper);
58
62
  return nucleotides;
59
63
  }
60
64
 
61
65
  return converter.convertTo(targetFormat);
62
66
  }
63
67
 
64
- export function getSupportedTargetFormats(): string[] {
65
- const supportedTargetFormats = Object.keys(CODES_TO_HELM_DICT).concat([DEFAULT_FORMATS.HELM, NUCLEOTIDES_FORMAT]).sort() as string[];
68
+ export function getSupportedTargetFormats(th: ITranslationHelper): string[] {
69
+ const supportedTargetFormats = Object.keys(th.jsonData.codesToHelmDict)
70
+ .concat([DEFAULT_FORMATS.HELM, NUCLEOTIDES_FORMAT]).sort() as string[];
66
71
  return supportedTargetFormats;
67
72
  }
@@ -1,7 +1,9 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
+
2
3
  import {DEFAULT_FORMATS} from '../../common/model/const';
3
- import {PHOSPHATE_SYMBOL, UNKNOWN_SYMBOL} from './const';
4
4
  import {FormatHandler, getRegExpPattern} from '../../common/model/parsing-validation/format-handler';
5
+ import {ITranslationHelper} from '../../../types';
6
+ import {PHOSPHATE_SYMBOL, UNKNOWN_SYMBOL} from './const';
5
7
 
6
8
  const HELM_WRAPPER = {
7
9
  LEFT: 'RNA1{',
@@ -9,14 +11,22 @@ const HELM_WRAPPER = {
9
11
  };
10
12
 
11
13
  export class FormatConverter {
12
- constructor(private readonly sequence: string, private readonly sourceFormat: string) { };
14
+ constructor(
15
+ private readonly sequence: string,
16
+ private readonly sourceFormat: string,
17
+ private readonly th: ITranslationHelper,
18
+ ) { };
13
19
 
14
- private formats = new FormatHandler();
20
+ private formats = new FormatHandler(this.th);
15
21
 
16
22
  convertTo(targetFormat: string): string {
17
23
  const formats = this.formats.getFormatNames();
18
24
 
19
- if (this.sourceFormat === DEFAULT_FORMATS.HELM && formats.includes(targetFormat)) { return this.helmToFormat(this.sequence, targetFormat); } else if (formats.includes(this.sourceFormat) && targetFormat === DEFAULT_FORMATS.HELM) { return this.formatToHelm(this.sequence, this.sourceFormat); } else if ([this.sourceFormat, targetFormat].every((el) => formats.includes(el))) {
25
+ if (this.sourceFormat === DEFAULT_FORMATS.HELM && formats.includes(targetFormat)) {
26
+ return this.helmToFormat(this.sequence, targetFormat);
27
+ } else if (formats.includes(this.sourceFormat) && targetFormat === DEFAULT_FORMATS.HELM) {
28
+ return this.formatToHelm(this.sequence, this.sourceFormat);
29
+ } else if ([this.sourceFormat, targetFormat].every((el) => formats.includes(el))) {
20
30
  const helm = this.formatToHelm(this.sequence, this.sourceFormat);
21
31
  return this.helmToFormat(helm, targetFormat);
22
32
  } else {
@@ -48,7 +58,7 @@ export class FormatConverter {
48
58
  const formatRegExp = this.formats.getFormatRegExp(sourceFormat);
49
59
  const phosphateRegExp = this.formats.getPhosphateHelmCodesRegExp(sourceFormat);
50
60
 
51
- let helm = sequence.replace(formatRegExp, (match) => {
61
+ let helm = !sequence ? '' : sequence.replace(formatRegExp, (match) => {
52
62
  const result = formatCodes.includes(match) ? dict[match] + '.' : '?';
53
63
  return result;
54
64
  });