Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
af6f2b1
link out to mock api and scenario docs
Apr 30, 2025
073e0ba
implement functions and update docs
Mar 2, 2026
7ad7cef
revert pnpm lock commit
Mar 2, 2026
21e7792
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
Mar 2, 2026
baf6f08
add changeset
Mar 2, 2026
b6e5da3
Add replaceResponse and addParameter functions, move functions to sep…
Mar 2, 2026
dfdde40
format and lint
Mar 2, 2026
31918a2
Improve function tests to verify TCGC object model
Mar 2, 2026
c0fa279
Apply formatting
Mar 2, 2026
7001a8a
Move @override documentation to Basic methods page
Mar 2, 2026
f7f263c
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
Mar 17, 2026
1c9e664
Merge branch 'main' into tcgc/addReplaceDecorator
tadelesh Mar 19, 2026
59096fa
remove replaceResponse and add reorderParameters
Mar 19, 2026
b6d087d
Merge https://github.com/iscai-msft/typespec-azure into tcgc/addRepla…
Mar 19, 2026
aaa9f37
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
Mar 19, 2026
192e15e
Merge branch 'tcgc/addReplaceDecorator' of https://github.com/iscai-m…
Mar 19, 2026
a78f6d6
remove as any setting
Mar 19, 2026
210f9ad
lint
Mar 19, 2026
be6f632
Update website/src/content/docs/docs/howtos/Generate client libraries…
tadelesh Mar 20, 2026
03dd24f
address copilot comments
Mar 20, 2026
529431e
Merge branch 'tcgc/addReplaceDecorator' of https://github.com/iscai-m…
Mar 20, 2026
c1c05b9
update doc to remove removal
Mar 20, 2026
adb7485
format
Mar 20, 2026
f23a7e8
Merge branch 'main' of https://github.com/Azure/typespec-azure into t…
Mar 23, 2026
008298e
add back remove parameter
Mar 23, 2026
b5969ad
Update packages/typespec-client-generator-core/src/functions.ts
tadelesh Mar 24, 2026
57d1e37
Update packages/typespec-client-generator-core/src/functions.ts
tadelesh Mar 24, 2026
225ee20
Update .chronus/changes/tcgc-addReplaceDecorator-2026-2-2-16-3-32.md
tadelesh Mar 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .chronus/changes/tcgc-addReplaceDecorator-2026-2-2-16-3-32.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
changeKind: feature
packages:
- "@azure-tools/typespec-client-generator-core"
---

Add experimental extern functions for operation transformations:
- `replaceParameter`: Replace a parameter in an operation
- `removeParameter`: Remove a parameter from an operation
- `addParameter`: Add a new parameter to an operation
- `reorderParameters`: Reorder parameters of an operation according to a specified order

These functions enable composable transformations that work with `@@override` to customize method signatures in client SDKs.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
DecoratorValidatorCallbacks,
Enum,
EnumMember,
FunctionContext,
Interface,
Model,
ModelProperty,
Expand Down Expand Up @@ -1128,3 +1129,130 @@ export type AzureClientGeneratorCoreDecorators = {
clientDoc: ClientDocDecorator;
clientOption: ClientOptionDecorator;
};

/**
* Replace a parameter in an operation with a new parameter definition.
* This function creates a new operation with the specified parameter replaced,
* enabling composable transformations without mutating the original operation.
*
* @param operation The operation to transform.
* @param selector The parameter to replace, specified either by name (string) or by direct reference (ModelProperty).
* @param replacement The replacement parameter.
* @returns A new operation with the parameter replaced.
* @example Making an optional parameter required
* ```typespec
* model RequiredMaxResults {
* maxResults: int32;
* }
*
* @@override(KeyVault.getSecrets, replaceParameter(KeyVault.getSecrets, "maxResults", RequiredMaxResults.maxResults));
* ```
* @example Chaining transformations
* ```typespec
* alias Step1 = replaceParameter(MyService.myOp, "oldParam", NewParams.newParam);
* @@override(MyService.myOp, replaceParameter(Step1, "anotherParam", NewParams.anotherParam));
* ```
*/
export type ReplaceParameterFunctionImplementation = (
context: FunctionContext,
operation: Operation,
selector: string | unknown,
replacement: ModelProperty,
) => Operation;

