diff --git a/packages/ketcher-core/src/domain/constants/monomers.ts b/packages/ketcher-core/src/domain/constants/monomers.ts index 425c984327..ab39af2321 100644 --- a/packages/ketcher-core/src/domain/constants/monomers.ts +++ b/packages/ketcher-core/src/domain/constants/monomers.ts @@ -22,6 +22,20 @@ export enum RnaDnaNaturalAnaloguesEnum { URACIL = 'U', } +export enum StandardAmbiguousRnaBase { + N = 'N', + B = 'B', + V = 'V', + D = 'D', + H = 'H', + K = 'K', + M = 'M', + W = 'W', + Y = 'Y', + R = 'R', + S = 'S', +} + export const rnaDnaNaturalAnalogues = [ RnaDnaNaturalAnaloguesEnum.ADENINE, RnaDnaNaturalAnaloguesEnum.THYMINE, diff --git a/packages/ketcher-core/src/domain/entities/DrawingEntitiesManager.ts b/packages/ketcher-core/src/domain/entities/DrawingEntitiesManager.ts index 7094802f10..3fdf0bd7de 100644 --- a/packages/ketcher-core/src/domain/entities/DrawingEntitiesManager.ts +++ b/packages/ketcher-core/src/domain/entities/DrawingEntitiesManager.ts @@ -89,6 +89,7 @@ import { MACROMOLECULES_BOND_TYPES } from 'application/editor/tools/Bond'; import { RNA_DNA_NON_MODIFIED_PART, RnaDnaNaturalAnaloguesEnum, + StandardAmbiguousRnaBase, } from 'domain/constants/monomers'; import { isNumber } from 'lodash'; import { Chain } from 'domain/entities/monomer-chains/Chain'; @@ -2621,6 +2622,17 @@ export class DrawingEntitiesManager { [RnaDnaNaturalAnaloguesEnum.GUANINE]: RnaDnaNaturalAnaloguesEnum.CYTOSINE, [RnaDnaNaturalAnaloguesEnum.THYMINE]: RnaDnaNaturalAnaloguesEnum.ADENINE, [RnaDnaNaturalAnaloguesEnum.URACIL]: RnaDnaNaturalAnaloguesEnum.ADENINE, + [StandardAmbiguousRnaBase.N]: StandardAmbiguousRnaBase.N, + [StandardAmbiguousRnaBase.B]: StandardAmbiguousRnaBase.V, + [StandardAmbiguousRnaBase.D]: StandardAmbiguousRnaBase.H, + [StandardAmbiguousRnaBase.H]: StandardAmbiguousRnaBase.D, + [StandardAmbiguousRnaBase.K]: StandardAmbiguousRnaBase.M, + [StandardAmbiguousRnaBase.W]: StandardAmbiguousRnaBase.W, + [StandardAmbiguousRnaBase.Y]: StandardAmbiguousRnaBase.R, + [StandardAmbiguousRnaBase.M]: StandardAmbiguousRnaBase.K, + [StandardAmbiguousRnaBase.R]: StandardAmbiguousRnaBase.Y, + [StandardAmbiguousRnaBase.S]: StandardAmbiguousRnaBase.S, + [StandardAmbiguousRnaBase.V]: StandardAmbiguousRnaBase.B, }; } @@ -2683,7 +2695,7 @@ export class DrawingEntitiesManager { complimentaryChainWithData.complimentaryChain.monomers.some( (monomer) => { return ( - (monomer instanceof RNABase && + (isRnaBaseOrAmbiguousRnaBase(monomer) && Boolean(getSugarFromRnaBase(monomer)) && monomer.hydrogenBonds.length > 0) || monomer.hydrogenBonds.some((hydrogenBond) => { @@ -2691,7 +2703,7 @@ export class DrawingEntitiesManager { hydrogenBond.getAnotherMonomer(monomer); return ( - anotherMonomer instanceof RNABase && + isRnaBaseOrAmbiguousRnaBase(anotherMonomer) && Boolean(getSugarFromRnaBase(anotherMonomer)) ); }) @@ -2782,6 +2794,14 @@ export class DrawingEntitiesManager { return command; } + private getAntisenseBaseLabel(rnaBase: RNABase | AmbiguousMonomer) { + return this.antisenseChainBasesMap[ + rnaBase instanceof AmbiguousMonomer + ? rnaBase.monomerItem.label + : rnaBase.monomerItem.props.MonomerNaturalAnalogCode + ]; + } + public createAntisenseChain() { const editor = CoreEditor.provideEditorInstance(); const command = new Command(); @@ -2795,6 +2815,7 @@ export class DrawingEntitiesManager { subChain.nodes.some( (node) => (node instanceof Nucleotide || node instanceof Nucleoside) && + Boolean(this.getAntisenseBaseLabel(node.rnaBase)) && node.monomer.selected, ), ); @@ -2814,14 +2835,18 @@ export class DrawingEntitiesManager { } if (node instanceof Nucleotide || node instanceof Nucleoside) { + const antisenseBaseLabel = this.getAntisenseBaseLabel(node.rnaBase); + + if (!antisenseBaseLabel) { + return; + } + const { modelChanges: addNucleotideCommand, node: addedNode } = ( node instanceof Nucleotide && node.phosphate.selected ? Nucleotide : Nucleoside ).createOnCanvas( - this.antisenseChainBasesMap[ - node.rnaBase.monomerItem.props.MonomerNaturalAnalogCode - ], + antisenseBaseLabel, node.monomer.position.add(new Vec2(0, 3)), RNA_DNA_NON_MODIFIED_PART.SUGAR_RNA, ); diff --git a/packages/ketcher-core/src/domain/entities/Nucleoside.ts b/packages/ketcher-core/src/domain/entities/Nucleoside.ts index 7411edd0d9..388ba8733e 100644 --- a/packages/ketcher-core/src/domain/entities/Nucleoside.ts +++ b/packages/ketcher-core/src/domain/entities/Nucleoside.ts @@ -18,6 +18,7 @@ import { AmbiguousMonomer } from 'domain/entities/AmbiguousMonomer'; import { RNA_MONOMER_DISTANCE } from 'application/editor/tools/RnaPreset'; import { SugarRenderer } from 'application/render'; import { RNA_DNA_NON_MODIFIED_PART } from 'domain/constants/monomers'; +import { KetMonomerClass } from 'application/formatters'; export class Nucleoside { constructor( @@ -46,8 +47,16 @@ export class Nucleoside { isAntisense = false, ) { const editor = CoreEditor.provideEditorInstance(); - const rnaBaseLibraryItem = getRnaPartLibraryItem(editor, rnaBaseName); - const sugarLibraryItem = getRnaPartLibraryItem(editor, sugarName); + const rnaBaseLibraryItem = getRnaPartLibraryItem( + editor, + rnaBaseName, + KetMonomerClass.Base, + ); + const sugarLibraryItem = getRnaPartLibraryItem( + editor, + sugarName, + KetMonomerClass.Sugar, + ); assert(sugarLibraryItem); assert(rnaBaseLibraryItem); diff --git a/packages/ketcher-core/src/domain/entities/Nucleotide.ts b/packages/ketcher-core/src/domain/entities/Nucleotide.ts index 5689afdae2..22c044ac82 100644 --- a/packages/ketcher-core/src/domain/entities/Nucleotide.ts +++ b/packages/ketcher-core/src/domain/entities/Nucleotide.ts @@ -18,6 +18,7 @@ import { AmbiguousMonomer } from 'domain/entities/AmbiguousMonomer'; import { RNA_MONOMER_DISTANCE } from 'application/editor/tools/RnaPreset'; import { SugarRenderer } from 'application/render'; import { SNAKE_LAYOUT_CELL_WIDTH } from 'domain/entities/DrawingEntitiesManager'; +import { KetMonomerClass } from 'application/formatters'; export class Nucleotide { constructor( @@ -53,12 +54,20 @@ export class Nucleotide { sugarName: RNA_DNA_NON_MODIFIED_PART = RNA_DNA_NON_MODIFIED_PART.SUGAR_RNA, ) { const editor = CoreEditor.provideEditorInstance(); - const rnaBaseLibraryItem = getRnaPartLibraryItem(editor, rnaBaseName); + const rnaBaseLibraryItem = getRnaPartLibraryItem( + editor, + rnaBaseName, + KetMonomerClass.Base, + ); const phosphateLibraryItem = getRnaPartLibraryItem( editor, RNA_DNA_NON_MODIFIED_PART.PHOSPHATE, ); - const sugarLibraryItem = getRnaPartLibraryItem(editor, sugarName); + const sugarLibraryItem = getRnaPartLibraryItem( + editor, + sugarName, + KetMonomerClass.Sugar, + ); assert(sugarLibraryItem); assert(rnaBaseLibraryItem); diff --git a/packages/ketcher-core/src/domain/helpers/rna.ts b/packages/ketcher-core/src/domain/helpers/rna.ts index edf727c67b..76b5e46ac4 100644 --- a/packages/ketcher-core/src/domain/helpers/rna.ts +++ b/packages/ketcher-core/src/domain/helpers/rna.ts @@ -1,13 +1,23 @@ import { CoreEditor } from 'application/editor/internal'; -import { SequenceType } from 'domain/entities'; +import { AmbiguousMonomer, SequenceType } from 'domain/entities'; import { RNA_DNA_NON_MODIFIED_PART } from 'domain/constants/monomers'; import { MONOMER_CONST } from 'application/editor'; +import { isAmbiguousMonomerLibraryItem } from 'domain/helpers/monomers'; +import { KetMonomerClass } from 'application/formatters'; -export function getRnaPartLibraryItem(editor: CoreEditor, rnaBaseName: string) { - return editor.monomersLibrary.find( - (libraryItem) => - libraryItem.props.MonomerType === MONOMER_CONST.RNA && - libraryItem.props.MonomerName === rnaBaseName, +export function getRnaPartLibraryItem( + editor: CoreEditor, + rnaBaseName: string, + monomerClass?: KetMonomerClass, +) { + return editor.monomersLibrary.find((libraryItem) => + isAmbiguousMonomerLibraryItem(libraryItem) + ? (!monomerClass || + AmbiguousMonomer.getMonomerClass(libraryItem.monomers) === + monomerClass) && + libraryItem.label === rnaBaseName + : (!monomerClass || libraryItem.props.MonomerClass === monomerClass) && + libraryItem.props.MonomerName === rnaBaseName, ); }