@datagrok/sequence-translator 1.3.0 → 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.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.md +18 -0
- package/dist/package-test.js +1 -2
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/monomers-sample/README.md +12 -0
- package/files/polytool-rules/rules_example.json +34 -0
- package/files/samples/bulk-translation-axolabs.csv +6 -0
- package/files/tests/README.md +2 -0
- package/files/tests/axolabs1.csv +2 -0
- package/package.json +23 -13
- package/src/apps/common/model/data-loader/const.ts +1 -2
- package/src/apps/common/model/data-loader/json-loader.ts +22 -31
- package/src/apps/common/model/monomer-lib/lib-wrapper.ts +13 -19
- package/src/apps/common/model/oligo-toolkit-package.ts +80 -13
- package/src/apps/common/model/parsing-validation/format-detector.ts +9 -6
- package/src/apps/common/model/parsing-validation/format-handler.ts +16 -13
- package/src/apps/common/model/parsing-validation/sequence-validator.ts +8 -3
- package/src/apps/common/view/combined-app-ui.ts +12 -10
- package/src/apps/common/view/components/colored-input/input-painters.ts +4 -3
- package/src/apps/common/view/monomer-lib-viewer.ts +2 -1
- package/src/apps/common/view/utils.ts +5 -4
- package/src/apps/pattern/model/data-manager.ts +9 -6
- package/src/apps/pattern/model/translator.ts +8 -10
- package/src/apps/pattern/model/utils.ts +0 -1
- package/src/apps/pattern/view/components/strand-editor/strand-controls.ts +0 -1
- package/src/apps/pattern/view/components/translation-examples-block.ts +2 -1
- package/src/apps/pattern/view/svg-utils/utils.ts +6 -4
- package/src/apps/pattern/view/ui.ts +4 -1
- package/src/apps/structure/model/monomer-code-parser.ts +15 -5
- package/src/apps/structure/model/oligo-structure.ts +17 -16
- package/src/apps/structure/model/sequence-to-molfile.ts +2 -1
- package/src/apps/structure/view/ui.ts +19 -11
- package/src/apps/translator/model/conversion-utils.ts +16 -11
- package/src/apps/translator/model/format-converter.ts +15 -5
- package/src/apps/translator/view/ui.ts +32 -20
- package/src/demo/demo-st-ui.ts +2 -2
- package/src/package-test.ts +9 -2
- package/src/package.ts +18 -17
- package/src/plugins/mermade.ts +11 -8
- package/src/polytool/pt-rules.ts +1 -1
- package/src/tests/const.ts +7 -5
- package/src/tests/files-tests.ts +75 -0
- package/src/tests/formats-support.ts +12 -11
- package/src/tests/formats-to-helm.ts +12 -19
- package/src/tests/helm-to-nucleotides.ts +12 -6
- package/src/tests/utils.ts +20 -0
- package/src/types.ts +18 -0
- package/dist/package-test.js.LICENSE.txt +0 -8
- /package/files/{codes-to-symbols.json → monomers-sample/codes-to-symbols.json} +0 -0
- /package/files/{formats-to-helm.json → monomers-sample/formats-to-helm.json} +0 -0
- /package/files/{linkers.json → monomers-sample/linkers.json} +0 -0
- /package/files/{monomer-lib.json → monomers-sample/monomer-lib.json} +0 -0
- /package/files/{pattern-app-data.json → monomers-sample/pattern-app-data.json} +0 -0
|
@@ -2,6 +2,7 @@ import {OligoPatternUI} from '../../pattern/view/ui';
|
|
|
2
2
|
import {OligoStructureUI} from '../../structure/view/ui';
|
|
3
3
|
import {OligoTranslatorUI} from '../../translator/view/ui';
|
|
4
4
|
import {IsolatedAppUIBase} from './isolated-app-ui';
|
|
5
|
+
import {ITranslationHelper} from '../../../types';
|
|
5
6
|
import {APP_NAME} from './const';
|
|
6
7
|
|
|
7
8
|
/** For plugins from external packages */
|
|
@@ -15,14 +16,14 @@ export class ExternalPluginUI extends IsolatedAppUIBase {
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
export function getSpecifiedAppUI(appName: string): IsolatedAppUIBase {
|
|
19
|
+
export function getSpecifiedAppUI(appName: string, th: ITranslationHelper): IsolatedAppUIBase {
|
|
19
20
|
switch (appName) {
|
|
20
21
|
case APP_NAME.TRANSLATOR:
|
|
21
|
-
return new OligoTranslatorUI();
|
|
22
|
+
return new OligoTranslatorUI(th);
|
|
22
23
|
case APP_NAME.PATTERN:
|
|
23
|
-
return new OligoPatternUI();
|
|
24
|
+
return new OligoPatternUI(th);
|
|
24
25
|
case APP_NAME.STRUCTURE:
|
|
25
|
-
return new OligoStructureUI();
|
|
26
|
+
return new OligoStructureUI(th);
|
|
26
27
|
default:
|
|
27
28
|
throw new Error(`Unknown app name: ${appName}`);
|
|
28
29
|
}
|
|
@@ -11,8 +11,8 @@ import {
|
|
|
11
11
|
|
|
12
12
|
import objectHash from 'object-hash';
|
|
13
13
|
import {EventBus} from './event-bus';
|
|
14
|
-
import {
|
|
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
|
|
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(
|
|
226
|
-
const nucleotideBases: string[] = Object.keys(
|
|
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(
|
|
56
|
-
const 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
|
|
|
@@ -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(
|
|
33
|
+
const format = Object.keys(_package.jsonData.patternAppData)[0];
|
|
32
34
|
if (!format)
|
|
33
|
-
throw new Error(
|
|
35
|
+
throw new Error(`No format found in '${PATTERN_APP_DATA_FILENAME}'`);
|
|
34
36
|
|
|
35
|
-
const styleMap =
|
|
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
|
-
|
|
9
|
-
import {
|
|
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
|
|
89
|
+
return _package.jsonData.monomersWithPhosphate['left'].includes(monomerSymbol);
|
|
80
90
|
}
|
|
81
91
|
|
|
82
92
|
function monomerHasRightPhosphateLinker(monomerSymbol: string): boolean {
|
|
83
|
-
return
|
|
93
|
+
return _package.jsonData.monomersWithPhosphate['right'].includes(monomerSymbol);
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
function monomerIsPhosphateLinker(monomerSymbol: string): boolean {
|
|
87
|
-
return
|
|
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 {
|
|
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 = (
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
9
|
-
|
|
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 =
|
|
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,
|
|
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(
|
|
54
|
-
|
|
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,
|
|
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(
|
|
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(
|
|
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)) {
|
|
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
|
});
|