UNPKG

@prometx/trpc-navigation-plugin

Version:

TypeScript Language Service Plugin that fixes broken 'go to definition' for tRPC when using declaration emit

141 lines 4.96 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.findWordAtPosition = findWordAtPosition; exports.parseNavigationPath = parseNavigationPath; exports.createDefinitionResult = createDefinitionResult; exports.createNavigationResult = createNavigationResult; exports.detectTrpcApiCall = detectTrpcApiCall; const ts = __importStar(require("typescript/lib/tsserverlibrary")); /** * Finds the word at the given position in the text */ function findWordAtPosition(text, position) { let wordStart = position; let wordEnd = position; // Find start of word while (wordStart > 0 && /\w/.test(text.charAt(wordStart - 1))) { wordStart--; } // Find end of word while (wordEnd < text.length && /\w/.test(text.charAt(wordEnd))) { wordEnd++; } const word = text.substring(wordStart, wordEnd); return { word, start: wordStart, end: wordEnd, segmentIndex: -1 }; } /** * Parses a navigation path and determines which segment was clicked */ function parseNavigationPath(fullPath, clickedWord, variableName) { const fullPathParts = fullPath.split('.'); const apiPath = fullPathParts.slice(1).join('.'); let clickedSegmentIndex = -1; // Find which segment was clicked for (let i = 0; i < fullPathParts.length; i++) { if (fullPathParts[i] === clickedWord) { clickedSegmentIndex = i; break; } } // Skip if clicked on variable name if (clickedSegmentIndex <= 0) { return null; } // Calculate target path (segments to navigate) const adjustedIndex = clickedSegmentIndex - 1; // Subtract 1 because apiPath doesn't include variable name const targetPath = apiPath.split('.').slice(0, adjustedIndex + 1); return { variableName, apiPath, segments: fullPathParts, clickedSegmentIndex, targetPath, }; } /** * Creates a TypeScript DefinitionInfo result */ function createDefinitionResult(fileName, start, length, name, kind = ts.ScriptElementKind.functionElement) { return { fileName, textSpan: { start, length, }, kind, name, containerKind: ts.ScriptElementKind.moduleElement, containerName: 'TRPC', }; } /** * Creates a DefinitionInfoAndBoundSpan result */ function createNavigationResult(definition, clickedWord) { return { definitions: [definition], textSpan: { start: clickedWord.start, length: clickedWord.word.length, }, }; } /** * Detects if a line contains a tRPC API call pattern */ function detectTrpcApiCall(line, cursorPosition) { const beforeCursor = line.substring(0, cursorPosition); const afterCursor = line.substring(cursorPosition); // Match any variable followed by a dot and path const apiPattern = /(\w+)\s*\.\s*([\w.]*\w)?$/; const apiMatch = beforeCursor.match(apiPattern); if (!apiMatch) { return null; } const variable = apiMatch[1]; let path = apiMatch[2] || ''; // Look forward to complete the path until we hit: // - A method call: .something() // - End of property chain: whitespace, operators, or end of line const forwardMatch = afterCursor.match(/^([\w.]*?)(?=\s*(?:\.\s*\w+\s*\(|[^\w.]|$))/); if (forwardMatch?.[1]) { path += forwardMatch[1]; } // Clean up the path path = path.replace(/\s+/g, '').replace(/\.+$/, '').replace(/^\.+/, ''); return path ? { variable, path } : null; } //# sourceMappingURL=navigation-utils.js.map