import { Injector } from '@opensumi/di'; import { LANGUAGE_TO_SUFFIX, URI } from '@opensumi/ide-core-common'; import { IFileServiceClient } from '@opensumi/ide-file-service'; import { Path } from '@opensumi/ide-utils/lib/path'; import { IWorkspaceService } from '@opensumi/ide-workspace'; import { LanguageParserService } from '../../../languages/service'; import { ICompletionContext, ImportedFileOptions, ResourceDocument } from '../types'; export const getImportedFilesInterface = async ( code: string, resource: ResourceDocument, options: ImportedFileOptions, injector: Injector, ): Promise<(string | string[])[][]> => { const languageParserService = injector.get(LanguageParserService) as LanguageParserService; let matches: string[] = []; const snippets: (string | string[])[][] = []; const languageParser = languageParserService.createParser(resource.languageId); if (languageParser) { matches = await languageParser.extractImportPaths(code); } const maxPromptTime = options.maxTime ?? 200; const startTime = Date.now(); for (const file of matches) { let filePath = ''; const basePath = resource.uri.parent.codeUri.fsPath; if (file.startsWith('@/') || file.startsWith('~') || !file.startsWith('.')) { // skip alias continue; } if (file === '.') { filePath = new Path(basePath).join('index.ts').toString(); } else { filePath = new Path(basePath).join(`${file}${LANGUAGE_TO_SUFFIX[resource.languageId]}`).toString(); } try { const fileService = injector.get(IFileServiceClient) as IFileServiceClient; const workspaceService = injector.get(IWorkspaceService) as IWorkspaceService; const fileUri = URI.file(filePath); const content = await fileService.readFile(fileUri.codeUri.fsPath); const interfaceCode = await languageParser?.extractInterfaceOrTypeCode(content.content.toString()); if (interfaceCode && interfaceCode.length > 0) { const relative = await workspaceService.asRelativePath(fileUri); if (relative?.path) { snippets.push([relative.path, interfaceCode]); } } } catch {} if (Date.now() - startTime > maxPromptTime) { break; } } return snippets; }; export const extractLocalImportContext = async ( resource: ResourceDocument, options: ImportedFileOptions, injector: Injector, ): Promise<(string | string[])[][]> => { // 从代码中提取出所有的 import 语句,并进一步提取 interface 相关代码声明 const { source } = resource; if (resource.languageId === 'typescript') { return getImportedFilesInterface(source, resource, options, injector); } return []; }; export const getImportedFile = async ( context: ICompletionContext, options: ImportedFileOptions, injector: Injector, ): Promise<(string | string[])[][]> => { if (context.language && !options.language.includes(context.language)) { return []; } const content = context.prefix; return extractLocalImportContext( { source: content, uri: context.uri, languageId: context.language, offset: content.length, }, options, injector, ); };