/**
* Remove a parameter from an operation.
* This function creates a new operation with the specified parameter removed,
* enabling composable transformations without mutating the original operation.
*
* Note: When used with `@@override`, only optional parameters can be removed. Attempting to
* remove a required parameter will result in an `override-parameters-mismatch` error.
*
* @param operation The operation to transform.
* @param selector The parameter to remove, specified either by name (string) or by direct reference (ModelProperty).
* @returns A new operation with the parameter removed.
* @example Removing an optional parameter
* ```typespec
* @@override(KeyVault.getSecrets, removeParameter(KeyVault.getSecrets, "maxResults"));
* ```
* @example Chaining with other transformations
* ```typespec
* alias Step1 = removeParameter(MyService.myOp, "unwantedParam");
* @@override(MyService.myOp, addParameter(Step1, NewParams.newParam));
* ```
*/
export type RemoveParameterFunctionImplementation = (
context: FunctionContext,
operation: Operation,
selector: string | unknown,
) => Operation;

/**
* Add a new parameter to an operation.
* This function creates a new operation with the additional parameter appended,
* enabling composable transformations without mutating the original operation.
*
* @param operation The operation to transform.
* @param parameter The parameter to add to the operation.
* @returns A new operation with the parameter added.
* @example Adding a required parameter
* ```typespec
* model ExtraParams {
* @header tracingId: string;
* }
*
* @@override(MyService.myOp, addParameter(MyService.myOp, ExtraParams.tracingId));
* ```
* @example Chaining with replaceParameter
* ```typespec
* model NewParams {
* oldParam: string; // make required
* newParam: int32;
* }
*
* alias Step1 = replaceParameter(MyService.myOp, "oldParam", NewParams.oldParam);
* @@override(MyService.myOp, addParameter(Step1, NewParams.newParam));
* ```
*/
export type AddParameterFunctionImplementation = (
context: FunctionContext,
operation: Operation,
parameter: ModelProperty,
) => Operation;

/**
* Reorder parameters of an operation according to the specified order.
* This function creates a new operation with parameters reordered as specified,
* enabling control over the parameter order in generated client SDK methods.
*
* @param operation The operation to transform.
* @param order An array of parameter names specifying the desired order. All parameters must be included.
* @returns A new operation with parameters reordered.
* @example Reordering parameters
* ```typespec
* @service
* namespace MyService;
*
* op myOp(a: string, b: string, c: string): void;
*
* // Reorder to put 'c' first, then 'a', then 'b'
* @@override(MyService.myOp, reorderParameters(MyService.myOp, #["c", "a", "b"]));
* ```
* @example Chaining with other transformations
* ```typespec
* alias Step1 = addParameter(MyService.myOp, NewParams.newParam);
* @@override(MyService.myOp, reorderParameters(Step1, #["newParam", "existingParam"]));
* ```
*/
export type ReorderParametersFunctionImplementation = (
context: FunctionContext,
operation: Operation,
order: readonly string[],
) => Operation;

