/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at . */
import { createSelector } from "reselect";
import { shallowEqual } from "../utils/shallow-equal";
import {
getPrettySourceURL,
isGenerated,
isPretty,
isJavaScript,
} from "../utils/source";
import { findPosition } from "../utils/breakpoint/breakpointPositions";
import { isFulfilled } from "../utils/async-value";
import { originalToGeneratedId } from "devtools/client/shared/source-map-loader/index";
import { prefs } from "../utils/prefs";
import {
hasSourceActor,
getSourceActor,
getBreakableLinesForSourceActors,
} from "./source-actors";
import { getSourceTextContent } from "./sources-content";
export function hasSource(state, id) {
return state.sources.sources.has(id);
}
export function getSource(state, id) {
return state.sources.sources.get(id);
}
export function getSourceFromId(state, id) {
const source = getSource(state, id);
if (!source) {
console.warn(`source ${id} does not exist`);
}
return source;
}
export function getLocationSource(state, location) {
return getSource(state, location.sourceId);
}
export function getSourceByActorId(state, actorId) {
if (!hasSourceActor(state, actorId)) {
return null;
}
return getSource(state, getSourceActor(state, actorId).source);
}
function getSourcesByURL(state, url) {
const urls = getUrls(state);
if (!url || !urls[url]) {
return [];
}
return urls[url].map(id => getSource(state, id));
}
export function getSourceByURL(state, url) {
const foundSources = getSourcesByURL(state, url);
return foundSources ? foundSources[0] : null;
}
// This is used by tabs selectors
export function getSpecificSourceByURL(state, url, isOriginal) {
const foundSources = getSourcesByURL(state, url);
if (foundSources) {
return foundSources.find(source => source.isOriginal == isOriginal);
}
return null;
}
function getOriginalSourceByURL(state, url) {
return getSpecificSourceByURL(state, url, true);
}
export function getGeneratedSourceByURL(state, url) {
return getSpecificSourceByURL(state, url, false);
}
export function getGeneratedSource(state, source) {
if (!source) {
return null;
}
if (isGenerated(source)) {
return source;
}
return getSourceFromId(state, originalToGeneratedId(source.id));
}
export function getPendingSelectedLocation(state) {
return state.sources.pendingSelectedLocation;
}
export function getPrettySource(state, id) {
if (!id) {
return null;
}
const source = getSource(state, id);
if (!source) {
return null;
}
return getOriginalSourceByURL(state, getPrettySourceURL(source.url));
}
export function hasPrettySource(state, id) {
return !!getPrettySource(state, id);
}
// This is only used externaly by tabs and breakpointSources selectors
export function getSourcesMap(state) {
return state.sources.sources;
}
function getUrls(state) {
return state.sources.urls;
}
export const getSourceList = createSelector(
getSourcesMap,
sourcesMap => {
return [...sourcesMap.values()];
},
{ equalityCheck: shallowEqual, resultEqualityCheck: shallowEqual }
);
// This is only used by tests
export function getSourceCount(state) {
return getSourcesMap(state).size;
}
export function getSelectedLocation(state) {
return state.sources.selectedLocation;
}
export const getSelectedSource = createSelector(
getSelectedLocation,
getSourcesMap,
(selectedLocation, sourcesMap) => {
if (!selectedLocation) {
return undefined;
}
return sourcesMap.get(selectedLocation.sourceId);
}
);
// This is used by tests and pause reducers
export function getSelectedSourceId(state) {
const source = getSelectedSource(state);
return source?.id;
}
/**
* Gets the first source actor for the source and/or thread
* provided.
*
* @param {Object} state
* @param {String} sourceId
* The source used
* @param {String} [threadId]
* The thread to check, this is optional.
* @param {Object} sourceActor
*
*/
export function getFirstSourceActorForGeneratedSource(
state,
sourceId,
threadId
) {
const source = getSource(state, sourceId);
if (source.isOriginal) {
return null;
}
let actorsInfo = state.sources.actors[sourceId];
if (!actorsInfo.length) {
return null;
}
if (threadId) {
actorsInfo = actorsInfo.filter(actorInfo => actorInfo.thread == threadId);
}
return actorsInfo.length ? getSourceActor(state, actorsInfo[0].id) : null;
}
/**
* Get the source actor of the source
*
* @param {Object} state
* @param {String} id
* The source id
* @return {Array