UNPKG

chrome-devtools-frontend

Version:
84 lines (69 loc) 3.06 kB
// Copyright 2025 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Common from '../../../core/common/common.js'; import * as SDK from '../../../core/sdk/sdk.js'; import type * as Protocol from '../../../generated/protocol.js'; import * as Trace from '../../../models/trace/trace.js'; import type * as Marked from '../../../third_party/marked/marked.js'; import * as Lit from '../../../ui/lit/lit.js'; import * as PanelsCommon from '../../common/common.js'; import {MarkdownRendererWithCodeBlock} from './MarkdownRendererWithCodeBlock.js'; const {html} = Lit.StaticHtml; const {until} = Lit.Directives; export class PerformanceAgentMarkdownRenderer extends MarkdownRendererWithCodeBlock { constructor( private mainFrameId = '', private lookupEvent: (key: Trace.Types.File.SerializableKey) => Trace.Types.Events.Event | null = () => null) { super(); } override templateForToken(token: Marked.Marked.MarkedToken): Lit.LitTemplate|null { if (token.type === 'link' && token.href.startsWith('#')) { if (token.href.startsWith('#node-')) { const nodeId = Number(token.href.replace('#node-', '')) as Protocol.DOM.BackendNodeId; return html`<span>${ until(this.#linkifyNode(nodeId, token.text).then(node => node || token.text), token.text)}</span>`; } const event = this.lookupEvent(token.href.slice(1) as Trace.Types.File.SerializableKey); if (!event) { return html`${token.text}`; } let label = token.text; let title = ''; if (Trace.Types.Events.isSyntheticNetworkRequest(event)) { title = event.args.data.url; } else { label += ` (${event.name})`; } // eslint-disable-next-line @devtools/no-a-tags-in-lit return html`<a href="#" draggable=false .title=${title} @click=${(e: Event) => { e.stopPropagation(); void Common.Revealer.reveal(new SDK.TraceObject.RevealableEvent(event)); }}>${label}</a>`; } return super.templateForToken(token); } // Taken from front_end/panels/timeline/components/insights/NodeLink.ts // Would be nice to move the above component to somewhere that allows the AI // Assistance panel to also use it. async #linkifyNode(backendNodeId: Protocol.DOM.BackendNodeId, label: string): Promise<Lit.LitTemplate|undefined> { if (backendNodeId === undefined) { return; } const target = SDK.TargetManager.TargetManager.instance().primaryPageTarget(); const domModel = target?.model(SDK.DOMModel.DOMModel); if (!domModel) { return undefined; } const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(new Set([backendNodeId])); const node = domNodesMap?.get(backendNodeId); if (!node) { return; } if (node.frameId() !== this.mainFrameId) { return; } const linkedNode = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(node, {textContent: label}); return linkedNode; } }