chrome-devtools-frontend
Version:
Chrome DevTools UI
123 lines (105 loc) • 3.82 kB
text/typescript
// Copyright 2026 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 Host from '../../../core/host/host.js';
import * as i18n from '../../../core/i18n/i18n.js';
import type * as Platform from '../../../core/platform/platform.js';
import {canResourceContentsBeReadForTrace} from '../AiOrigins.js';
import {PerformanceTraceContext} from '../contexts/PerformanceTraceContext.js';
import {
type BaseToolCapability,
type DataHandlerResult,
type DataTool,
type ToolArgs,
ToolName,
} from './Tool.js';
const UIStringsNotTranslate = {
lookingUpFunctionCode: 'Looking up function code',
} as const;
const lockedString = i18n.i18n.lockedString;
export interface GetFunctionCodeArgs extends ToolArgs {
scriptUrl: string;
line: number;
column: number;
}
export class GetFunctionCodeTool implements DataTool<GetFunctionCodeArgs, string, BaseToolCapability> {
readonly name = ToolName.GET_FUNCTION_CODE;
readonly description =
'Returns the code for a function defined at the given location. The result is annotated with the runtime performance of each line of code.';
readonly parameters: Host.AidaClient.FunctionObjectParam<keyof GetFunctionCodeArgs> = {
type: Host.AidaClient.ParametersTypes.OBJECT,
description: 'Arguments for looking up function code.',
nullable: false,
properties: {
scriptUrl: {
type: Host.AidaClient.ParametersTypes.STRING,
description: 'The url of the function.',
nullable: false,
},
line: {
type: Host.AidaClient.ParametersTypes.INTEGER,
description: 'The line number where the function is defined.',
nullable: false,
},
column: {
type: Host.AidaClient.ParametersTypes.INTEGER,
description: 'The column number where the function is defined.',
nullable: false,
},
},
required: ['scriptUrl', 'line', 'column'],
};
displayInfoFromArgs(params: GetFunctionCodeArgs): {
title: string,
action: string,
} {
return {
title: lockedString(UIStringsNotTranslate.lookingUpFunctionCode),
action: `getFunctionCode('${params.scriptUrl}', ${params.line}, ${params.column})`,
};
}
async handler(
params: GetFunctionCodeArgs,
capabilities: BaseToolCapability,
): Promise<DataHandlerResult<string>> {
const conversationContext = capabilities.conversationContext;
if (!conversationContext || !(conversationContext instanceof PerformanceTraceContext)) {
return {error: 'Performance trace context is not available.'};
}
if (conversationContext.getOrigin().startsWith('imported-trace://')) {
return {error: 'Cannot use this tool on an imported file.'};
}
if (!params.scriptUrl) {
return {error: 'Missing arg: scriptUrl'};
}
const allowedOrigin = conversationContext.getOrigin();
if (!canResourceContentsBeReadForTrace(params.scriptUrl, allowedOrigin)) {
return {error: 'Script not found'};
}
if (params.line === undefined) {
return {error: 'Missing arg: line'};
}
if (params.column === undefined) {
return {error: 'Missing arg: column'};
}
const formatter = conversationContext.createFormatter();
const url = params.scriptUrl as Platform.DevToolsPath.UrlString;
const code = await formatter.resolveFunctionCodeAtLocation(url, params.line, params.column);
if (!code) {
return {error: 'Could not find code'};
}
const result = formatter.formatFunctionCode(code);
return {
result,
widgets: [{
name: 'SOURCE_CODE',
data: {
url,
line: params.line,
column: params.column,
code: code.code,
},
}],
};
}
}