From ae04d13833b77c77c86efe4e3bbfbee3dfa11543 Mon Sep 17 00:00:00 2001 From: Mukesh-ghildiyal Date: Mon, 24 Mar 2025 19:54:46 +0530 Subject: [PATCH] Oncoprinter enable submitting of data in same format as MutationMapper --- package.json | 1 + .../OncoprinterGeneticUtils.spec.ts | 214 +++++---- .../oncoprinter/OncoprinterGeneticUtils.ts | 425 ++++++++++++------ .../tools/oncoprinter/OncoprinterStore.ts | 67 ++- yarn.lock | 36 +- 5 files changed, 452 insertions(+), 291 deletions(-) diff --git a/package.json b/package.json index 4e0cd8e3e85..f28151853cd 100644 --- a/package.json +++ b/package.json @@ -356,6 +356,7 @@ "es-abstract": "1.18.0-next.2", "expect": "^1.20.2", "expect-jsx": "5.0.0", + "glob": "7.2.0", "http-server": "0.11.1", "identity-obj-proxy": "^3.0.0", "jasmine-core": "^3.9.0", diff --git a/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.spec.ts b/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.spec.ts index 7f4458a619d..5de42c5e976 100644 --- a/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.spec.ts +++ b/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.spec.ts @@ -3,111 +3,107 @@ import { parseGeneticInput } from './OncoprinterGeneticUtils'; describe('OncoprinterGeneticUtils', () => { describe('parseGeneticInput', () => { - it('skips header line', () => { - assert.deepEqual( - parseGeneticInput( - 'sample gene alteration type\nsample_id TP53 FUSION FUSION\n' - ), - { - parseSuccess: true, - result: [ - { - sampleId: 'sample_id', - hugoGeneSymbol: 'TP53', - alteration: 'structuralVariant', - eventInfo: 'FUSION', - trackName: undefined, - }, - ], - error: undefined, - } + it('skips header line', async () => { + const parsed = await parseGeneticInput( + 'sample gene alteration type\nsample_id TP53 FUSION FUSION\n' ); + assert.deepEqual(parsed, { + parseSuccess: true, + result: [ + { + sampleId: 'sample_id', + hugoGeneSymbol: 'TP53', + alteration: 'structuralVariant', + eventInfo: 'FUSION', + trackName: undefined, + }, + ], + error: undefined, + }); }); - it('parses fusion command correctly', () => { - assert.deepEqual( - parseGeneticInput('sample_id TP53 FUSION FUSION'), - { - parseSuccess: true, - result: [ - { - sampleId: 'sample_id', - hugoGeneSymbol: 'TP53', - alteration: 'structuralVariant', - eventInfo: 'FUSION', - trackName: undefined, - }, - ], - error: undefined, - } + it('parses fusion command correctly', async () => { + const parsed = await parseGeneticInput( + 'sample_id TP53 FUSION FUSION' ); + assert.deepEqual(parsed, { + parseSuccess: true, + result: [ + { + sampleId: 'sample_id', + hugoGeneSymbol: 'TP53', + alteration: 'structuralVariant', + eventInfo: 'FUSION', + trackName: undefined, + }, + ], + error: undefined, + }); }); - it('throws an error if fusion is not specified correctly', () => { + it('throws an error if fusion is not specified correctly', async () => { try { - const parsed = parseGeneticInput( + const parsed = await parseGeneticInput( 'sample_id TP53 FUSION apsoidjfpaos' ); assert(false); } catch (e) {} }); - it('parses germline mutation correctly', () => { - assert.deepEqual( - parseGeneticInput('sampleid BRCA1 Q1538A MISSENSE_GERMLINE'), - { - parseSuccess: true, - result: [ - { - sampleId: 'sampleid', - hugoGeneSymbol: 'BRCA1', - alteration: 'missense', - proteinChange: 'Q1538A', - isGermline: true, - trackName: undefined, - }, - ], - error: undefined, - } + it('parses germline mutation correctly', async () => { + const parsed = await parseGeneticInput( + 'sampleid BRCA1 Q1538A MISSENSE_GERMLINE' ); + assert.deepEqual(parsed, { + parseSuccess: true, + result: [ + { + sampleId: 'sampleid', + hugoGeneSymbol: 'BRCA1', + alteration: 'missense', + proteinChange: 'Q1538A', + isGermline: true, + trackName: undefined, + }, + ], + error: undefined, + }); }); - it('parses driver mutation correctly', () => { - assert.deepEqual( - parseGeneticInput('sampleid BRCA1 Q1538A TRUNC_DRIVER'), - { - parseSuccess: true, - result: [ - { - sampleId: 'sampleid', - hugoGeneSymbol: 'BRCA1', - alteration: 'trunc', - proteinChange: 'Q1538A', - isCustomDriver: true, - trackName: undefined, - }, - ], - error: undefined, - } + it('parses driver mutation correctly', async () => { + const parsed = await parseGeneticInput( + 'sampleid BRCA1 Q1538A TRUNC_DRIVER' ); + assert.deepEqual(parsed, { + parseSuccess: true, + result: [ + { + sampleId: 'sampleid', + hugoGeneSymbol: 'BRCA1', + alteration: 'trunc', + proteinChange: 'Q1538A', + isCustomDriver: true, + trackName: undefined, + }, + ], + error: undefined, + }); }); - it('parses germline & driver mutation correctly', () => { - assert.deepEqual( - parseGeneticInput( - 'sampleid BRCA1 Q1538A MISSENSE_GERMLINE_DRIVER' - ), - { - parseSuccess: true, - result: [ - { - sampleId: 'sampleid', - hugoGeneSymbol: 'BRCA1', - alteration: 'missense', - proteinChange: 'Q1538A', - isGermline: true, - isCustomDriver: true, - trackName: undefined, - }, - ], - error: undefined, - } + it('parses germline & driver mutation correctly', async () => { + const parsed = await parseGeneticInput( + 'sampleid BRCA1 Q1538A MISSENSE_GERMLINE_DRIVER' ); + assert.deepEqual(parsed, { + parseSuccess: true, + result: [ + { + sampleId: 'sampleid', + hugoGeneSymbol: 'BRCA1', + alteration: 'missense', + proteinChange: 'Q1538A', + isGermline: true, + isCustomDriver: true, + trackName: undefined, + }, + ], + error: undefined, + }); }); it('throws an error for an invalid mutation modifier', () => { try { @@ -117,27 +113,25 @@ describe('OncoprinterGeneticUtils', () => { assert(false); } catch (e) {} }); - it('parses a line with a given track name correctly', () => { - assert.deepEqual( - parseGeneticInput( - 'sampleid BRCA1 Q1538A MISSENSE_GERMLINE_DRIVER testTrackName' - ), - { - parseSuccess: true, - result: [ - { - sampleId: 'sampleid', - hugoGeneSymbol: 'BRCA1', - alteration: 'missense', - proteinChange: 'Q1538A', - isGermline: true, - isCustomDriver: true, - trackName: 'testTrackName', - }, - ], - error: undefined, - } + it('parses a line with a given track name correctly', async () => { + const parsed = await parseGeneticInput( + 'sampleid BRCA1 Q1538A MISSENSE_GERMLINE_DRIVER testTrackName' ); + assert.deepEqual(parsed, { + parseSuccess: true, + result: [ + { + sampleId: 'sampleid', + hugoGeneSymbol: 'BRCA1', + alteration: 'missense', + proteinChange: 'Q1538A', + isGermline: true, + isCustomDriver: true, + trackName: 'testTrackName', + }, + ], + error: undefined, + }); }); }); }); diff --git a/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.ts b/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.ts index b500e44edcb..6eed77768ba 100644 --- a/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.ts +++ b/src/pages/staticPages/tools/oncoprinter/OncoprinterGeneticUtils.ts @@ -1,4 +1,4 @@ -import { observable } from 'mobx'; +import { observable, reaction, when } from 'mobx'; import { getServerConfig } from 'config/config'; import { default as OncoprinterStore } from './OncoprinterStore'; import _ from 'lodash'; @@ -26,6 +26,7 @@ import { getProteinPositionFromProteinChange, EvidenceType, IOncoKbData, + annotateMutations, } from 'cbioportal-utils'; import { generateQueryVariantId, @@ -43,14 +44,25 @@ import { queryOncoKbData, } from '../../../../shared/lib/StoreUtils'; import { default as oncokbClient } from '../../../../shared/api/oncokbClientInstance'; -import { MobxPromise } from 'cbioportal-frontend-commons'; +import { MobxPromise, remoteData } from 'cbioportal-frontend-commons'; import { mutationCountByPositionKey } from '../../../resultsView/mutationCountHelpers'; import { getAlterationString } from '../../../../shared/lib/CopyNumberUtils'; import { GERMLINE_REGEXP } from '../../../../shared/lib/MutationUtils'; import { parseOQLQuery } from '../../../../shared/lib/oql/oqlfilter'; import { Alteration, MUTCommand } from '../../../../shared/lib/oql/oql-parser'; -import { MUTATION_STATUS_GERMLINE } from '../../../../shared/constants'; +import { + MUTATION_STATUS_GERMLINE, + GENOME_NEXUS_ARG_FIELD_ENUM, +} from '../../../../shared/constants'; import { OncoprintModel } from 'oncoprintjs'; +import { + parseInput, + mutationInputToMutation, +} from '../../../../shared/lib/MutationInputParser'; +import { fetchVariantAnnotationsIndexedByGenomicLocation } from '../../../../shared/lib/StoreUtils'; +import { VariantAnnotation } from 'genome-nexus-ts-api-client'; +import { normalizeMutations } from 'shared/components/mutationMapper/MutationMapperUtils'; +import { rawListeners } from 'superagent'; export type OncoprinterGeneticTrackDatum = Pick< GeneticTrackDatum, @@ -796,163 +808,286 @@ export function annotateGeneticTrackData( }); } -export function parseGeneticInput( +export async function fetchGeneticMutationAnnotation( + input: string[], + sampleId: string +): Promise> { + const mutationData = parseInput(input.join('\n')); + let mutationType: string | undefined; + let proteinChange: string | undefined; + let hugoGeneSymbol: string | undefined; + const trackName = undefined; + if (mutationData.length === 1) { + try { + const rawMutations = mutationInputToMutation( + mutationData + ) as Mutation[]; + const variantAnnotations = remoteData<{ + [genomicLocation: string]: VariantAnnotation; + }>({ + invoke: async () => + await fetchVariantAnnotationsIndexedByGenomicLocation( + rawMutations, + [GENOME_NEXUS_ARG_FIELD_ENUM.ANNOTATION_SUMMARY].filter( + f => f + ) + ), + onError: (error: Error) => { + console.error(error); + }, + }); + await when(() => variantAnnotations.result !== undefined); + const result = variantAnnotations.result; + if (result) { + const annotatedMutation = annotateMutations( + normalizeMutations(rawMutations), + result + ); + if (annotatedMutation.length === 1) { + const gene = annotatedMutation[0]['gene']; + const annotatedMutationType = annotatedMutation[0][ + 'mutationType' + ] + ?.replace(/[^a-zA-Z0-9]/g, '') + .toLowerCase(); + const validMutationTypes = [ + 'missense', + 'inframe', + 'promoter', + 'trunc', + 'splice', + ]; + if ( + annotatedMutationType && + validMutationTypes.some(type => + annotatedMutationType.includes(type) + ) + ) { + mutationType = + validMutationTypes.find(type => + annotatedMutationType.includes(type) + ) || 'other'; + } else { + mutationType = 'other'; + } + proteinChange = annotatedMutation[0]['proteinChange']; + hugoGeneSymbol = gene ? gene['hugoGeneSymbol'] : ''; + return { + sampleId, + hugoGeneSymbol, + trackName, + alteration: mutationType as OncoprintMutationType, + proteinChange, + }; + } + } + } catch (error) { + console.error('Error fetching annotation:', error); + } + } + + return {}; +} +export async function parseGeneticInput( input: string -): +): Promise< | { parseSuccess: true; result: OncoprinterGeneticInputLine[]; error: undefined; } - | { parseSuccess: false; result: undefined; error: string } { + | { parseSuccess: false; result: undefined; error: string } +> { + const separator = input.indexOf('\t') > 0 ? /\t/ : /\s+/; const lines = input .trim() .split('\n') - .map(line => line.trim().split(/\s+/)); + .map(line => line.trim().split(separator)); try { - const result = lines.map((line, lineIndex) => { - if ( - lineIndex === 0 && - _.isEqual(lines[0].map(s => s.toLowerCase()).slice(0, 4), [ - 'sample', - 'gene', - 'alteration', - 'type', - ]) - ) { - return null; // skip header line - } - const errorPrefix = `Genetic data input error on line ${lineIndex + - 1}: \n${line.join('\t')}\n\n`; - if (line.length === 1) { - // Type 1 line - return { sampleId: line[0] }; - } else if (line.length === 4 || line.length === 5) { - // Type 2 line - const sampleId = line[0]; - const hugoGeneSymbol = line[1]; - const alteration = line[2]; - const lcAlteration = alteration.toLowerCase(); - const type = line[3]; - const lcType = type.toLowerCase(); - const trackName = line.length === 5 ? line[4] : undefined; - let ret: Partial = { - sampleId, - hugoGeneSymbol, - trackName, - }; - - switch (lcType) { - case 'cna': - if ( - ['amp', 'gain', 'hetloss', 'homdel'].indexOf( - lcAlteration - ) === -1 - ) { - throw new Error( - `${errorPrefix}Alteration "${alteration}" is not valid - it must be "AMP", "GAIN" ,"HETLOSS", or "HOMDEL" since Type is "CNA"` - ); - } - ret.alteration = lcAlteration as - | 'amp' - | 'gain' - | 'hetloss' - | 'homdel'; - break; - case 'exp': - if (lcAlteration === 'high') { - ret.alteration = 'mrnaHigh'; - } else if (lcAlteration === 'low') { - ret.alteration = 'mrnaLow'; - } else { - throw new Error( - `${errorPrefix}Alteration "${alteration}" is not valid - it must be "HIGH" or "LOW" if Type is "EXP"` - ); - } - break; - case 'prot': - if (lcAlteration === 'high') { - ret.alteration = 'protHigh'; - } else if (lcAlteration === 'low') { - ret.alteration = 'protLow'; - } else { - throw new Error( - `${errorPrefix}Alteration "${alteration}" is not valid - it must be "HIGH" or "LOW" if Type is "PROT"` - ); - } - break; - case 'fusion': - if (lcType !== 'fusion') { - throw new Error( - `${errorPrefix}Type "${type}" is not valid - it must be "FUSION" if Alteration is "FUSION"` - ); - } else { - ret.alteration = 'structuralVariant'; - ret.eventInfo = alteration; - } - break; - default: - // everything else is a mutation - // use OQL parsing for handling mutation modifiers - let parsedMutation: MUTCommand; - try { - parsedMutation = (parseOQLQuery( - `GENE: ${lcType}` - )[0].alterations as Alteration[])[0] as MUTCommand< - any - >; - } catch (e) { - throw new Error( - `${errorPrefix}Mutation type ${type} is not valid.` - ); - } - - for (const modifier of parsedMutation.modifiers) { - switch (modifier.type) { - case 'GERMLINE': - ret.isGermline = true; - break; - case 'DRIVER': - ret.isCustomDriver = true; - break; - default: - throw new Error( - `${errorPrefix}Only allowed mutation modifiers are GERMLINE and DRIVER` - ); + const result = await Promise.all( + lines.map(async (line, lineIndex) => { + if ( + lineIndex === 0 && + _.isEqual(lines[0].map(s => s.toLowerCase()).slice(0, 4), [ + 'sample', + 'gene', + 'alteration', + 'type', + ]) + ) { + return null; // skip header line + } else if ( + lineIndex === 0 && + _.isEqual(lines[0].map(s => s.toLowerCase()).slice(0, 7), [ + 'sample_id', + 'cancer_type', + 'chromosome', + 'start_position', + 'end_position', + 'reference_allele', + 'variant_allele', + ]) + ) { + return null; // skip header line + } + const errorPrefix = `Genetic data input error on line ${lineIndex + + 1}: \n${line.join('\t')}\n\n`; + if (line.length === 1) { + // Type 1 line + return { sampleId: line[0] }; + } else if (line.length === 4 || line.length === 5) { + // Type 2 line + const sampleId = line[0]; + const hugoGeneSymbol = line[1]; + const alteration = line[2]; + const lcAlteration = alteration.toLowerCase(); + const type = line[3]; + const lcType = type.toLowerCase(); + const trackName = line.length === 5 ? line[4] : undefined; + + let ret: Partial = { + sampleId, + hugoGeneSymbol, + trackName, + }; + + switch (lcType) { + case 'cna': + if ( + ['amp', 'gain', 'hetloss', 'homdel'].indexOf( + lcAlteration + ) === -1 + ) { + throw new Error( + `${errorPrefix}Alteration "${alteration}" is not valid - it must be "AMP", "GAIN" ,"HETLOSS", or "HOMDEL" since Type is "CNA"` + ); + } + ret.alteration = lcAlteration as + | 'amp' + | 'gain' + | 'hetloss' + | 'homdel'; + break; + case 'exp': + if (lcAlteration === 'high') { + ret.alteration = 'mrnaHigh'; + } else if (lcAlteration === 'low') { + ret.alteration = 'mrnaLow'; + } else { + throw new Error( + `${errorPrefix}Alteration "${alteration}" is not valid - it must be "HIGH" or "LOW" if Type is "EXP"` + ); + } + break; + case 'prot': + if (lcAlteration === 'high') { + ret.alteration = 'protHigh'; + } else if (lcAlteration === 'low') { + ret.alteration = 'protLow'; + } else { + throw new Error( + `${errorPrefix}Alteration "${alteration}" is not valid - it must be "HIGH" or "LOW" if Type is "PROT"` + ); + } + break; + case 'fusion': + if (lcType !== 'fusion') { + throw new Error( + `${errorPrefix}Type "${type}" is not valid - it must be "FUSION" if Alteration is "FUSION"` + ); + } else { + ret.alteration = 'structuralVariant'; + ret.eventInfo = alteration; + } + break; + default: + // everything else is a mutation + // use OQL parsing for handling mutation modifiers + let parsedMutation: MUTCommand; + try { + parsedMutation = (parseOQLQuery( + `GENE: ${lcType}` + )[0] + .alterations as Alteration[])[0] as MUTCommand< + any + >; + } catch (e) { + throw new Error( + `${errorPrefix}Mutation type ${type} is not valid.` + ); + } + for (const modifier of parsedMutation.modifiers) { + switch (modifier.type) { + case 'GERMLINE': + ret.isGermline = true; + break; + case 'DRIVER': + ret.isCustomDriver = true; + break; + default: + throw new Error( + `${errorPrefix}Only allowed mutation modifiers are GERMLINE and DRIVER` + ); + } } - } - - const lcMutationType = parsedMutation.constr_val!.toLowerCase(); - - if ( - [ - 'missense', - 'inframe', - 'promoter', - 'trunc', - 'splice', - 'other', - ].indexOf(lcMutationType) === -1 - ) { - throw new Error( - `${errorPrefix}Type "${type}" is not valid - it must be "MISSENSE", "INFRAME", "TRUNC", "SPLICE", "PROMOTER", or "OTHER" for a mutation alteration.` - ); - } - ret.alteration = lcMutationType as OncoprintMutationType; - ret.proteinChange = alteration; - break; + const lcMutationType = parsedMutation.constr_val!.toLowerCase(); + + if ( + [ + 'missense', + 'inframe', + 'promoter', + 'trunc', + 'splice', + 'other', + ].indexOf(lcMutationType) === -1 + ) { + throw new Error( + `${errorPrefix}Type "${type}" is not valid - it must be "MISSENSE", "INFRAME", "TRUNC", "SPLICE", "PROMOTER", or "OTHER" for a mutation alteration.` + ); + } + ret.alteration = lcMutationType as OncoprintMutationType; + ret.proteinChange = alteration; + + break; + } + return ret as OncoprinterGeneticInputLineType2; + } else if ( + // Type 3 line + line.length === 7 && + line.slice(2, 5).every(it => /^\d+$/.test(it)) && + line.slice(5, 7).every(it => /^[A-Z\- ]+$/.test(it)) + ) { + const sampleId = line[0]; + const cancerType = line[1]; + const mutationInput = [ + 'Sample_ID Cancer_Type Chromosome Start_Position End_Position Reference_Allele Variant_Allele', + ]; + mutationInput.push( + sampleId + + '\t' + + cancerType + + '\t' + + line.slice(2, 7).join('\t') + ); + return await fetchGeneticMutationAnnotation( + mutationInput, + sampleId + ); + } else { + throw new Error( + `${errorPrefix}input lines must have either 1 or 4 columns.` + ); } - return ret as OncoprinterGeneticInputLineType2; - } else { - throw new Error( - `${errorPrefix}input lines must have either 1 or 4 columns.` - ); - } - }); + }) + ); + const returnResult = result.filter( + x => x !== null + ) as OncoprinterGeneticInputLine[]; return { parseSuccess: true, - result: result.filter(x => !!x) as OncoprinterGeneticInputLine[], + result: returnResult, error: undefined, }; } catch (e) { diff --git a/src/pages/staticPages/tools/oncoprinter/OncoprinterStore.ts b/src/pages/staticPages/tools/oncoprinter/OncoprinterStore.ts index e5215251b53..6f889c3b70d 100644 --- a/src/pages/staticPages/tools/oncoprinter/OncoprinterStore.ts +++ b/src/pages/staticPages/tools/oncoprinter/OncoprinterStore.ts @@ -1,5 +1,12 @@ import { DriverAnnotationSettings } from '../../../../shared/alterationFiltering/AnnotationFilteringSettings'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { + action, + computed, + makeObservable, + observable, + reaction, + runInAction, +} from 'mobx'; import { getServerConfig } from 'config/config'; import { annotateGeneticTrackData, @@ -82,10 +89,23 @@ export default class OncoprinterStore { }; } = {}; + @observable parsedGeneticInputLinesResult: { + error: any; + result: any[] | null; + } = { error: null, result: [] }; + @observable isParsingGeneticInputLines: boolean = false; + constructor() { makeObservable(this); this.initialize(); + reaction( + () => this._geneticDataInput, + () => { + this._getParsedGeneticInput(); + } + ); + const clinicalTracksColorConfig = localStorage.getItem( ONCOPRINTER_COLOR_CONFIG ); @@ -221,25 +241,48 @@ export default class OncoprinterStore { if (this._studyIds) return JSON.parse(this._studyIds); } - @computed get parsedGeneticInputLines() { - if (!this._geneticDataInput) { + @computed + get parsedGeneticInputLines() { + if (!this._geneticDataInput || this.isParsingGeneticInputLines) { return { error: null, result: [], }; } + return this.parsedGeneticInputLinesResult; + } + @action + async _getParsedGeneticInput() { + if (this.isParsingGeneticInputLines) return; - const parsed = parseGeneticInput(this._geneticDataInput); - if (!parsed.parseSuccess) { - return { - error: parsed.error, + runInAction(() => { + this.isParsingGeneticInputLines = true; + }); + + try { + const parsed = await parseGeneticInput( + this._geneticDataInput ?? '' + ); + if (!parsed.parseSuccess) { + this.parsedGeneticInputLinesResult = { + error: parsed.error, + result: null, + }; + } else { + this.parsedGeneticInputLinesResult = { + error: null, + result: parsed.result, + }; + } + } catch (error) { + this.parsedGeneticInputLinesResult = { + error: error, result: null, }; - } else { - return { - error: null, - result: parsed.result, - }; + } finally { + runInAction(() => { + this.isParsingGeneticInputLines = false; + }); } } diff --git a/yarn.lock b/yarn.lock index 58b143d0a42..81e4a27726b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1152,11 +1152,6 @@ resolved "https://registry.yarnpkg.com/@datadog/browser-core/-/browser-core-5.28.0.tgz#bd4677eeb08fcd3c98eba0600e34a2d8bc347ee2" integrity sha512-aLYXaTkbZQIpyx+mxRGnj3Es6njoac8VhBaGr27KPuvwb/xJlBgAt5K/xdGxAPO135mdfq5evmguWuMpffE4Og== -"@datadog/browser-core@5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@datadog/browser-core/-/browser-core-5.4.0.tgz#c9d55357d75a6ce25a95d235795d6b68c6f85e17" - integrity sha512-8HlKAcKXm7cJmzWQTVGnZiBs21BXkmRiknDaH9NbO6UT5JqYupXe/3zEesoX6Kxad2EzGlPVpBV816luWfqepw== - "@datadog/browser-logs@^5.28.0": version "5.28.0" resolved "https://registry.yarnpkg.com/@datadog/browser-logs/-/browser-logs-5.28.0.tgz#9f86067c0482d0ea01a86a185aff511252d52307" @@ -1164,13 +1159,6 @@ dependencies: "@datadog/browser-core" "5.28.0" -"@datadog/browser-logs@^5.4.0": - version "5.4.0" - resolved "https://registry.yarnpkg.com/@datadog/browser-logs/-/browser-logs-5.4.0.tgz#fc346364b1e59acb24d400114ef74adb6f223b92" - integrity sha512-0eLkUHUTnch8cpJMqV421XpUaEs0yS/4xriWz+GsAs+2uFQGio26fDmdRGOvK+8JowDBSv9VY+YzRi8iXlhJOA== - dependencies: - "@datadog/browser-core" "5.4.0" - "@datastructures-js/max-heap@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@datastructures-js/max-heap/-/max-heap-2.0.0.tgz#4ab3bbc09706ff632aaa6d85fe6ba51747663b9a" @@ -12171,6 +12159,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@7.2.0, glob@^7.1.6: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@^5.0.15, glob@^5.0.3: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" @@ -12206,18 +12206,6 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.6: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - "glob@~ 3.2.1": version "3.2.11" resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d"