/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* 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 http://mozilla.org/MPL/2.0/. */ "use strict"; const { l10n } = require("devtools/client/webconsole/new-console-output/utils/messages"); const { getAllFilters } = require("devtools/client/webconsole/new-console-output/selectors/filters"); const { getLogLimit } = require("devtools/client/webconsole/new-console-output/selectors/prefs"); const { MESSAGE_TYPE, MESSAGE_SOURCE } = require("devtools/client/webconsole/new-console-output/constants"); function getAllMessages(state) { let messages = getAllMessagesById(state); let logLimit = getLogLimit(state); let filters = getAllFilters(state); let groups = getAllGroupsById(state); let messagesUI = getAllMessagesUiById(state); return prune( messages.filter(message => { return ( isInOpenedGroup(message, groups, messagesUI) && ( isUnfilterable(message) || ( matchLevelFilters(message, filters) && matchNetworkFilters(message, filters) && matchSearchFilters(message, filters) ) ) ); }), logLimit ); } function getAllMessagesById(state) { return state.messages.messagesById; } function getAllMessagesUiById(state) { return state.messages.messagesUiById; } function getAllMessagesTableDataById(state) { return state.messages.messagesTableDataById; } function getAllGroupsById(state) { return state.messages.groupsById; } function getCurrentGroup(state) { return state.messages.currentGroup; } function isUnfilterable(message) { return [ MESSAGE_TYPE.COMMAND, MESSAGE_TYPE.RESULT, MESSAGE_TYPE.START_GROUP, MESSAGE_TYPE.START_GROUP_COLLAPSED, ].includes(message.type); } function isInOpenedGroup(message, groups, messagesUI) { return !message.groupId || ( !isGroupClosed(message.groupId, messagesUI) && !hasClosedParentGroup(groups.get(message.groupId), messagesUI) ); } function hasClosedParentGroup(group, messagesUI) { return group.some(groupId => isGroupClosed(groupId, messagesUI)); } function isGroupClosed(groupId, messagesUI) { return messagesUI.includes(groupId) === false; } function matchLevelFilters(message, filters) { return filters.get(message.level) === true; } function matchNetworkFilters(message, filters) { return ( message.source !== MESSAGE_SOURCE.NETWORK || (filters.get("net") === true && message.isXHR === false) || (filters.get("netxhr") === true && message.isXHR === true) ); } function matchSearchFilters(message, filters) { let text = filters.text || ""; return ( text === "" // @TODO currently we return true for any object grip. We should find a way to // search object grips. || (message.parameters !== null && !Array.isArray(message.parameters)) // Look for a match in location. || isTextInFrame(text, message.frame) // Look for a match in stacktrace. || ( Array.isArray(message.stacktrace) && message.stacktrace.some(frame => isTextInFrame(text, // isTextInFrame expect the properties of the frame object to be in the same // order they are rendered in the Frame component. { functionName: frame.functionName || l10n.getStr("stacktrace.anonymousFunction"), filename: frame.filename, lineNumber: frame.lineNumber, columnNumber: frame.columnNumber })) ) // Look for a match in messageText. || (message.messageText !== null && message.messageText.toLocaleLowerCase().includes(text.toLocaleLowerCase())) // Look for a match in parameters. Currently only checks value grips. || (message.parameters !== null && message.parameters.join("").toLocaleLowerCase() .includes(text.toLocaleLowerCase())) // Look for a match in notes. || (Array.isArray(message.notes) && message.notes.some(note => // Look for a match in location. isTextInFrame(text, note.frame) // Look for a match in messageBody. || (note.messageBody !== null && note.messageBody.toLocaleLowerCase() .includes(text.toLocaleLowerCase())) )) ); } function isTextInFrame(text, frame) { if (!frame) { return false; } // @TODO Change this to Object.values once it's supported in Node's version of V8 return Object.keys(frame) .map(key => frame[key]) .join(":") .toLocaleLowerCase() .includes(text.toLocaleLowerCase()); } function prune(messages, logLimit) { let messageCount = messages.count(); if (messageCount > logLimit) { // If the second non-pruned message is in a group, // we want to return the group as the first non-pruned message. let firstIndex = messages.size - logLimit; let groupId = messages.get(firstIndex + 1).groupId; if (groupId) { return messages.splice(0, firstIndex + 1) .unshift( messages.findLast((message) => message.id === groupId) ); } return messages.splice(0, firstIndex); } return messages; } exports.getAllMessages = getAllMessages; exports.getAllMessagesUiById = getAllMessagesUiById; exports.getAllMessagesTableDataById = getAllMessagesTableDataById; exports.getAllGroupsById = getAllGroupsById; exports.getCurrentGroup = getCurrentGroup;