Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
318 changes: 159 additions & 159 deletions common/config/rush/pnpm-lock.yaml

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions packages/typespec-powershell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@
"vitest": "1.6.1"
},
"peerDependencies": {
"@azure-tools/typespec-azure-core": ">=0.58.0 <1.0.0",
"@azure-tools/typespec-client-generator-core": ">=0.58.0 <1.0.0",
"@typespec/compiler": ">=1.2.1 <2.0.0",
"@typespec/http": ">=1.2.1 <2.0.0",
"@azure-tools/typespec-azure-core": ">=0.59.0 <1.0.0",
"@azure-tools/typespec-client-generator-core": ">=0.59.0 <1.0.0",
"@typespec/compiler": ">=1.3.0 <2.0.0",
"@typespec/http": ">=1.3.0 <2.0.0",
"@typespec/streams": ">=0.72.1 <1.0.0",
"@typespec/xml": ">=0.72.1 <1.0.0",
"@typespec/rest": ">=0.72.1 <1.0.0",
"@typespec/versioning": ">=0.72.1 <1.0.0",
"@typespec/openapi": ">=1.2.1 <2.0.0",
"@azure-tools/typespec-azure-resource-manager": ">=0.58.0 <1.0.0",
"@azure-tools/typespec-azure-rulesets": ">=0.58.0 <1.0.0"
"@typespec/openapi": ">=1.3.0 <2.0.0",
"@azure-tools/typespec-azure-resource-manager": ">=0.59.0 <1.0.0",
"@azure-tools/typespec-azure-rulesets": ">=0.59.0 <1.0.0"
},
"scripts": {
"build": "tsc",
Expand Down
12 changes: 5 additions & 7 deletions packages/typespec-powershell/src/convertor/convertor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ import { camelCase, deconstruct, pascalCase, serialize } from "@azure-tools/code
import { PSOptions } from "../types/interfaces.js";
import { Request, ImplementationLocation, OperationGroup, Operation, Parameter, Schema, Protocol, Response, HttpHeader } from "@autorest/codemodel";
import { stat } from "fs";
import { extractPagedMetadataNested } from "../utils/operationUtil.js";
import { parseNextLinkName } from "../utils/operationUtil.js";
import { extractPageDetails } from "../utils/operationUtil.js";
import { getLroMetadata } from "@azure-tools/typespec-azure-core";
import { getOperationId } from "@typespec/openapi";
import { listOperations } from "../utils/clientUtils.js";
Expand Down Expand Up @@ -264,14 +263,13 @@ function addOperation(psContext: SdkContext, op: HttpOperation, operationGroup:

function addExtensions(psContext: SdkContext, op: HttpOperation, newOperation: Operation, model: PwshModel) {
// Add extensions for pageable
const paged = extractPagedMetadataNested(psContext.program, op.responses[0].type as Model);
if (paged) {
const pagedDetail = extractPageDetails(psContext.program, op);
if (pagedDetail) {
newOperation.extensions = newOperation.extensions || {};
//ToDo: add value if it is specified by xiaogang
newOperation.extensions['x-ms-pageable'] = newOperation.extensions['x-ms-pageable'] || {};
newOperation.extensions['x-ms-pageable']['nextLinkName'] = parseNextLinkName(paged) ?? "nextLink";
newOperation.extensions['x-ms-pageable']['nextLinkName'] = pagedDetail.nextLinkNames[0] ?? "nextLink";
newOperation.language.default.paging = newOperation.language.default.paging || {};
newOperation.language.default.paging.nextLinkName = parseNextLinkName(paged) ?? "nextLink";
newOperation.language.default.paging.nextLinkName = pagedDetail.nextLinkNames[0] ?? "nextLink";
}
// Add extensions for long running operation
const lro = getLroMetadata(psContext.program, op.operation);
Expand Down
2 changes: 1 addition & 1 deletion packages/typespec-powershell/src/utils/modelUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import {
createMetadataInfo,
Visibility
} from "@typespec/http";
import { getPagedResult, isFixed, getUnionAsEnum } from "@azure-tools/typespec-azure-core";
import { getPagedResult, getUnionAsEnum } from "@azure-tools/typespec-azure-core";
import { extractPagedMetadataNested } from "./operationUtil.js";
import { pascalCase, deconstruct } from "@azure-tools/codegen";
import {
Expand Down
106 changes: 101 additions & 5 deletions packages/typespec-powershell/src/utils/operationUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
// } from "@azure-tools/rlc-common";
import {
ignoreDiagnostics,
isList,
Model,
ModelProperty,
Operation,
Program,
Type
Expand All @@ -37,6 +39,7 @@ import {
SdkContext
} from "@azure-tools/typespec-client-generator-core";
import { listOperations } from "./clientUtils.js";
import { $ } from "@typespec/compiler/typekit";
// import {
// OperationLroDetail,
// OPERATION_LRO_LOW_PRIORITY,
Expand Down Expand Up @@ -324,13 +327,49 @@ export function hasPollingOperations(
}

export function isPagingOperation(program: Program, operation: HttpOperation) {
for (const response of operation.responses) {
const paged = extractPagedMetadataNested(program, response.type as Model);
if (paged) {
return true;
return extractPageDetails(program, operation) !== undefined;
}

function mapFirstSegmentForResultSegments(
resultSegments: ModelProperty[] | undefined,
responses: HttpOperationResponse[]
): ModelProperty[] | undefined {
const pagingBodyType = responses.find((r) => r.statusCodes === 200)
?.responses[0]?.body;
if (!pagingBodyType || pagingBodyType.bodyKind !== "single") return undefined;
const bodyType = pagingBodyType.type;

if (resultSegments === undefined || bodyType === undefined) return undefined;
// TCGC use Http response type as the return type
// For implicit body response, we need to locate the first segment in the response type
// Several cases:
// 1. `op test(): {items, nextLink}`
// 2. `op test(): {items, nextLink} & {a, b, c}`
// 3. `op test(): {@bodyRoot body: {items, nextLink}}`

if (resultSegments.length > 0 && bodyType && bodyType.kind === "Model") {
for (let i = 0; i < resultSegments.length; i++) {
const segment = resultSegments[i];
for (const property of bodyType.properties ?? []) {
if (
property &&
segment &&
findRootSourceProperty(property[1]) ===
findRootSourceProperty(segment)
) {
return [property[1], ...resultSegments.slice(i + 1)];
}
}
}
}
return false;
return resultSegments;
}

function findRootSourceProperty(property: ModelProperty): ModelProperty {
while (property.sourceProperty) {
property = property.sourceProperty;
}
return property;
}

export function hasPagingOperations(
Expand Down Expand Up @@ -525,3 +564,60 @@ export function parseItemName(paged: PagedResultMetadata): string | undefined {
// TODO: support the nested item names
return (paged.itemsSegments ?? [])[0];
}

export interface PageDetails {
nextLinkNames: string[];
itemNames: string[];
}

export function extractPageDetails(
program: Program,
operation: HttpOperation
): PageDetails | undefined {
if (isList(program, operation.operation)) {
// If the operation is a list, we don't need to extract paging details.
const metadata = $(program).operation.getPagingMetadata(
operation.operation
);
if (metadata === undefined) {
// would fallback to default paging metadata
return undefined;
}
const nextLinkPath = mapFirstSegmentForResultSegments(
metadata?.output.nextLink?.path,
operation.responses
);
const itemNamePath = mapFirstSegmentForResultSegments(
metadata?.output.pageItems?.path,
operation.responses
);
if (
(nextLinkPath && nextLinkPath?.length > 1) ||
(itemNamePath && itemNamePath?.length > 1)
) {
return undefined;
}
const nextLinkNames =
nextLinkPath?.map((prop) => prop.name).join(".") ?? "nextLink";
const itemNames =
itemNamePath?.map((prop) => prop.name).join(".") ?? "value";
return {
nextLinkNames: [nextLinkNames],
itemNames: [itemNames]
};
} else {
// TODO: remember to remove this once Azure Paging is removed.
for (const response of operation.responses) {
const paged = extractPagedMetadataNested(program, response.type as Model);
if (paged) {
const nextLinkName = parseNextLinkName(paged) ?? "nextLink";
const itemName = parseItemName(paged) ?? "value";
return {
nextLinkNames: [nextLinkName],
itemNames: [itemName]
};
}
}
}
return undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ interface SubscriptionUsages {
@get
@armResourceList(Location)
@doc("List Quota resources by subscription ID")
@list
usages(
...SubscriptionIdParameter,
...Azure.ResourceManager.Foundations.DefaultProviderNamespace,
Expand Down
4 changes: 4 additions & 0 deletions tests-upgrade/tests-emitter/Sphere.Management/catalog.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ interface Catalogs {
/**
* Lists deployments for catalog.
*/
@list
listDeployments is ArmResourceActionSync<
Catalog,
void,
Expand All @@ -86,6 +87,7 @@ interface Catalogs {
/**
* List the device groups for the catalog.
*/
@list
listDeviceGroups is ArmResourceActionSync<
Catalog,
ListDeviceGroupsRequest,
Expand All @@ -102,6 +104,7 @@ interface Catalogs {
/**
* Lists device insights for catalog.
*/
@list
listDeviceInsights is ArmResourceActionSync<
Catalog,
void,
Expand All @@ -118,6 +121,7 @@ interface Catalogs {
/**
* Lists devices for catalog.
*/
@list
listDevices is ArmResourceActionSync<
Catalog,
void,
Expand Down
1 change: 1 addition & 0 deletions tests-upgrade/tests-emitter/Sphere.Management/product.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ interface Products {
/**
* Generates default device groups for the product. '.default' and '.unassigned' are system defined values and cannot be used for product name.
*/
@list
generateDefaultDeviceGroups is ArmResourceActionSync<
Product,
void,
Expand Down
24 changes: 12 additions & 12 deletions tests-upgrade/tests-emitter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
"version": "0.1.0",
"type": "module",
"dependencies": {
"@typespec/compiler": "1.2.1",
"@azure-tools/typespec-autorest": "0.58.0",
"@azure-tools/typespec-azure-core": "0.58.0",
"@azure-tools/typespec-azure-resource-manager": "0.58.0",
"@azure-tools/typespec-client-generator-core": "0.58.0",
"@azure-tools/typespec-azure-rulesets": "0.58.0",
"@typespec/http": "1.2.1",
"@typespec/openapi": "1.2.1",
"@typespec/rest": "0.72.1",
"@typespec/streams": "0.72.1",
"@typespec/versioning": "0.72.1",
"@typespec/xml": "0.72.1",
"@typespec/compiler": "1.3.0",
"@azure-tools/typespec-autorest": "0.59.0",
"@azure-tools/typespec-azure-core": "0.59.0",
"@azure-tools/typespec-azure-resource-manager": "0.59.0",
"@azure-tools/typespec-client-generator-core": "0.59.0",
"@azure-tools/typespec-azure-rulesets": "0.59.0",
"@typespec/http": "1.3.0",
"@typespec/openapi": "1.3.0",
"@typespec/rest": "0.73.0",
"@typespec/streams": "0.73.0",
"@typespec/versioning": "0.73.0",
"@typespec/xml": "0.73.0",
"@azure-tools/typespec-liftr-base": "0.8.0"
},
"scripts": {
Expand Down
Loading