diff --git a/packages/react-router-dev/typescript/autotype/language-service.ts b/packages/react-router-dev/typescript/autotype/language-service.ts index 2cbd7cc81a..560744b812 100644 --- a/packages/react-router-dev/typescript/autotype/language-service.ts +++ b/packages/react-router-dev/typescript/autotype/language-service.ts @@ -167,7 +167,6 @@ function autotypeRoute(ctx: Context, filepath: string, code: string) { ...annotateDefaultExportExpression(ctx, stmt, typesSource), ...annotateNamedExportFunctionDeclaration(ctx, stmt, typesSource), ...annotateNamedExportVariableStatement(ctx, stmt, typesSource), - ...annotateExportDeclaration(ctx, stmt, typesSource), ]), ]; return new AutotypedRoute(code, splices); @@ -295,62 +294,23 @@ function annotateFunction( const annotateReturnType = Route.exports[name]?.annotateReturnType; + name = name === "default" ? "Default" : name; return [ param && param.type === undefined ? { index: param.getEnd(), - content: `: Parameters[0]`, + content: `: import("${typesSource}").${name}["args"]`, remapDiagnostics, } : null, returnTypeIndex && annotateReturnType && fn.type === undefined ? { index: returnTypeIndex, - content: `: ReturnType `, + content: `: import("${typesSource}").${name}["return"]`, remapDiagnostics, } : null, - ].filter((x) => x !== null); -} - -function annotateExportDeclaration( - ctx: Context, - stmt: ts.Statement, - typesSource: string -): Splice[] { - if (!ctx.ts.isExportDeclaration(stmt)) return []; - - const source = stmt.moduleSpecifier; - if (source && !ctx.ts.isStringLiteral(source)) return []; - - const exports = stmt.exportClause; - if (!exports) return []; - if (!ctx.ts.isNamedExports(exports)) return []; - - return exports.elements - .map((specifier) => { - const name = specifier.name.text; - const routeExport = Route.exports[name]; - if (!routeExport) return undefined; - - const localName = specifier.propertyName?.text ?? name; - const unique = AST.generateUniqueIdentifier(); - const satisfiesType = `import("${typesSource}").Route["${name}"]`; - - const splice: Splice = { - index: stmt.getStart(), - content: source - ? `import { ${localName} as ${unique} } from "${source.text}"\n` + - `${unique} satisfies ${satisfiesType}\n` - : `${localName} satisfies ${satisfiesType}\n`, - remapDiagnostics: { - start: specifier.name.getStart(), - length: specifier.name.getWidth(), - }, - }; - return splice; - }) - .filter((x) => x !== undefined); + ].filter((x) => x !== null) as Splice[]; } export class AutotypedRoute { diff --git a/packages/react-router-dev/typescript/decorate.ts b/packages/react-router-dev/typescript/decorate.ts index 138e919e24..75cc12f8da 100644 --- a/packages/react-router-dev/typescript/decorate.ts +++ b/packages/react-router-dev/typescript/decorate.ts @@ -77,7 +77,7 @@ export function decorateLanguageService(ctx: Context) { replacementSpan: { start: lineStart, length: position - lineStart }, }; }) - .filter((x) => x !== null); + .filter((x) => x !== null) as ts.CompletionEntry[]; if (!completions) { return routeExportCompletions.length > 0 @@ -176,7 +176,7 @@ export function decorateLanguageService(ctx: Context) { return diagnostic; } }) - .filter((x) => x !== undefined); + .filter((x) => x !== undefined) as ts.Diagnostic[]; const hmrNamedFunctionsDiagnostics: ts.Diagnostic[] = sourceFile.statements // eslint-disable-next-line array-callback-return @@ -212,7 +212,7 @@ export function decorateLanguageService(ctx: Context) { }; } }) - .filter((x) => x !== undefined); + .filter((x) => x !== undefined) as ts.Diagnostic[]; return [ ...hmrNamedFunctionsDiagnostics, diff --git a/packages/react-router-dev/typescript/plugin.ts b/packages/react-router-dev/typescript/plugin.ts index 2c7773888d..522e197935 100644 --- a/packages/react-router-dev/typescript/plugin.ts +++ b/packages/react-router-dev/typescript/plugin.ts @@ -8,6 +8,7 @@ import * as Path from "pathe"; import * as Typegen from "./typegen"; import type { Context } from "./context"; +import { decorateLanguageService } from "./decorate"; export default function init(modules: { typescript: typeof ts }) { function create(info: ts.server.PluginCreateInfo) { @@ -29,6 +30,7 @@ export default function init(modules: { typescript: typeof ts }) { }; Typegen.watch(ctx); + decorateLanguageService(ctx); return info.languageService; } return { create }; diff --git a/packages/react-router-dev/typescript/routes.ts b/packages/react-router-dev/typescript/routes.ts index fafcf08292..499771c262 100644 --- a/packages/react-router-dev/typescript/routes.ts +++ b/packages/react-router-dev/typescript/routes.ts @@ -1,15 +1,26 @@ import Path from "pathe"; +import Pathe from "pathe/utils"; import type ts from "typescript/lib/tsserverlibrary"; import type { Context } from "./context"; import type { RouteManifestEntry } from "../config/routes"; +function noext(path: string) { + return Path.join(Path.dirname(path), Pathe.filename(path)); +} + export function get( ctx: Context, fileName: string ): RouteManifestEntry | undefined { - return ctx.routes[Path.relative(ctx.config.appDirectory, fileName)]; + const routeId = noext(Path.relative(ctx.config.appDirectory, fileName)); + ctx.logger?.info( + `Route.get filename:${fileName} routeId:${routeId} routes:${JSON.stringify( + ctx.routes + )}` + ); + return ctx.routes[routeId]; } type RouteExportInfo = { @@ -25,7 +36,7 @@ export const exports: Record = { link: `https://remix.run/docs/en/main/route/links`, }), }, - serverLoader: { + loader: { annotateReturnType: false, documentation: createDocumentation({ name: "serverLoader", @@ -47,7 +58,7 @@ export const exports: Record = { link: `https://remix.run/docs/en/main/route/hydrate-fallback`, }), }, - serverAction: { + action: { annotateReturnType: false, documentation: createDocumentation({ name: "serverAction", diff --git a/packages/react-router-dev/typescript/typegen.ts b/packages/react-router-dev/typescript/typegen.ts index 7574c56b7d..5347420633 100644 --- a/packages/react-router-dev/typescript/typegen.ts +++ b/packages/react-router-dev/typescript/typegen.ts @@ -90,10 +90,10 @@ function getModule(ctx: Context, route: RouteManifestEntry): string { export type LoaderData = T.LoaderData export type ActionData = T.ActionData - export type ServerLoader = T.ServerLoader - export type ClientLoader = T.ClientLoader - export type ServerAction = T.ServerAction - export type ClientAction = T.ClientAction + export type serverLoader = T.ServerLoader + export type clientLoader = T.ClientLoader + export type serverAction = T.ServerAction + export type clientAction = T.ClientAction export type HydrateFallback = T.HydrateFallback export type Default = T.Default