-
Notifications
You must be signed in to change notification settings - Fork 66
Add @markAsPageable decorator to force pageable operation treatment #3660
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
base: main
Are you sure you want to change the base?
Changes from 7 commits
868c709
28ab966
e89f892
75d0427
bf40654
eec5eee
7493af0
0e21505
ef5d766
d4e1fe4
19bf0da
d63b8f0
fe3117e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| import { getLroMetadata } from "@azure-tools/typespec-azure-core"; | ||
| import { | ||
| $decorators as typespecDecorators, | ||
| compilerAssert, | ||
| DecoratorContext, | ||
| DecoratorFunction, | ||
|
|
@@ -10,6 +11,7 @@ import { | |
| ignoreDiagnostics, | ||
| Interface, | ||
| isErrorModel, | ||
| isList, | ||
| isNumeric, | ||
| isService, | ||
| isTemplateDeclaration, | ||
|
|
@@ -51,6 +53,7 @@ import { | |
| FlattenPropertyDecorator, | ||
| HierarchyBuildingDecorator, | ||
| MarkAsLroDecorator, | ||
| MarkAsPageableDecorator, | ||
| NextLinkVerbDecorator, | ||
| } from "../generated-defs/Azure.ClientGenerator.Core.Legacy.js"; | ||
| import { | ||
|
|
@@ -1535,6 +1538,86 @@ export function getMarkAsLro(context: TCGCContext, entity: Operation): boolean { | |
| return getScopedDecoratorData(context, markAsLroKey, entity) ?? false; | ||
| } | ||
|
|
||
| const markAsPageableKey = createStateSymbol("markAsPageable"); | ||
|
|
||
| export const $markAsPageable: MarkAsPageableDecorator = ( | ||
| context: DecoratorContext, | ||
| target: Operation, | ||
| scope?: LanguageScopes, | ||
| ) => { | ||
| const httpOperation = ignoreDiagnostics(getHttpOperation(context.program, target)); | ||
| const hasModelResponse = httpOperation.responses.filter( | ||
| (r) => | ||
| r.type?.kind === "Model" && !(r.statusCodes === "*" || isErrorModel(context.program, r.type)), | ||
| )[0]; | ||
| if (!hasModelResponse || hasModelResponse.type?.kind !== "Model") { | ||
| reportDiagnostic(context.program, { | ||
| code: "invalid-mark-as-pageable-target", | ||
| format: { | ||
| operation: target.name, | ||
| }, | ||
| target: context.decoratorTarget, | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| // Check if already marked with @list decorator | ||
| if (isList(context.program, target)) { | ||
| reportDiagnostic(context.program, { | ||
| code: "mark-as-pageable-ineffective", | ||
| format: { | ||
| operation: target.name, | ||
| }, | ||
| target: context.decoratorTarget, | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| // Check the response model for @pageItems decorator | ||
| const responseModel = hasModelResponse.type as Model; | ||
| let hasPageItemsProperty = false; | ||
|
|
||
| // Check if any property has @pageItems decorator | ||
| for (const [, prop] of responseModel.properties) { | ||
| // Check if the property is marked with @pageItems by checking the program state | ||
| // The @pageItems decorator uses a state symbol "pageItems" | ||
| const pageItemsStateKey = Symbol.for("TypeSpec.pageItems"); | ||
| if (context.program.stateSet(pageItemsStateKey).has(prop)) { | ||
| hasPageItemsProperty = true; | ||
| break; | ||
|
||
| } | ||
| } | ||
|
|
||
| if (!hasPageItemsProperty) { | ||
| // Try to find a property named "value" and apply @pageItems to it | ||
| const valueProperty = responseModel.properties.get("value"); | ||
| if (valueProperty) { | ||
| // Apply @pageItems decorator to the value property | ||
| context.call(typespecDecorators.TypeSpec.pageItems, valueProperty); | ||
| } else { | ||
| // No @pageItems property and no "value" property found | ||
| reportDiagnostic(context.program, { | ||
| code: "invalid-mark-as-pageable-target", | ||
| format: { | ||
| operation: target.name, | ||
| }, | ||
| target: context.decoratorTarget, | ||
| }); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
| // Apply the @list decorator to the operation | ||
| context.call(typespecDecorators.TypeSpec.list, target); | ||
|
|
||
| // Store metadata that will be checked by TCGC to treat this operation as pageable | ||
| setScopedDecoratorData(context, $markAsPageable, markAsPageableKey, target, true, scope); | ||
| }; | ||
|
|
||
| export function getMarkAsPageable(context: TCGCContext, entity: Operation): boolean { | ||
| return getScopedDecoratorData(context, markAsPageableKey, entity) ?? false; | ||
| } | ||
|
|
||
| const nextLinkVerbKey = createStateSymbol("nextLinkVerb"); | ||
|
|
||
| export const $nextLinkVerb: NextLinkVerbDecorator = ( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.