entity-helpers.ts 5.68 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/**
 * See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17 18 19 20
import { Pick2, Pick3 } from 'ts-multipick';

import { Slice } from 'src/shared/types/thoas/slice';
import { PhasedExon, Exon } from 'src/shared/types/thoas/exon';
21
import { Product, ProductType } from 'src/shared/types/thoas/product';
22 23 24 25 26 27
import { ExternalReference } from 'src/shared/types/thoas/externalReference';

import {
  SWISSPROT_SOURCE,
  SPTREMBL_SOURCE
} from 'src/content/app/entity-viewer/gene-view/components/proteins-list/protein-list-constants';
28

29 30 31 32
type GetFeatureCoordinatesParams = {
  slice: Pick2<Slice, 'location', 'start' | 'end'>;
};
export const getFeatureCoordinates = (feature: GetFeatureCoordinatesParams) => {
33 34 35
  const { start, end } = feature.slice.location;
  return { start, end };
};
36

37 38 39 40
type GetRegionNameParams = {
  slice: Pick2<Slice, 'region', 'name'>;
};
export const getRegionName = (feature: GetRegionNameParams) =>
41 42
  feature.slice.region.name;

43 44 45 46
type GetFeatureStrandParams = {
  slice: Pick2<Slice, 'strand', 'code'>;
};
export const getFeatureStrand = (feature: GetFeatureStrandParams) =>
47
  feature.slice.strand.code;
48

49 50 51 52
type GetFeatureLengthParams = {
  slice: Pick2<Slice, 'location', 'length'>;
};
export const getFeatureLength = (feature: GetFeatureLengthParams) => {
53
  return feature.slice.location.length;
54
};
55

56 57 58 59 60 61 62 63 64
export type IsProteinCodingTranscriptParam = {
  product_generating_contexts: Array<{
    product_type: ProductType;
  }>;
};

export const isProteinCodingTranscript = (
  transcript: IsProteinCodingTranscriptParam
) => {
65 66
  const { product_generating_contexts } = transcript;
  const firstProductGeneratingContext = product_generating_contexts[0];
67

68 69 70 71 72
  return (
    firstProductGeneratingContext &&
    firstProductGeneratingContext.product_type === ProductType.PROTEIN
  );
};
73

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
export type GetNumberOfCodingExonsParam = {
  product_generating_contexts: Array<{
    product_type: ProductType;
    phased_exons: Array<
      Pick<PhasedExon, 'start_phase' | 'end_phase'> & {
        exon: {
          stable_id: string;
        };
      }
    >;
  }>;
  spliced_exons: Array<{
    exon: {
      stable_id: string;
    };
  }>;
};

export const getNumberOfCodingExons = (
  transcript: GetNumberOfCodingExonsParam
) => {
95 96
  if (!isProteinCodingTranscript(transcript)) {
    return 0;
97
  }
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
  const { product_generating_contexts, spliced_exons } = transcript;
  const firstProductGeneratingContext = product_generating_contexts[0];

  const { phased_exons } = firstProductGeneratingContext;
  // coding exons will have a phase that is different from -1
  return phased_exons
    .filter(
      ({ start_phase, end_phase }) => start_phase !== -1 || end_phase !== -1
    )
    .filter((phasedExon) => {
      // to exclude the unlikely chance of trans-splicing,
      // check that all phased exons actually belong to this transcript
      return spliced_exons.find(
        (splicedExon) =>
          splicedExon.exon.stable_id === phasedExon.exon.stable_id
      );
    }).length;
115 116
};

117 118 119 120 121
export type GetProductAminoAcidLengthParam = {
  product_generating_contexts: Array<{
    product_type: ProductType.PROTEIN;
    product: {
      length: number;
122
    } | null;
123 124 125 126 127 128
  }>;
};

export const getProductAminoAcidLength = (
  transcript: GetProductAminoAcidLengthParam
) => {
129 130 131 132 133
  if (!isProteinCodingTranscript(transcript)) {
    return 0;
  }
  const { product_generating_contexts } = transcript;
  const firstProductGeneratingContext = product_generating_contexts[0];
134
  const product = firstProductGeneratingContext.product as Product;
135

136
  return product.length;
137
};
Imran Salam's avatar
Imran Salam committed
138

139 140
export type GetSplicedRNALengthParam = {
  spliced_exons: Array<{
141
    exon: Pick3<Exon, 'slice', 'location', 'length'>;
142 143 144 145
  }>;
};

export const getSplicedRNALength = (transcript: GetSplicedRNALengthParam) =>
146 147
  transcript.spliced_exons.reduce((length, { exon }) => {
    return length + exon.slice.location.length;
Imran Salam's avatar
Imran Salam committed
148 149
  }, 0);

150 151 152 153 154
export type GetLongestProteinLengthParam = {
  transcripts: GetProductAminoAcidLengthParam[];
};

export const getLongestProteinLength = (gene: GetLongestProteinLengthParam) => {
155
  const proteinLengths = gene.transcripts.map(getProductAminoAcidLength);
Imran Salam's avatar
Imran Salam committed
156 157
  return Math.max(...proteinLengths);
};
Imran Salam's avatar
Imran Salam committed
158 159 160

export enum ExternalSource {
  INTERPRO = 'Interpro',
161 162
  UNIPROT_TREMBL = 'UniProtKB/TrEMBL',
  UNIPROT_SWISSPROT = 'UniProtKB/Swiss-Prot',
Imran Salam's avatar
Imran Salam committed
163 164 165 166 167
  PDBE = 'PDBe-KB'
}

export const externalSourceLinks = {
  [ExternalSource.INTERPRO]: 'https://www.ebi.ac.uk/interpro/protein/UniProt/',
168 169
  [ExternalSource.UNIPROT_TREMBL]: 'https://www.uniprot.org/uniprot/',
  [ExternalSource.UNIPROT_SWISSPROT]: 'https://www.uniprot.org/uniprot/',
Imran Salam's avatar
Imran Salam committed
170 171
  [ExternalSource.PDBE]: 'https://www.ebi.ac.uk/pdbe/pdbe-kb/proteins/'
};
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

export const getProteinXrefs = <
  T extends Pick2<ExternalReference, 'source', 'id'>
>(transcript: {
  product_generating_contexts: Array<{
    product: {
      external_references: T[];
    };
  }>;
}) => {
  const xrefs =
    transcript.product_generating_contexts[0].product.external_references;
  let proteinXrefs = xrefs.filter(
    (xref) => xref.source.id === SWISSPROT_SOURCE
  );

  if (!proteinXrefs.length) {
    proteinXrefs = xrefs.filter((xref) => xref.source.id === SPTREMBL_SOURCE);
  }

  return proteinXrefs;
};