-
Notifications
You must be signed in to change notification settings - Fork 17
fix: infer route types across the middleware/validator module cycle #278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rturnq
wants to merge
10
commits into
main
Choose a base branch
from
ryanturnquist-Mac-run-agent-triage-p2d582
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
396cf77
fix: break the type cycle between middleware data and downstream vali…
rturnq 448bd75
revert: restore the full downstream options merge; pin the type cycle…
rturnq ee1df50
fix: keep middleware and validator types across the route module cycle
rturnq a645777
feat: file-wide options export merged route-wide without the module t…
rturnq c41d0cd
fix: infer route types across the middleware/validator module cycle
rturnq f31766d
fix: check handler returns where no middleware entangles, name captur…
rturnq d24226c
test: pin context helper compatibility and route-level validated params
rturnq 3091eaa
refactor: one deferred DefineHandler parameterized by its return target
rturnq 88fd81f
refactor: tighten handler define aliases and drop redundant intersect…
rturnq c99cfc6
docs: align type comments with the comment conventions
rturnq File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@marko/run": patch | ||
| --- | ||
|
|
||
| Fix route middleware and handler types collapsing to `any` when a middleware derives `next()` data from its context while a downstream handler declares validators. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
packages/run/src/__tests__/fixtures/params-validator-types/.marko-run/routes.d.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| /* | ||
| WARNING: This file is automatically generated and any changes made to it will be overwritten without warning. | ||
| Do NOT manually edit this file or your changes will be lost. | ||
| */ | ||
|
|
||
| import { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "@marko/run/namespace"; | ||
| import type * as $ from "@marko/run"; | ||
|
|
||
|
|
||
| declare module "@marko/run" { | ||
| interface App extends $.DefineRoutes<{ | ||
| "/api/procs/$pid": [H1]; | ||
| "/api/workspaces/$id/review/$commentId": [M1, H2]; | ||
| }> {} | ||
| } | ||
|
|
||
| type M1 = $.Middleware<"M1", typeof import("../src/routes/api/workspaces/$id/+middleware")>; | ||
| declare module "../src/routes/api/workspaces/$id/+middleware" { | ||
| const Run: $.Namespace<M1>; | ||
| namespace Run { | ||
| type Context = $.ContextForFile<M1>; | ||
| } | ||
|
|
||
| /** @deprecated use `Run` namespace instead */ | ||
| namespace MarkoRun { | ||
| export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform }; | ||
| export type Route = $.Routes["/api/workspaces/$id/review/$commentId"]; | ||
| export type Context = $.MultiRouteContext<Route>; | ||
| export type Handler = $.HandlerLike<Route>; | ||
| export type GET = $.HandlerLike<Route, "GET">; | ||
| export type HEAD = $.HandlerLike<Route, "HEAD">; | ||
| export type POST = $.HandlerLike<Route, "POST">; | ||
| export type PUT = $.HandlerLike<Route, "PUT">; | ||
| export type DELETE = $.HandlerLike<Route, "DELETE">; | ||
| export type PATCH = $.HandlerLike<Route, "PATCH">; | ||
| export type OPTIONS = $.HandlerLike<Route, "OPTIONS">; | ||
| export type QUERY = $.HandlerLike<Route, "QUERY">; | ||
| } | ||
| } | ||
|
|
||
| type H1 = $.Handler<"H1", typeof import("../src/routes/api/procs/$pid/+handler")>; | ||
| declare module "../src/routes/api/procs/$pid/+handler" { | ||
| const Run: $.Namespace<H1>; | ||
| namespace Run { | ||
| type Context = $.ContextForFile<H1>; | ||
| } | ||
|
|
||
| /** @deprecated use `Run` namespace instead */ | ||
| namespace MarkoRun { | ||
| export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform }; | ||
| export type Route = $.Routes["/api/procs/$pid"]; | ||
| export type Context = $.MultiRouteContext<Route>; | ||
| export type Handler = $.HandlerLike<Route>; | ||
| export type GET = $.HandlerLike<Route, "GET">; | ||
| export type HEAD = $.HandlerLike<Route, "HEAD">; | ||
| export type POST = $.HandlerLike<Route, "POST">; | ||
| export type PUT = $.HandlerLike<Route, "PUT">; | ||
| export type DELETE = $.HandlerLike<Route, "DELETE">; | ||
| export type PATCH = $.HandlerLike<Route, "PATCH">; | ||
| export type OPTIONS = $.HandlerLike<Route, "OPTIONS">; | ||
| export type QUERY = $.HandlerLike<Route, "QUERY">; | ||
| } | ||
| } | ||
|
|
||
| type H2 = $.Handler<"H2", typeof import("../src/routes/api/workspaces/$id/review/$commentId/+handler")>; | ||
| declare module "../src/routes/api/workspaces/$id/review/$commentId/+handler" { | ||
| const Run: $.Namespace<H2>; | ||
| namespace Run { | ||
| type Context = $.ContextForFile<H2>; | ||
| } | ||
|
|
||
| /** @deprecated use `Run` namespace instead */ | ||
| namespace MarkoRun { | ||
| export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform }; | ||
| export type Route = $.Routes["/api/workspaces/$id/review/$commentId"]; | ||
| export type Context = $.MultiRouteContext<Route>; | ||
| export type Handler = $.HandlerLike<Route>; | ||
| export type GET = $.HandlerLike<Route, "GET">; | ||
| export type HEAD = $.HandlerLike<Route, "HEAD">; | ||
| export type POST = $.HandlerLike<Route, "POST">; | ||
| export type PUT = $.HandlerLike<Route, "PUT">; | ||
| export type DELETE = $.HandlerLike<Route, "DELETE">; | ||
| export type PATCH = $.HandlerLike<Route, "PATCH">; | ||
| export type OPTIONS = $.HandlerLike<Route, "OPTIONS">; | ||
| export type QUERY = $.HandlerLike<Route, "QUERY">; | ||
| } | ||
| } |
5 changes: 5 additions & 0 deletions
5
...run/src/__tests__/fixtures/params-validator-types/__snapshots__/dev.expected.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Loading | ||
|
|
||
| # Step 0 | ||
| ctx=>deleteComment(ctx) | ||
|
|
5 changes: 5 additions & 0 deletions
5
...src/__tests__/fixtures/params-validator-types/__snapshots__/preview.expected.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| # Loading | ||
|
|
||
| # Step 0 | ||
| ctx=>deleteComment(ctx) | ||
|
|
21 changes: 21 additions & 0 deletions
21
...s/run/src/__tests__/fixtures/params-validator-types/src/routes/api/procs/$pid/+handler.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| export const DELETE = Run.DELETE( | ||
| { | ||
| params({ pid }) { | ||
| return { pid }; | ||
| }, | ||
| }, | ||
| (ctx) => { | ||
| return Response.json({ pid: ctx.params.pid }); | ||
| }, | ||
| ); | ||
|
|
||
| // No middleware runs upstream, so this file's handlers get return checking. | ||
| export const validReturns = [ | ||
| Run.GET(() => new Response("ok")), | ||
| Run.GET(async () => Response.json({ ok: true })), | ||
| Run.GET((ctx, next) => next()), | ||
| ]; | ||
| // @ts-expect-error a handler cannot return a bare number | ||
| export const badNumber = Run.GET(() => 42); | ||
| // @ts-expect-error a handler cannot return a bare object in place of a Response | ||
| export const badObject = Run.GET(() => ({ plain: "object" })); |
16 changes: 16 additions & 0 deletions
16
...rc/__tests__/fixtures/params-validator-types/src/routes/api/workspaces/$id/+middleware.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| export default Run.ALL( | ||
| { | ||
| search({ limit }) { | ||
| return { limit: limit ? Number(limit) : 0 }; | ||
| }, | ||
| }, | ||
| (ctx, next) => { | ||
| if ("commentId" in ctx.params) { | ||
| const merged: number = ctx.params.commentId; | ||
| // @ts-expect-error the DELETE validator types commentId as number | ||
| const bad: boolean = ctx.params.commentId; | ||
| void merged, void bad; | ||
| } | ||
| return next({ workspace: `ws-${ctx.params.id}` }); | ||
| }, | ||
| ); |
37 changes: 37 additions & 0 deletions
37
...xtures/params-validator-types/src/routes/api/workspaces/$id/review/$commentId/+handler.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import type { Context, GetContext } from "@marko/run"; | ||
|
|
||
| export const DELETE = Run.DELETE( | ||
| { | ||
| params({ id, commentId }) { | ||
| return { id, commentId: Number(commentId) }; | ||
| }, | ||
| }, | ||
| (ctx) => { | ||
| const asPlainContext: Context = ctx; | ||
| const asScopedContext: GetContext<"/api/workspaces/$id/review/$commentId"> = | ||
| ctx; | ||
| // @ts-expect-error the deprecated MarkoRun.Context types params as raw | ||
| // strings, so a context whose validator produced a number never fit it | ||
| const asLegacyContext: MarkoRun.Context = ctx; | ||
| void asPlainContext, void asScopedContext, void asLegacyContext; | ||
| const validated: number = ctx.params.commentId; | ||
| const upstream: string = ctx.data.workspace; | ||
| const fromMiddleware: number = ctx.search.limit; | ||
| // @ts-expect-error the validator types commentId as number | ||
| const badParam: boolean = ctx.params.commentId; | ||
| // @ts-expect-error the middleware data types workspace as string | ||
| const badData: boolean = ctx.data.workspace; | ||
| // @ts-expect-error the middleware search validator types limit as number | ||
| const badSearch: boolean = ctx.search.limit; | ||
| void validated, void upstream, void fromMiddleware, void badParam; | ||
| void badData, void badSearch; | ||
| return Response.json({ | ||
| id: ctx.params.id, | ||
| commentId: ctx.params.commentId, | ||
| }); | ||
| }, | ||
| ); | ||
|
|
||
| export const routeLevel: number = null as unknown as Run.Context["params"]["commentId"]; | ||
| // @ts-expect-error route-level params keep the validated number type | ||
| export const routeLevelBad: boolean = null as unknown as Run.Context["params"]["commentId"]; |
15 changes: 15 additions & 0 deletions
15
packages/run/src/__tests__/fixtures/params-validator-types/test.config.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import assert from "assert"; | ||
|
|
||
| import type { Step, StepContext } from "../../main.test"; | ||
|
|
||
| export const path = "/api/procs/42"; | ||
|
|
||
| async function deleteComment({ page }: StepContext) { | ||
| const res = await page.fetch( | ||
| new URL("/api/workspaces/w1/review/7", page.url()).href, | ||
| { method: "DELETE" }, | ||
| ); | ||
| assert.deepEqual(await res.json(), { id: "w1", commentId: 7 }); | ||
| } | ||
|
|
||
| export const steps: Step[] = [(ctx) => deleteComment(ctx)]; |
11 changes: 11 additions & 0 deletions
11
packages/run/src/__tests__/fixtures/params-validator-types/tsconfig.check.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "extends": "./tsconfig.json", | ||
| "compilerOptions": { | ||
| "noEmit": true, | ||
| "baseUrl": ".", | ||
| "paths": { | ||
| "@marko/run": ["../../../runtime/index.ts"], | ||
| "@marko/run/namespace": ["../../../runtime/namespace.ts"] | ||
| } | ||
| } | ||
| } |
4 changes: 4 additions & 0 deletions
4
packages/run/src/__tests__/fixtures/params-validator-types/tsconfig.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "extends": "../../tsconfig-base.json", | ||
| "include": ["src/**/*", ".marko-run/*"], | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fail when the TypeScript process does not complete.
spawnSynccan returnerrororsignalwith no compiler output. In that case,localErrorsis empty and this regression test passes after a timeout or process-launch failure. Assert that the process has no error and no termination signal before filtering diagnostics.Proposed fix
const result = spawnSync( process.execPath, [ require.resolve("typescript/lib/tsc.js"), @@ { encoding: "utf-8", timeout: 90000 }, ); + assert.equal(result.error, undefined, result.error?.message); + assert.equal(result.signal, null, "TypeScript type check did not complete"); const localErrors = (result.stdout || "")📝 Committable suggestion
🤖 Prompt for AI Agents