From ace543880c6137304431f791010ae6079ce036bf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:15:32 +0000 Subject: [PATCH 1/3] Initial plan From 26791834b25bb74d5e5cc17f2ecbd81c3c895cd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:22:58 +0000 Subject: [PATCH 2/3] Remove type and optionality constraints from @continuationToken decorator Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> --- packages/compiler/src/lib/paging.ts | 13 +--- .../compiler/test/decorators/paging.test.ts | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/packages/compiler/src/lib/paging.ts b/packages/compiler/src/lib/paging.ts index f0ed07f32c5..3c84700d188 100644 --- a/packages/compiler/src/lib/paging.ts +++ b/packages/compiler/src/lib/paging.ts @@ -109,18 +109,7 @@ export const [ markContinuationTokenProperty, /** {@inheritdoc ContinuationTokenDecorator} */ continuationTokenDecorator, -] = createMarkerDecorator("continuationToken", (context, target) => { - if (!isStringType(context.program, target.type)) { - reportDiagnostic(context.program, { - code: "decorator-wrong-target", - messageId: "withExpected", - format: { decorator: "continuationToken", expected: "string", to: getTypeName(target.type) }, - target: context.decoratorTarget, - }); - return false; - } - return true; -}); +] = createMarkerDecorator("continuationToken"); export const [ /** diff --git a/packages/compiler/test/decorators/paging.test.ts b/packages/compiler/test/decorators/paging.test.ts index 6174445cd30..e4ab7d9b9c5 100644 --- a/packages/compiler/test/decorators/paging.test.ts +++ b/packages/compiler/test/decorators/paging.test.ts @@ -213,3 +213,80 @@ describe("collect nested paging properties", () => { expect(pathString).toBe("results.items"); }); }); + +describe("@continuationToken supports nullable and optional properties", () => { + it("accepts nullable string type (string | null)", async () => { + const diagnostics = await runner.diagnose(` + @list op list(): { + @pageItems items: string[]; + @continuationToken token: string | null; + }; + `); + expectDiagnosticEmpty(diagnostics); + }); + + it("accepts optional string type", async () => { + const diagnostics = await runner.diagnose(` + @list op list(): { + @pageItems items: string[]; + @continuationToken token?: string; + }; + `); + expectDiagnosticEmpty(diagnostics); + }); + + it("accepts nullable optional string type", async () => { + const diagnostics = await runner.diagnose(` + @list op list(): { + @pageItems items: string[]; + @continuationToken token?: string | null; + }; + `); + expectDiagnosticEmpty(diagnostics); + }); + + it("accepts non-string types", async () => { + const diagnostics = await runner.diagnose(` + @list op list(): { + @pageItems items: string[]; + @continuationToken token: int32; + }; + `); + expectDiagnosticEmpty(diagnostics); + }); + + it("collects nullable continuation token in input", async () => { + const { list, token } = (await runner.compile(` + @list @test op list( + @continuationToken @test token: string | null + ): { @pageItems items: string[] }; + `)) as { list: Operation; token: ModelProperty }; + + const paging = ignoreDiagnostics(getPagingOperation(runner.program, list)); + expect(paging?.input.continuationToken?.property).toBe(token); + }); + + it("collects nullable continuation token in output", async () => { + const { list, token } = (await runner.compile(` + @list @test op list(): { + @pageItems items: string[]; + @continuationToken @test token: string | null; + }; + `)) as { list: Operation; token: ModelProperty }; + + const paging = ignoreDiagnostics(getPagingOperation(runner.program, list)); + expect(paging?.output.continuationToken?.property).toBe(token); + }); + + it("collects optional continuation token", async () => { + const { list, token } = (await runner.compile(` + @list @test op list(): { + @pageItems items: string[]; + @continuationToken @test token?: string; + }; + `)) as { list: Operation; token: ModelProperty }; + + const paging = ignoreDiagnostics(getPagingOperation(runner.program, list)); + expect(paging?.output.continuationToken?.property).toBe(token); + }); +}); From dd33b6fddc397f4d8ad052b49e13b406cf909d15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 24 Nov 2025 19:25:17 +0000 Subject: [PATCH 3/3] Remove unused import after removing type validation Co-authored-by: markcowl <1054056+markcowl@users.noreply.github.com> --- packages/compiler/src/lib/paging.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compiler/src/lib/paging.ts b/packages/compiler/src/lib/paging.ts index 3c84700d188..61b97ae646f 100644 --- a/packages/compiler/src/lib/paging.ts +++ b/packages/compiler/src/lib/paging.ts @@ -26,7 +26,7 @@ import type { } from "../core/types.js"; import { createStateSymbol } from "../lib/utils.js"; import { DuplicateTracker, useStateSet } from "../utils/index.js"; -import { isNumericType, isStringType } from "./decorators.js"; +import { isNumericType } from "./decorators.js"; export const [ /**