diff --git a/packages/http-client-java/emitter/src/code-model-builder.ts b/packages/http-client-java/emitter/src/code-model-builder.ts index 2bfd89326d..8796194eaa 100644 --- a/packages/http-client-java/emitter/src/code-model-builder.ts +++ b/packages/http-client-java/emitter/src/code-model-builder.ts @@ -100,7 +100,6 @@ import { HttpStatusCodesEntry, Visibility, getAuthentication, - isCookieParam, } from "@typespec/http"; import { getSegment } from "@typespec/rest"; import { getAddedOnVersions } from "@typespec/versioning"; @@ -138,13 +137,13 @@ import { getNonNullSdkType, getUnionDescription, getUsage, - isStable, modelIs, pushDistinct, } from "./type-utils.js"; import { DiagnosticError, getNamespace, + isStableApiVersion, pascalCase, removeClientSuffix, stringArrayContainsIgnoreCase, @@ -764,7 +763,10 @@ export class CodeModelBuilder { } return versions .slice(0, versions.indexOf(pinnedApiVersion) + 1) - .filter((version) => !excludePreview || !isStable(pinnedApiVersion) || isStable(version)); + .filter( + (version) => + !excludePreview || !isStableApiVersion(pinnedApiVersion) || isStableApiVersion(version), + ); } private needToSkipProcessingOperation( @@ -909,8 +911,7 @@ export class CodeModelBuilder { clientContext.hostParameters.forEach((it) => codeModelOperation.addParameter(it)); // path/query/header parameters for (const param of httpOperation.parameters) { - // TODO, switch to TCGC param.kind=="cookie" - if (param.__raw && isCookieParam(this.program, param.__raw)) { + if (param.kind === "cookie") { // ignore cookie parameter continue; } @@ -1287,12 +1288,7 @@ export class CodeModelBuilder { } } - // TODO: use param.onClient after TCGC fix - const parameterOnClient = - !isApiVersion(this.sdkContext, param) && - param.correspondingMethodParams && - param.correspondingMethodParams.length > 0 && - param.correspondingMethodParams[0].onClient; + const parameterOnClient = param.onClient; const nullable = param.type.kind === "nullable"; const parameter = new Parameter(param.name, param.doc ?? "", schema, { @@ -2311,9 +2307,9 @@ export class CodeModelBuilder { extensions["x-ms-mutability"] = mutability; } - if (prop.kind === "property" && prop.multipartOptions) { + if (prop.kind === "property" && prop.serializationOptions.multipart) { // TODO: handle MultipartOptions.isMulti - if (prop.multipartOptions.isFilePart) { + if (prop.serializationOptions.multipart?.isFilePart) { schema = this.processMultipartFormDataFilePropertySchema(prop); } else if ( prop.type.kind === "model" && diff --git a/packages/http-client-java/emitter/src/type-utils.ts b/packages/http-client-java/emitter/src/type-utils.ts index ab5e6e6bee..045b4d8474 100644 --- a/packages/http-client-java/emitter/src/type-utils.ts +++ b/packages/http-client-java/emitter/src/type-utils.ts @@ -56,10 +56,6 @@ export class ProcessingCache { } } -export function isStable(version: string): boolean { - return !version.toLowerCase().includes("preview"); -} - /** adds only if the item is not in the collection already * * @note While this isn't very efficient, it doesn't disturb the original diff --git a/packages/http-client-java/emitter/src/utils.ts b/packages/http-client-java/emitter/src/utils.ts index 62ced52e78..accfce0478 100644 --- a/packages/http-client-java/emitter/src/utils.ts +++ b/packages/http-client-java/emitter/src/utils.ts @@ -5,6 +5,10 @@ export function trace(program: Program, msg: string) { program.trace("http-client-java", msg); } +export function isStableApiVersion(version: string): boolean { + return !version.toLowerCase().includes("preview"); +} + export function pascalCase(name: string): string { if (name.length > 0) { return name[0].toUpperCase() + name.slice(1); diff --git a/packages/http-client-java/emitter/test/utils.test.ts b/packages/http-client-java/emitter/test/utils.test.ts new file mode 100644 index 0000000000..8850b98c63 --- /dev/null +++ b/packages/http-client-java/emitter/test/utils.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from "vitest"; +import { + isStableApiVersion, + pascalCase, + removeClientSuffix, + stringArrayContainsIgnoreCase, +} from "../src/utils"; + +describe("utils", () => { + it("isStableApiVersion", () => { + expect(isStableApiVersion("2022-09-01")).toBe(true); + expect(isStableApiVersion("2023-12-01-preview")).toBe(false); + }); + + it("pascalCase", () => { + expect(pascalCase("foo")).toBe("Foo"); + expect(pascalCase("fooBar")).toBe("FooBar"); + expect(pascalCase("FooBar")).toBe("FooBar"); + expect(pascalCase("foo bar")).toBe("Foo bar"); + }); + + it("stringArrayContainsIgnoreCase", () => { + expect(stringArrayContainsIgnoreCase(["foo", "bar"], "foo")).toBe(true); + expect(stringArrayContainsIgnoreCase(["foo", "bar"], "Bar")).toBe(true); + expect(stringArrayContainsIgnoreCase(["foo", "bar"], "del")).toBe(false); + }); + + it("removeClientSuffix", () => { + expect(removeClientSuffix("FooClient")).toBe("Foo"); + expect(removeClientSuffix("client")).toBe("client"); + }); +}); diff --git a/packages/http-client-java/emitter/vitest.config.ts b/packages/http-client-java/emitter/vitest.config.ts new file mode 100644 index 0000000000..95e2a5ecfa --- /dev/null +++ b/packages/http-client-java/emitter/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig, mergeConfig } from "vitest/config"; +import { defaultTypeSpecVitestConfig } from "../../../vitest.workspace.js"; + +export default mergeConfig( + defaultTypeSpecVitestConfig, + defineConfig({ + test: { + include: ["emitter/test/**/*.test.ts"], + }, + }), +); diff --git a/packages/http-client-java/eng/scripts/Test-Packages.ps1 b/packages/http-client-java/eng/scripts/Test-Packages.ps1 index 4996d7da60..8052ab2207 100644 --- a/packages/http-client-java/eng/scripts/Test-Packages.ps1 +++ b/packages/http-client-java/eng/scripts/Test-Packages.ps1 @@ -20,6 +20,9 @@ Invoke-LoggedCommand "mvn -version" Push-Location $packageRoot try { if ($UnitTests) { + Invoke-LoggedCommand "npm run test" + Write-Host "Emitter unit tests passed" + Write-Host "Current PATH: $env:PATH" Write-Host "Current JAVA_HOME: $Env:JAVA_HOME" $env:JAVA_HOME = $env:JAVA_HOME_21_X64 diff --git a/packages/http-client-java/generator/http-client-generator-core/pom.xml b/packages/http-client-java/generator/http-client-generator-core/pom.xml index a883b2f816..b65210b561 100644 --- a/packages/http-client-java/generator/http-client-generator-core/pom.xml +++ b/packages/http-client-java/generator/http-client-generator-core/pom.xml @@ -95,12 +95,6 @@ 5.11.2 test - - io.clientcore - core - 1.0.0-beta.2 - test - org.junit.jupiter junit-jupiter-engine diff --git a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java b/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java deleted file mode 100644 index d040660ce5..0000000000 --- a/packages/http-client-java/generator/http-client-generator-core/src/test/java/com/microsoft/typespec/http/client/generator/core/template/ClientMethodSerializeItemValueCodeTests.java +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -package com.microsoft.typespec.http.client.generator.core.template; - -import com.azure.core.annotation.Generated; -import com.azure.core.util.ExpandableEnum; -import io.clientcore.core.util.binarydata.BinaryData; -import java.time.OffsetDateTime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class ClientMethodSerializeItemValueCodeTests { - - @Test - public void testClientMethodSerializeItemValueCode() { - // code from resources/ClientMethodSerializeItemValue.java - Function testCode = paramItemValue -> { - if (paramItemValue == null) { - return ""; - } else { - String itemValueString = BinaryData.fromObject(paramItemValue).toString(); - int strLength = itemValueString.length(); - int startOffset = 0; - while (startOffset < strLength) { - if (itemValueString.charAt(startOffset) != '"') { - break; - } - startOffset++; - } - if (startOffset == strLength) { - return ""; - } - int endOffset = strLength - 1; - while (endOffset >= 0) { - if (itemValueString.charAt(endOffset) != '"') { - break; - } - - endOffset--; - } - return itemValueString.substring(startOffset, endOffset + 1); - } - }; - - Function, String> serializeCsvCode - = paramItems -> paramItems.stream().map(testCode).collect(Collectors.joining(",")); - - // Long - Assertions.assertEquals("1,2,3", serializeCsvCode.apply(List.of(1L, 2L, 3L))); - - // String - Assertions.assertEquals("a,b,c", serializeCsvCode.apply(List.of("a", "b", "c"))); - - // Enum - Assertions.assertEquals("0,100", serializeCsvCode.apply(List.of(PriorityModel.LOW, PriorityModel.HIGH))); - - // date-time - Assertions.assertEquals("2025-01-24T07:34:05Z,2024-05-20T00:00:01Z", serializeCsvCode.apply( - List.of(OffsetDateTime.parse("2025-01-24T07:34:05Z"), OffsetDateTime.parse("2024-05-20T00:00:01Z")))); - } - - /** - * Defines values for PriorityModel. - */ - public static final class PriorityModel implements ExpandableEnum { - private static final Map VALUES = new ConcurrentHashMap<>(); - - private static final Function NEW_INSTANCE = PriorityModel::new; - - /** - * Static value 100 for PriorityModel. - */ - @Generated - public static final PriorityModel HIGH = fromValue(100); - - /** - * Static value 0 for PriorityModel. - */ - @Generated - public static final PriorityModel LOW = fromValue(0); - - private final Integer value; - - private PriorityModel(Integer value) { - this.value = value; - } - - /** - * Creates or finds a PriorityModel. - * - * @param value a value to look for. - * @return the corresponding PriorityModel. - * @throws IllegalArgumentException if value is null. - */ - @Generated - public static PriorityModel fromValue(Integer value) { - if (value == null) { - throw new IllegalArgumentException("'value' cannot be null."); - } - return VALUES.computeIfAbsent(value, NEW_INSTANCE); - } - - /** - * Gets known PriorityModel values. - * - * @return Known PriorityModel values. - */ - @Generated - public static Collection values() { - return new ArrayList<>(VALUES.values()); - } - - /** - * Gets the value of the PriorityModel instance. - * - * @return the value of the PriorityModel instance. - */ - @Generated - @Override - public Integer getValue() { - return this.value; - } - - @Generated - @Override - public String toString() { - return Objects.toString(this.value); - } - - @Generated - @Override - public boolean equals(Object obj) { - return this == obj; - } - - @Generated - @Override - public int hashCode() { - return Objects.hashCode(this.value); - } - } -} diff --git a/packages/http-client-java/package.json b/packages/http-client-java/package.json index 234ddd5c75..d4c64bd355 100644 --- a/packages/http-client-java/package.json +++ b/packages/http-client-java/package.json @@ -19,7 +19,10 @@ "type": "module", "main": "dist/emitter/index.js", "exports": { - ".": "./dist/emitter/index.js" + ".": { + "types": "./dist/emitter/index.d.ts", + "default": "./dist/emitter/index.js" + } }, "engines": { "node": ">=18.0.0" @@ -29,6 +32,8 @@ "build": "npm run build:generator && npm run build:emitter", "build:emitter": "tsc -p ./emitter/tsconfig.build.json", "build:generator": "mvn clean install --no-transfer-progress -T 1C -f ./generator/pom.xml", + "test": "npm run test:emitter", + "test:emitter": "vitest run -c ./emitter/vitest.config.ts", "format": "pnpm -w format:dir packages/http-client-java && mvn spotless:apply --no-transfer-progress -T 1C --activate-profiles test -f ./generator/pom.xml", "lint": "eslint . --max-warnings=0", "lint:fix": "eslint . --fix",