export type AzureClientGeneratorCoreFunctions = {
replaceParameter: ReplaceParameterFunctionImplementation;
removeParameter: RemoveParameterFunctionImplementation;
addParameter: AddParameterFunctionImplementation;
reorderParameters: ReorderParametersFunctionImplementation;
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
// An error in the imports would mean that the decorator is not exported or
// doesn't have the right name.

import { $decorators } from "@azure-tools/typespec-client-generator-core";
import type { AzureClientGeneratorCoreDecorators } from "./Azure.ClientGenerator.Core.js";
import { $decorators, $functions } from "@azure-tools/typespec-client-generator-core";
import type {
AzureClientGeneratorCoreDecorators,
AzureClientGeneratorCoreFunctions,
} from "./Azure.ClientGenerator.Core.js";

/**
* An error here would mean that the exported decorator is not using the same signature. Make sure to have export const $decName: DecNameDecorator = (...) => ...
*/
const _decs: AzureClientGeneratorCoreDecorators = $decorators["Azure.ClientGenerator.Core"];

/**
* An error here would mean that the exported function is not using the same signature. Make sure to have export const $funcName: FuncNameFunction = (...) => ...
*/
const _funcs: AzureClientGeneratorCoreFunctions = $functions["Azure.ClientGenerator.Core"];
131 changes: 131 additions & 0 deletions packages/typespec-client-generator-core/lib/functions.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using Reflection;

namespace Azure.ClientGenerator.Core;

/**
* Replace a parameter in an operation with a new parameter definition.
* This function creates a new operation with the specified parameter replaced,
* enabling composable transformations without mutating the original operation.
*
* @param operation The operation to transform.
* @param selector The parameter to replace, specified either by name (string) or by direct reference (ModelProperty).
* @param replacement The replacement parameter.
* @returns A new operation with the parameter replaced.
*
* @example Making an optional parameter required
* ```typespec
* model RequiredMaxResults {
* maxResults: int32;
* }
*
* @@override(KeyVault.getSecrets, replaceParameter(KeyVault.getSecrets, "maxResults", RequiredMaxResults.maxResults));
* ```
*
* @example Chaining transformations
* ```typespec
* alias Step1 = replaceParameter(MyService.myOp, "oldParam", NewParams.newParam);
* @@override(MyService.myOp, replaceParameter(Step1, "anotherParam", NewParams.anotherParam));
* ```
*/
#suppress "experimental-feature" "replaceParameter uses extern fn which is experimental but provides essential parameter transformation functionality"
extern fn replaceParameter(
operation: Reflection.Operation,
selector: valueof string | Reflection.ModelProperty,
replacement: Reflection.ModelProperty
): Reflection.Operation;

/**
* Remove a parameter from an operation.
* This function creates a new operation with the specified parameter removed,
* enabling composable transformations without mutating the original operation.
*
* Note: When used with `@@override`, only optional parameters can be removed. Attempting to
* remove a required parameter will result in an `override-parameters-mismatch` error.
*
* @param operation The operation to transform.
* @param selector The parameter to remove, specified either by name (string) or by direct reference (ModelProperty).
* @returns A new operation with the parameter removed.
*
* @example Removing an optional parameter
* ```typespec
* @@override(KeyVault.getSecrets, removeParameter(KeyVault.getSecrets, "maxResults"));
* ```
*
* @example Chaining with other transformations
* ```typespec
* alias Step1 = removeParameter(MyService.myOp, "unwantedParam");
* @@override(MyService.myOp, addParameter(Step1, NewParams.newParam));
* ```
*/
#suppress "experimental-feature" "removeParameter uses extern fn which is experimental but provides essential parameter transformation functionality"
extern fn removeParameter(
operation: Reflection.Operation,
selector: valueof string | Reflection.ModelProperty
): Reflection.Operation;

/**
* Add a new parameter to an operation.
* This function creates a new operation with the additional parameter appended,
* enabling composable transformations without mutating the original operation.
*
* @param operation The operation to transform.
* @param parameter The parameter to add to the operation.
* @returns A new operation with the parameter added.
*
* @example Adding a required parameter
* ```typespec
* model ExtraParams {
* @header tracingId: string;
* }
*
* @@override(MyService.myOp, addParameter(MyService.myOp, ExtraParams.tracingId));
* ```
*
* @example Chaining with replaceParameter
* ```typespec
* model NewParams {
* oldParam: string; // make required
* newParam: int32;
* }
*
* alias Step1 = replaceParameter(MyService.myOp, "oldParam", NewParams.oldParam);
* @@override(MyService.myOp, addParameter(Step1, NewParams.newParam));
* ```
*/
#suppress "experimental-feature" "addParameter uses extern fn which is experimental but provides essential parameter transformation functionality"
extern fn addParameter(
operation: Reflection.Operation,
parameter: Reflection.ModelProperty
): Reflection.Operation;

/**
* Reorder parameters of an operation according to the specified order.
* This function creates a new operation with parameters reordered as specified,
* enabling control over the parameter order in generated client SDK methods.
*
* @param operation The operation to transform.
* @param order An array of parameter names specifying the desired order. All parameters must be included.
* @returns A new operation with parameters reordered.
*
* @example Reordering parameters
* ```typespec
* @service
* namespace MyService;
*
* op myOp(a: string, b: string, c: string): void;
*
* // Reorder to put 'c' first, then 'a', then 'b'
* @@override(MyService.myOp, reorderParameters(MyService.myOp, #["c", "a", "b"]));
* ```
*
* @example Chaining with other transformations
* ```typespec
* alias Step1 = addParameter(MyService.myOp, NewParams.newParam);
* @@override(MyService.myOp, reorderParameters(Step1, #["newParam", "existingParam"]));
* ```
*/
#suppress "experimental-feature" "reorderParameters uses extern fn which is experimental but provides essential parameter transformation functionality"
extern fn reorderParameters(
operation: Reflection.Operation,
order: valueof string[]
): Reflection.Operation;
1 change: 1 addition & 0 deletions packages/typespec-client-generator-core/lib/main.tsp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "./decorators.tsp";
import "./functions.tsp";
import "./augmentCore.tsp";
import "./legacy.tsp";
import "../dist/src/tsp-index.js";
Loading
Loading